Annotation of embedaddon/nginx/src/http/modules/ngx_http_log_module.c, revision 1.1.1.1

1.1       misho       1: 
                      2: /*
                      3:  * Copyright (C) Igor Sysoev
                      4:  * Copyright (C) Nginx, Inc.
                      5:  */
                      6: 
                      7: 
                      8: #include <ngx_config.h>
                      9: #include <ngx_core.h>
                     10: #include <ngx_http.h>
                     11: 
                     12: #if (NGX_ZLIB)
                     13: #include <zlib.h>
                     14: #endif
                     15: 
                     16: 
                     17: typedef struct ngx_http_log_op_s  ngx_http_log_op_t;
                     18: 
                     19: typedef u_char *(*ngx_http_log_op_run_pt) (ngx_http_request_t *r, u_char *buf,
                     20:     ngx_http_log_op_t *op);
                     21: 
                     22: typedef size_t (*ngx_http_log_op_getlen_pt) (ngx_http_request_t *r,
                     23:     uintptr_t data);
                     24: 
                     25: 
                     26: struct ngx_http_log_op_s {
                     27:     size_t                      len;
                     28:     ngx_http_log_op_getlen_pt   getlen;
                     29:     ngx_http_log_op_run_pt      run;
                     30:     uintptr_t                   data;
                     31: };
                     32: 
                     33: 
                     34: typedef struct {
                     35:     ngx_str_t                   name;
                     36:     ngx_array_t                *flushes;
                     37:     ngx_array_t                *ops;        /* array of ngx_http_log_op_t */
                     38: } ngx_http_log_fmt_t;
                     39: 
                     40: 
                     41: typedef struct {
                     42:     ngx_array_t                 formats;    /* array of ngx_http_log_fmt_t */
                     43:     ngx_uint_t                  combined_used; /* unsigned  combined_used:1 */
                     44: } ngx_http_log_main_conf_t;
                     45: 
                     46: 
                     47: typedef struct {
                     48:     u_char                     *start;
                     49:     u_char                     *pos;
                     50:     u_char                     *last;
                     51: 
                     52:     ngx_event_t                *event;
                     53:     ngx_msec_t                  flush;
                     54:     ngx_int_t                   gzip;
                     55: } ngx_http_log_buf_t;
                     56: 
                     57: 
                     58: typedef struct {
                     59:     ngx_array_t                *lengths;
                     60:     ngx_array_t                *values;
                     61: } ngx_http_log_script_t;
                     62: 
                     63: 
                     64: typedef struct {
                     65:     ngx_open_file_t            *file;
                     66:     ngx_http_log_script_t      *script;
                     67:     time_t                      disk_full_time;
                     68:     time_t                      error_log_time;
                     69:     ngx_http_log_fmt_t         *format;
                     70: } ngx_http_log_t;
                     71: 
                     72: 
                     73: typedef struct {
                     74:     ngx_array_t                *logs;       /* array of ngx_http_log_t */
                     75: 
                     76:     ngx_open_file_cache_t      *open_file_cache;
                     77:     time_t                      open_file_cache_valid;
                     78:     ngx_uint_t                  open_file_cache_min_uses;
                     79: 
                     80:     ngx_uint_t                  off;        /* unsigned  off:1 */
                     81: } ngx_http_log_loc_conf_t;
                     82: 
                     83: 
                     84: typedef struct {
                     85:     ngx_str_t                   name;
                     86:     size_t                      len;
                     87:     ngx_http_log_op_run_pt      run;
                     88: } ngx_http_log_var_t;
                     89: 
                     90: 
                     91: static void ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log,
                     92:     u_char *buf, size_t len);
                     93: static ssize_t ngx_http_log_script_write(ngx_http_request_t *r,
                     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
                    103: 
                    104: static void ngx_http_log_flush(ngx_open_file_t *file, ngx_log_t *log);
                    105: static void ngx_http_log_flush_handler(ngx_event_t *ev);
                    106: 
                    107: static u_char *ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf,
                    108:     ngx_http_log_op_t *op);
                    109: static u_char *ngx_http_log_time(ngx_http_request_t *r, u_char *buf,
                    110:     ngx_http_log_op_t *op);
                    111: static u_char *ngx_http_log_iso8601(ngx_http_request_t *r, u_char *buf,
                    112:     ngx_http_log_op_t *op);
                    113: static u_char *ngx_http_log_msec(ngx_http_request_t *r, u_char *buf,
                    114:     ngx_http_log_op_t *op);
                    115: static u_char *ngx_http_log_request_time(ngx_http_request_t *r, u_char *buf,
                    116:     ngx_http_log_op_t *op);
                    117: static u_char *ngx_http_log_status(ngx_http_request_t *r, u_char *buf,
                    118:     ngx_http_log_op_t *op);
                    119: static u_char *ngx_http_log_bytes_sent(ngx_http_request_t *r, u_char *buf,
                    120:     ngx_http_log_op_t *op);
                    121: static u_char *ngx_http_log_body_bytes_sent(ngx_http_request_t *r,
                    122:     u_char *buf, ngx_http_log_op_t *op);
                    123: static u_char *ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf,
                    124:     ngx_http_log_op_t *op);
                    125: 
                    126: static ngx_int_t ngx_http_log_variable_compile(ngx_conf_t *cf,
                    127:     ngx_http_log_op_t *op, ngx_str_t *value);
                    128: static size_t ngx_http_log_variable_getlen(ngx_http_request_t *r,
                    129:     uintptr_t data);
                    130: static u_char *ngx_http_log_variable(ngx_http_request_t *r, u_char *buf,
                    131:     ngx_http_log_op_t *op);
                    132: static uintptr_t ngx_http_log_escape(u_char *dst, u_char *src, size_t size);
                    133: 
                    134: 
                    135: static void *ngx_http_log_create_main_conf(ngx_conf_t *cf);
                    136: static void *ngx_http_log_create_loc_conf(ngx_conf_t *cf);
                    137: static char *ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent,
                    138:     void *child);
                    139: static char *ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd,
                    140:     void *conf);
                    141: static char *ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd,
                    142:     void *conf);
                    143: static char *ngx_http_log_compile_format(ngx_conf_t *cf,
                    144:     ngx_array_t *flushes, ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s);
                    145: static char *ngx_http_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd,
                    146:     void *conf);
                    147: static ngx_int_t ngx_http_log_init(ngx_conf_t *cf);
                    148: 
                    149: 
                    150: static ngx_command_t  ngx_http_log_commands[] = {
                    151: 
                    152:     { ngx_string("log_format"),
                    153:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_2MORE,
                    154:       ngx_http_log_set_format,
                    155:       NGX_HTTP_MAIN_CONF_OFFSET,
                    156:       0,
                    157:       NULL },
                    158: 
                    159:     { ngx_string("access_log"),
                    160:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
                    161:                         |NGX_HTTP_LMT_CONF|NGX_CONF_1MORE,
                    162:       ngx_http_log_set_log,
                    163:       NGX_HTTP_LOC_CONF_OFFSET,
                    164:       0,
                    165:       NULL },
                    166: 
                    167:     { ngx_string("open_log_file_cache"),
                    168:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
                    169:       ngx_http_log_open_file_cache,
                    170:       NGX_HTTP_LOC_CONF_OFFSET,
                    171:       0,
                    172:       NULL },
                    173: 
                    174:       ngx_null_command
                    175: };
                    176: 
                    177: 
                    178: static ngx_http_module_t  ngx_http_log_module_ctx = {
                    179:     NULL,                                  /* preconfiguration */
                    180:     ngx_http_log_init,                     /* postconfiguration */
                    181: 
                    182:     ngx_http_log_create_main_conf,         /* create main configuration */
                    183:     NULL,                                  /* init main configuration */
                    184: 
                    185:     NULL,                                  /* create server configuration */
                    186:     NULL,                                  /* merge server configuration */
                    187: 
                    188:     ngx_http_log_create_loc_conf,          /* create location configuration */
                    189:     ngx_http_log_merge_loc_conf            /* merge location configuration */
                    190: };
                    191: 
                    192: 
                    193: ngx_module_t  ngx_http_log_module = {
                    194:     NGX_MODULE_V1,
                    195:     &ngx_http_log_module_ctx,              /* module context */
                    196:     ngx_http_log_commands,                 /* module directives */
                    197:     NGX_HTTP_MODULE,                       /* module type */
                    198:     NULL,                                  /* init master */
                    199:     NULL,                                  /* init module */
                    200:     NULL,                                  /* init process */
                    201:     NULL,                                  /* init thread */
                    202:     NULL,                                  /* exit thread */
                    203:     NULL,                                  /* exit process */
                    204:     NULL,                                  /* exit master */
                    205:     NGX_MODULE_V1_PADDING
                    206: };
                    207: 
                    208: 
                    209: static ngx_str_t  ngx_http_access_log = ngx_string(NGX_HTTP_LOG_PATH);
                    210: 
                    211: 
                    212: static ngx_str_t  ngx_http_combined_fmt =
                    213:     ngx_string("$remote_addr - $remote_user [$time_local] "
                    214:                "\"$request\" $status $body_bytes_sent "
                    215:                "\"$http_referer\" \"$http_user_agent\"");
                    216: 
                    217: 
                    218: static ngx_http_log_var_t  ngx_http_log_vars[] = {
                    219:     { ngx_string("pipe"), 1, ngx_http_log_pipe },
                    220:     { ngx_string("time_local"), sizeof("28/Sep/1970:12:00:00 +0600") - 1,
                    221:                           ngx_http_log_time },
                    222:     { ngx_string("time_iso8601"), sizeof("1970-09-28T12:00:00+06:00") - 1,
                    223:                           ngx_http_log_iso8601 },
                    224:     { ngx_string("msec"), NGX_TIME_T_LEN + 4, ngx_http_log_msec },
                    225:     { ngx_string("request_time"), NGX_TIME_T_LEN + 4,
                    226:                           ngx_http_log_request_time },
                    227:     { ngx_string("status"), NGX_INT_T_LEN, ngx_http_log_status },
                    228:     { ngx_string("bytes_sent"), NGX_OFF_T_LEN, ngx_http_log_bytes_sent },
                    229:     { ngx_string("body_bytes_sent"), NGX_OFF_T_LEN,
                    230:                           ngx_http_log_body_bytes_sent },
                    231:     { ngx_string("request_length"), NGX_SIZE_T_LEN,
                    232:                           ngx_http_log_request_length },
                    233: 
                    234:     { ngx_null_string, 0, NULL }
                    235: };
                    236: 
                    237: 
                    238: static ngx_int_t
                    239: ngx_http_log_handler(ngx_http_request_t *r)
                    240: {
                    241:     u_char                   *line, *p;
                    242:     size_t                    len;
                    243:     ngx_uint_t                i, l;
                    244:     ngx_http_log_t           *log;
                    245:     ngx_http_log_op_t        *op;
                    246:     ngx_http_log_buf_t       *buffer;
                    247:     ngx_http_log_loc_conf_t  *lcf;
                    248: 
                    249:     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    250:                    "http log handler");
                    251: 
                    252:     lcf = ngx_http_get_module_loc_conf(r, ngx_http_log_module);
                    253: 
                    254:     if (lcf->off) {
                    255:         return NGX_OK;
                    256:     }
                    257: 
                    258:     log = lcf->logs->elts;
                    259:     for (l = 0; l < lcf->logs->nelts; l++) {
                    260: 
                    261:         if (ngx_time() == log[l].disk_full_time) {
                    262: 
                    263:             /*
                    264:              * on FreeBSD writing to a full filesystem with enabled softupdates
                    265:              * may block process for much longer time than writing to non-full
                    266:              * filesystem, so we skip writing to a log for one second
                    267:              */
                    268: 
                    269:             continue;
                    270:         }
                    271: 
                    272:         ngx_http_script_flush_no_cacheable_variables(r, log[l].format->flushes);
                    273: 
                    274:         len = 0;
                    275:         op = log[l].format->ops->elts;
                    276:         for (i = 0; i < log[l].format->ops->nelts; i++) {
                    277:             if (op[i].len == 0) {
                    278:                 len += op[i].getlen(r, op[i].data);
                    279: 
                    280:             } else {
                    281:                 len += op[i].len;
                    282:             }
                    283:         }
                    284: 
                    285:         len += NGX_LINEFEED_SIZE;
                    286: 
                    287:         buffer = log[l].file ? log[l].file->data : NULL;
                    288: 
                    289:         if (buffer) {
                    290: 
                    291:             if (len > (size_t) (buffer->last - buffer->pos)) {
                    292: 
                    293:                 ngx_http_log_write(r, &log[l], buffer->start,
                    294:                                    buffer->pos - buffer->start);
                    295: 
                    296:                 buffer->pos = buffer->start;
                    297:             }
                    298: 
                    299:             if (len <= (size_t) (buffer->last - buffer->pos)) {
                    300: 
                    301:                 p = buffer->pos;
                    302: 
                    303:                 if (buffer->event && p == buffer->start) {
                    304:                     ngx_add_timer(buffer->event, buffer->flush);
                    305:                 }
                    306: 
                    307:                 for (i = 0; i < log[l].format->ops->nelts; i++) {
                    308:                     p = op[i].run(r, p, &op[i]);
                    309:                 }
                    310: 
                    311:                 ngx_linefeed(p);
                    312: 
                    313:                 buffer->pos = p;
                    314: 
                    315:                 continue;
                    316:             }
                    317: 
                    318:             if (buffer->event && buffer->event->timer_set) {
                    319:                 ngx_del_timer(buffer->event);
                    320:             }
                    321:         }
                    322: 
                    323:         line = ngx_pnalloc(r->pool, len);
                    324:         if (line == NULL) {
                    325:             return NGX_ERROR;
                    326:         }
                    327: 
                    328:         p = line;
                    329: 
                    330:         for (i = 0; i < log[l].format->ops->nelts; i++) {
                    331:             p = op[i].run(r, p, &op[i]);
                    332:         }
                    333: 
                    334:         ngx_linefeed(p);
                    335: 
                    336:         ngx_http_log_write(r, &log[l], line, p - line);
                    337:     }
                    338: 
                    339:     return NGX_OK;
                    340: }
                    341: 
                    342: 
                    343: static void
                    344: ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log, u_char *buf,
                    345:     size_t len)
                    346: {
                    347:     u_char              *name;
                    348:     time_t               now;
                    349:     ssize_t              n;
                    350:     ngx_err_t            err;
                    351: #if (NGX_ZLIB)
                    352:     ngx_http_log_buf_t  *buffer;
                    353: #endif
                    354: 
                    355:     if (log->script == NULL) {
                    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
                    368:         n = ngx_write_fd(log->file->fd, buf, len);
                    369: #endif
                    370: 
                    371:     } else {
                    372:         name = NULL;
                    373:         n = ngx_http_log_script_write(r, log->script, &name, buf, len);
                    374:     }
                    375: 
                    376:     if (n == (ssize_t) len) {
                    377:         return;
                    378:     }
                    379: 
                    380:     now = ngx_time();
                    381: 
                    382:     if (n == -1) {
                    383:         err = ngx_errno;
                    384: 
                    385:         if (err == NGX_ENOSPC) {
                    386:             log->disk_full_time = now;
                    387:         }
                    388: 
                    389:         if (now - log->error_log_time > 59) {
                    390:             ngx_log_error(NGX_LOG_ALERT, r->connection->log, err,
                    391:                           ngx_write_fd_n " to \"%s\" failed", name);
                    392: 
                    393:             log->error_log_time = now;
                    394:         }
                    395: 
                    396:         return;
                    397:     }
                    398: 
                    399:     if (now - log->error_log_time > 59) {
                    400:         ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
                    401:                       ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz",
                    402:                       name, n, len);
                    403: 
                    404:         log->error_log_time = now;
                    405:     }
                    406: }
                    407: 
                    408: 
                    409: static ssize_t
                    410: ngx_http_log_script_write(ngx_http_request_t *r, ngx_http_log_script_t *script,
                    411:     u_char **name, u_char *buf, size_t len)
                    412: {
                    413:     size_t                     root;
                    414:     ssize_t                    n;
                    415:     ngx_str_t                  log, path;
                    416:     ngx_open_file_info_t       of;
                    417:     ngx_http_log_loc_conf_t   *llcf;
                    418:     ngx_http_core_loc_conf_t  *clcf;
                    419: 
                    420:     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
                    421: 
                    422:     if (!r->root_tested) {
                    423: 
                    424:         /* test root directory existence */
                    425: 
                    426:         if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) {
                    427:             /* simulate successful logging */
                    428:             return len;
                    429:         }
                    430: 
                    431:         path.data[root] = '\0';
                    432: 
                    433:         ngx_memzero(&of, sizeof(ngx_open_file_info_t));
                    434: 
                    435:         of.valid = clcf->open_file_cache_valid;
                    436:         of.min_uses = clcf->open_file_cache_min_uses;
                    437:         of.test_dir = 1;
                    438:         of.test_only = 1;
                    439:         of.errors = clcf->open_file_cache_errors;
                    440:         of.events = clcf->open_file_cache_events;
                    441: 
                    442:         if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) {
                    443:             /* simulate successful logging */
                    444:             return len;
                    445:         }
                    446: 
                    447:         if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
                    448:             != NGX_OK)
                    449:         {
                    450:             if (of.err == 0) {
                    451:                 /* simulate successful logging */
                    452:                 return len;
                    453:             }
                    454: 
                    455:             ngx_log_error(NGX_LOG_ERR, r->connection->log, of.err,
                    456:                           "testing \"%s\" existence failed", path.data);
                    457: 
                    458:             /* simulate successful logging */
                    459:             return len;
                    460:         }
                    461: 
                    462:         if (!of.is_dir) {
                    463:             ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_ENOTDIR,
                    464:                           "testing \"%s\" existence failed", path.data);
                    465: 
                    466:             /* simulate successful logging */
                    467:             return len;
                    468:         }
                    469:     }
                    470: 
                    471:     if (ngx_http_script_run(r, &log, script->lengths->elts, 1,
                    472:                             script->values->elts)
                    473:         == NULL)
                    474:     {
                    475:         /* simulate successful logging */
                    476:         return len;
                    477:     }
                    478: 
                    479:     log.data[log.len - 1] = '\0';
                    480:     *name = log.data;
                    481: 
                    482:     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    483:                    "http log \"%s\"", log.data);
                    484: 
                    485:     llcf = ngx_http_get_module_loc_conf(r, ngx_http_log_module);
                    486: 
                    487:     ngx_memzero(&of, sizeof(ngx_open_file_info_t));
                    488: 
                    489:     of.log = 1;
                    490:     of.valid = llcf->open_file_cache_valid;
                    491:     of.min_uses = llcf->open_file_cache_min_uses;
                    492:     of.directio = NGX_OPEN_FILE_DIRECTIO_OFF;
                    493: 
                    494:     if (ngx_http_set_disable_symlinks(r, clcf, &log, &of) != NGX_OK) {
                    495:         /* simulate successful logging */
                    496:         return len;
                    497:     }
                    498: 
                    499:     if (ngx_open_cached_file(llcf->open_file_cache, &log, &of, r->pool)
                    500:         != NGX_OK)
                    501:     {
                    502:         ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
                    503:                       "%s \"%s\" failed", of.failed, log.data);
                    504:         /* simulate successful logging */
                    505:         return len;
                    506:     }
                    507: 
                    508:     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    509:                    "http log #%d", of.fd);
                    510: 
                    511:     n = ngx_write_fd(of.fd, buf, len);
                    512: 
                    513:     return n;
                    514: }
                    515: 
                    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: 
                    651: static void
                    652: ngx_http_log_flush(ngx_open_file_t *file, ngx_log_t *log)
                    653: {
                    654:     size_t               len;
                    655:     ssize_t              n;
                    656:     ngx_http_log_buf_t  *buffer;
                    657: 
                    658:     buffer = file->data;
                    659: 
                    660:     len = buffer->pos - buffer->start;
                    661: 
                    662:     if (len == 0) {
                    663:         return;
                    664:     }
                    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
                    673:     n = ngx_write_fd(file->fd, buffer->start, len);
                    674: #endif
                    675: 
                    676:     if (n == -1) {
                    677:         ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
                    678:                       ngx_write_fd_n " to \"%s\" failed",
                    679:                       file->name.data);
                    680: 
                    681:     } else if ((size_t) n != len) {
                    682:         ngx_log_error(NGX_LOG_ALERT, log, 0,
                    683:                       ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz",
                    684:                       file->name.data, n, len);
                    685:     }
                    686: 
                    687:     buffer->pos = buffer->start;
                    688: 
                    689:     if (buffer->event && buffer->event->timer_set) {
                    690:         ngx_del_timer(buffer->event);
                    691:     }
                    692: }
                    693: 
                    694: 
                    695: static void
                    696: ngx_http_log_flush_handler(ngx_event_t *ev)
                    697: {
                    698:     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0,
                    699:                    "http log buffer flush handler");
                    700: 
                    701:     ngx_http_log_flush(ev->data, ev->log);
                    702: }
                    703: 
                    704: 
                    705: static u_char *
                    706: ngx_http_log_copy_short(ngx_http_request_t *r, u_char *buf,
                    707:     ngx_http_log_op_t *op)
                    708: {
                    709:     size_t     len;
                    710:     uintptr_t  data;
                    711: 
                    712:     len = op->len;
                    713:     data = op->data;
                    714: 
                    715:     while (len--) {
                    716:         *buf++ = (u_char) (data & 0xff);
                    717:         data >>= 8;
                    718:     }
                    719: 
                    720:     return buf;
                    721: }
                    722: 
                    723: 
                    724: static u_char *
                    725: ngx_http_log_copy_long(ngx_http_request_t *r, u_char *buf,
                    726:     ngx_http_log_op_t *op)
                    727: {
                    728:     return ngx_cpymem(buf, (u_char *) op->data, op->len);
                    729: }
                    730: 
                    731: 
                    732: static u_char *
                    733: ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
                    734: {
                    735:     if (r->pipeline) {
                    736:         *buf = 'p';
                    737:     } else {
                    738:         *buf = '.';
                    739:     }
                    740: 
                    741:     return buf + 1;
                    742: }
                    743: 
                    744: 
                    745: static u_char *
                    746: ngx_http_log_time(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
                    747: {
                    748:     return ngx_cpymem(buf, ngx_cached_http_log_time.data,
                    749:                       ngx_cached_http_log_time.len);
                    750: }
                    751: 
                    752: static u_char *
                    753: ngx_http_log_iso8601(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
                    754: {
                    755:     return ngx_cpymem(buf, ngx_cached_http_log_iso8601.data,
                    756:                       ngx_cached_http_log_iso8601.len);
                    757: }
                    758: 
                    759: static u_char *
                    760: ngx_http_log_msec(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
                    761: {
                    762:     ngx_time_t  *tp;
                    763: 
                    764:     tp = ngx_timeofday();
                    765: 
                    766:     return ngx_sprintf(buf, "%T.%03M", tp->sec, tp->msec);
                    767: }
                    768: 
                    769: 
                    770: static u_char *
                    771: ngx_http_log_request_time(ngx_http_request_t *r, u_char *buf,
                    772:     ngx_http_log_op_t *op)
                    773: {
                    774:     ngx_time_t      *tp;
                    775:     ngx_msec_int_t   ms;
                    776: 
                    777:     tp = ngx_timeofday();
                    778: 
                    779:     ms = (ngx_msec_int_t)
                    780:              ((tp->sec - r->start_sec) * 1000 + (tp->msec - r->start_msec));
                    781:     ms = ngx_max(ms, 0);
                    782: 
                    783:     return ngx_sprintf(buf, "%T.%03M", (time_t) ms / 1000, ms % 1000);
                    784: }
                    785: 
                    786: 
                    787: static u_char *
                    788: ngx_http_log_status(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
                    789: {
                    790:     ngx_uint_t  status;
                    791: 
                    792:     if (r->err_status) {
                    793:         status = r->err_status;
                    794: 
                    795:     } else if (r->headers_out.status) {
                    796:         status = r->headers_out.status;
                    797: 
                    798:     } else if (r->http_version == NGX_HTTP_VERSION_9) {
                    799:         status = 9;
                    800: 
                    801:     } else {
                    802:         status = 0;
                    803:     }
                    804: 
                    805:     return ngx_sprintf(buf, "%03ui", status);
                    806: }
                    807: 
                    808: 
                    809: static u_char *
                    810: ngx_http_log_bytes_sent(ngx_http_request_t *r, u_char *buf,
                    811:     ngx_http_log_op_t *op)
                    812: {
                    813:     return ngx_sprintf(buf, "%O", r->connection->sent);
                    814: }
                    815: 
                    816: 
                    817: /*
                    818:  * although there is a real $body_bytes_sent variable,
                    819:  * this log operation code function is more optimized for logging
                    820:  */
                    821: 
                    822: static u_char *
                    823: ngx_http_log_body_bytes_sent(ngx_http_request_t *r, u_char *buf,
                    824:     ngx_http_log_op_t *op)
                    825: {
                    826:     off_t  length;
                    827: 
                    828:     length = r->connection->sent - r->header_size;
                    829: 
                    830:     if (length > 0) {
                    831:         return ngx_sprintf(buf, "%O", length);
                    832:     }
                    833: 
                    834:     *buf = '0';
                    835: 
                    836:     return buf + 1;
                    837: }
                    838: 
                    839: 
                    840: static u_char *
                    841: ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf,
                    842:     ngx_http_log_op_t *op)
                    843: {
                    844:     return ngx_sprintf(buf, "%O", r->request_length);
                    845: }
                    846: 
                    847: 
                    848: static ngx_int_t
                    849: ngx_http_log_variable_compile(ngx_conf_t *cf, ngx_http_log_op_t *op,
                    850:     ngx_str_t *value)
                    851: {
                    852:     ngx_int_t  index;
                    853: 
                    854:     index = ngx_http_get_variable_index(cf, value);
                    855:     if (index == NGX_ERROR) {
                    856:         return NGX_ERROR;
                    857:     }
                    858: 
                    859:     op->len = 0;
                    860:     op->getlen = ngx_http_log_variable_getlen;
                    861:     op->run = ngx_http_log_variable;
                    862:     op->data = index;
                    863: 
                    864:     return NGX_OK;
                    865: }
                    866: 
                    867: 
                    868: static size_t
                    869: ngx_http_log_variable_getlen(ngx_http_request_t *r, uintptr_t data)
                    870: {
                    871:     uintptr_t                   len;
                    872:     ngx_http_variable_value_t  *value;
                    873: 
                    874:     value = ngx_http_get_indexed_variable(r, data);
                    875: 
                    876:     if (value == NULL || value->not_found) {
                    877:         return 1;
                    878:     }
                    879: 
                    880:     len = ngx_http_log_escape(NULL, value->data, value->len);
                    881: 
                    882:     value->escape = len ? 1 : 0;
                    883: 
                    884:     return value->len + len * 3;
                    885: }
                    886: 
                    887: 
                    888: static u_char *
                    889: ngx_http_log_variable(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
                    890: {
                    891:     ngx_http_variable_value_t  *value;
                    892: 
                    893:     value = ngx_http_get_indexed_variable(r, op->data);
                    894: 
                    895:     if (value == NULL || value->not_found) {
                    896:         *buf = '-';
                    897:         return buf + 1;
                    898:     }
                    899: 
                    900:     if (value->escape == 0) {
                    901:         return ngx_cpymem(buf, value->data, value->len);
                    902: 
                    903:     } else {
                    904:         return (u_char *) ngx_http_log_escape(buf, value->data, value->len);
                    905:     }
                    906: }
                    907: 
                    908: 
                    909: static uintptr_t
                    910: ngx_http_log_escape(u_char *dst, u_char *src, size_t size)
                    911: {
                    912:     ngx_uint_t      n;
                    913:     static u_char   hex[] = "0123456789ABCDEF";
                    914: 
                    915:     static uint32_t   escape[] = {
                    916:         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
                    917: 
                    918:                     /* ?>=< ;:98 7654 3210  /.-, +*)( '&%$ #"!  */
                    919:         0x00000004, /* 0000 0000 0000 0000  0000 0000 0000 0100 */
                    920: 
                    921:                     /* _^]\ [ZYX WVUT SRQP  ONML KJIH GFED CBA@ */
                    922:         0x10000000, /* 0001 0000 0000 0000  0000 0000 0000 0000 */
                    923: 
                    924:                     /*  ~}| {zyx wvut srqp  onml kjih gfed cba` */
                    925:         0x80000000, /* 1000 0000 0000 0000  0000 0000 0000 0000 */
                    926: 
                    927:         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
                    928:         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
                    929:         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
                    930:         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
                    931:     };
                    932: 
                    933: 
                    934:     if (dst == NULL) {
                    935: 
                    936:         /* find the number of the characters to be escaped */
                    937: 
                    938:         n = 0;
                    939: 
                    940:         while (size) {
                    941:             if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
                    942:                 n++;
                    943:             }
                    944:             src++;
                    945:             size--;
                    946:         }
                    947: 
                    948:         return (uintptr_t) n;
                    949:     }
                    950: 
                    951:     while (size) {
                    952:         if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
                    953:             *dst++ = '\\';
                    954:             *dst++ = 'x';
                    955:             *dst++ = hex[*src >> 4];
                    956:             *dst++ = hex[*src & 0xf];
                    957:             src++;
                    958: 
                    959:         } else {
                    960:             *dst++ = *src++;
                    961:         }
                    962:         size--;
                    963:     }
                    964: 
                    965:     return (uintptr_t) dst;
                    966: }
                    967: 
                    968: 
                    969: static void *
                    970: ngx_http_log_create_main_conf(ngx_conf_t *cf)
                    971: {
                    972:     ngx_http_log_main_conf_t  *conf;
                    973: 
                    974:     ngx_http_log_fmt_t  *fmt;
                    975: 
                    976:     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_main_conf_t));
                    977:     if (conf == NULL) {
                    978:         return NULL;
                    979:     }
                    980: 
                    981:     if (ngx_array_init(&conf->formats, cf->pool, 4, sizeof(ngx_http_log_fmt_t))
                    982:         != NGX_OK)
                    983:     {
                    984:         return NULL;
                    985:     }
                    986: 
                    987:     fmt = ngx_array_push(&conf->formats);
                    988:     if (fmt == NULL) {
                    989:         return NULL;
                    990:     }
                    991: 
                    992:     ngx_str_set(&fmt->name, "combined");
                    993: 
                    994:     fmt->flushes = NULL;
                    995: 
                    996:     fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_http_log_op_t));
                    997:     if (fmt->ops == NULL) {
                    998:         return NULL;
                    999:     }
                   1000: 
                   1001:     return conf;
                   1002: }
                   1003: 
                   1004: 
                   1005: static void *
                   1006: ngx_http_log_create_loc_conf(ngx_conf_t *cf)
                   1007: {
                   1008:     ngx_http_log_loc_conf_t  *conf;
                   1009: 
                   1010:     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_loc_conf_t));
                   1011:     if (conf == NULL) {
                   1012:         return NULL;
                   1013:     }
                   1014: 
                   1015:     conf->open_file_cache = NGX_CONF_UNSET_PTR;
                   1016: 
                   1017:     return conf;
                   1018: }
                   1019: 
                   1020: 
                   1021: static char *
                   1022: ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
                   1023: {
                   1024:     ngx_http_log_loc_conf_t *prev = parent;
                   1025:     ngx_http_log_loc_conf_t *conf = child;
                   1026: 
                   1027:     ngx_http_log_t            *log;
                   1028:     ngx_http_log_fmt_t        *fmt;
                   1029:     ngx_http_log_main_conf_t  *lmcf;
                   1030: 
                   1031:     if (conf->open_file_cache == NGX_CONF_UNSET_PTR) {
                   1032: 
                   1033:         conf->open_file_cache = prev->open_file_cache;
                   1034:         conf->open_file_cache_valid = prev->open_file_cache_valid;
                   1035:         conf->open_file_cache_min_uses = prev->open_file_cache_min_uses;
                   1036: 
                   1037:         if (conf->open_file_cache == NGX_CONF_UNSET_PTR) {
                   1038:             conf->open_file_cache = NULL;
                   1039:         }
                   1040:     }
                   1041: 
                   1042:     if (conf->logs || conf->off) {
                   1043:         return NGX_CONF_OK;
                   1044:     }
                   1045: 
                   1046:     conf->logs = prev->logs;
                   1047:     conf->off = prev->off;
                   1048: 
                   1049:     if (conf->logs || conf->off) {
                   1050:         return NGX_CONF_OK;
                   1051:     }
                   1052: 
                   1053:     conf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_http_log_t));
                   1054:     if (conf->logs == NULL) {
                   1055:         return NGX_CONF_ERROR;
                   1056:     }
                   1057: 
                   1058:     log = ngx_array_push(conf->logs);
                   1059:     if (log == NULL) {
                   1060:         return NGX_CONF_ERROR;
                   1061:     }
                   1062: 
                   1063:     log->file = ngx_conf_open_file(cf->cycle, &ngx_http_access_log);
                   1064:     if (log->file == NULL) {
                   1065:         return NGX_CONF_ERROR;
                   1066:     }
                   1067: 
                   1068:     log->script = NULL;
                   1069:     log->disk_full_time = 0;
                   1070:     log->error_log_time = 0;
                   1071: 
                   1072:     lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);
                   1073:     fmt = lmcf->formats.elts;
                   1074: 
                   1075:     /* the default "combined" format */
                   1076:     log->format = &fmt[0];
                   1077:     lmcf->combined_used = 1;
                   1078: 
                   1079:     return NGX_CONF_OK;
                   1080: }
                   1081: 
                   1082: 
                   1083: static char *
                   1084: ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
                   1085: {
                   1086:     ngx_http_log_loc_conf_t *llcf = conf;
                   1087: 
                   1088:     ssize_t                     size;
                   1089:     ngx_int_t                   gzip;
                   1090:     ngx_uint_t                  i, n;
                   1091:     ngx_msec_t                  flush;
                   1092:     ngx_str_t                  *value, name, s;
                   1093:     ngx_http_log_t             *log;
                   1094:     ngx_http_log_buf_t         *buffer;
                   1095:     ngx_http_log_fmt_t         *fmt;
                   1096:     ngx_http_log_main_conf_t   *lmcf;
                   1097:     ngx_http_script_compile_t   sc;
                   1098: 
                   1099:     value = cf->args->elts;
                   1100: 
                   1101:     if (ngx_strcmp(value[1].data, "off") == 0) {
                   1102:         llcf->off = 1;
                   1103:         if (cf->args->nelts == 2) {
                   1104:             return NGX_CONF_OK;
                   1105:         }
                   1106: 
                   1107:         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                   1108:                            "invalid parameter \"%V\"", &value[2]);
                   1109:         return NGX_CONF_ERROR;
                   1110:     }
                   1111: 
                   1112:     if (llcf->logs == NULL) {
                   1113:         llcf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_http_log_t));
                   1114:         if (llcf->logs == NULL) {
                   1115:             return NGX_CONF_ERROR;
                   1116:         }
                   1117:     }
                   1118: 
                   1119:     lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);
                   1120: 
                   1121:     log = ngx_array_push(llcf->logs);
                   1122:     if (log == NULL) {
                   1123:         return NGX_CONF_ERROR;
                   1124:     }
                   1125: 
                   1126:     ngx_memzero(log, sizeof(ngx_http_log_t));
                   1127: 
                   1128:     n = ngx_http_script_variables_count(&value[1]);
                   1129: 
                   1130:     if (n == 0) {
                   1131:         log->file = ngx_conf_open_file(cf->cycle, &value[1]);
                   1132:         if (log->file == NULL) {
                   1133:             return NGX_CONF_ERROR;
                   1134:         }
                   1135: 
                   1136:     } else {
                   1137:         if (ngx_conf_full_name(cf->cycle, &value[1], 0) != NGX_OK) {
                   1138:             return NGX_CONF_ERROR;
                   1139:         }
                   1140: 
                   1141:         log->script = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_script_t));
                   1142:         if (log->script == NULL) {
                   1143:             return NGX_CONF_ERROR;
                   1144:         }
                   1145: 
                   1146:         ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
                   1147: 
                   1148:         sc.cf = cf;
                   1149:         sc.source = &value[1];
                   1150:         sc.lengths = &log->script->lengths;
                   1151:         sc.values = &log->script->values;
                   1152:         sc.variables = n;
                   1153:         sc.complete_lengths = 1;
                   1154:         sc.complete_values = 1;
                   1155: 
                   1156:         if (ngx_http_script_compile(&sc) != NGX_OK) {
                   1157:             return NGX_CONF_ERROR;
                   1158:         }
                   1159:     }
                   1160: 
                   1161:     if (cf->args->nelts >= 3) {
                   1162:         name = value[2];
                   1163: 
                   1164:         if (ngx_strcmp(name.data, "combined") == 0) {
                   1165:             lmcf->combined_used = 1;
                   1166:         }
                   1167: 
                   1168:     } else {
                   1169:         ngx_str_set(&name, "combined");
                   1170:         lmcf->combined_used = 1;
                   1171:     }
                   1172: 
                   1173:     fmt = lmcf->formats.elts;
                   1174:     for (i = 0; i < lmcf->formats.nelts; i++) {
                   1175:         if (fmt[i].name.len == name.len
                   1176:             && ngx_strcasecmp(fmt[i].name.data, name.data) == 0)
                   1177:         {
                   1178:             log->format = &fmt[i];
                   1179:             break;
                   1180:         }
                   1181:     }
                   1182: 
                   1183:     if (log->format == NULL) {
                   1184:         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                   1185:                            "unknown log format \"%V\"", &name);
                   1186:         return NGX_CONF_ERROR;
                   1187:     }
                   1188: 
                   1189:     size = 0;
                   1190:     flush = 0;
                   1191:     gzip = 0;
                   1192: 
                   1193:     for (i = 3; i < cf->args->nelts; i++) {
                   1194: 
                   1195:         if (ngx_strncmp(value[i].data, "buffer=", 7) == 0) {
                   1196:             s.len = value[i].len - 7;
                   1197:             s.data = value[i].data + 7;
                   1198: 
                   1199:             size = ngx_parse_size(&s);
                   1200: 
                   1201:             if (size == NGX_ERROR || size == 0) {
                   1202:                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                   1203:                                    "invalid buffer size \"%V\"", &s);
                   1204:                 return NGX_CONF_ERROR;
                   1205:             }
                   1206: 
                   1207:             continue;
                   1208:         }
                   1209: 
                   1210:         if (ngx_strncmp(value[i].data, "flush=", 6) == 0) {
                   1211:             s.len = value[i].len - 6;
                   1212:             s.data = value[i].data + 6;
                   1213: 
                   1214:             flush = ngx_parse_time(&s, 0);
                   1215: 
                   1216:             if (flush == (ngx_msec_t) NGX_ERROR || flush == 0) {
                   1217:                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                   1218:                                    "invalid flush time \"%V\"", &s);
                   1219:                 return NGX_CONF_ERROR;
                   1220:             }
                   1221: 
                   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
                   1256:         }
                   1257: 
                   1258:         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                   1259:                            "invalid parameter \"%V\"", &value[i]);
                   1260:         return NGX_CONF_ERROR;
                   1261:     }
                   1262: 
                   1263:     if (flush && size == 0) {
                   1264:         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                   1265:                            "no buffer is defined for access_log \"%V\"",
                   1266:                            &value[1]);
                   1267:         return NGX_CONF_ERROR;
                   1268:     }
                   1269: 
                   1270:     if (size) {
                   1271: 
                   1272:         if (log->script) {
                   1273:             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                   1274:                                "buffered logs cannot have variables in name");
                   1275:             return NGX_CONF_ERROR;
                   1276:         }
                   1277: 
                   1278:         if (log->file->data) {
                   1279:             buffer = log->file->data;
                   1280: 
                   1281:             if (buffer->last - buffer->start != size
                   1282:                 || buffer->flush != flush
                   1283:                 || buffer->gzip != gzip)
                   1284:             {
                   1285:                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                   1286:                                    "access_log \"%V\" already defined "
                   1287:                                    "with conflicting parameters",
                   1288:                                    &value[1]);
                   1289:                 return NGX_CONF_ERROR;
                   1290:             }
                   1291: 
                   1292:             return NGX_CONF_OK;
                   1293:         }
                   1294: 
                   1295:         buffer = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_buf_t));
                   1296:         if (buffer == NULL) {
                   1297:             return NGX_CONF_ERROR;
                   1298:         }
                   1299: 
                   1300:         buffer->start = ngx_pnalloc(cf->pool, size);
                   1301:         if (buffer->start == NULL) {
                   1302:             return NGX_CONF_ERROR;
                   1303:         }
                   1304: 
                   1305:         buffer->pos = buffer->start;
                   1306:         buffer->last = buffer->start + size;
                   1307: 
                   1308:         if (flush) {
                   1309:             buffer->event = ngx_pcalloc(cf->pool, sizeof(ngx_event_t));
                   1310:             if (buffer->event == NULL) {
                   1311:                 return NGX_CONF_ERROR;
                   1312:             }
                   1313: 
                   1314:             buffer->event->data = log->file;
                   1315:             buffer->event->handler = ngx_http_log_flush_handler;
                   1316:             buffer->event->log = &cf->cycle->new_log;
                   1317: 
                   1318:             buffer->flush = flush;
                   1319:         }
                   1320: 
                   1321:         buffer->gzip = gzip;
                   1322: 
                   1323:         log->file->flush = ngx_http_log_flush;
                   1324:         log->file->data = buffer;
                   1325:     }
                   1326: 
                   1327:     return NGX_CONF_OK;
                   1328: }
                   1329: 
                   1330: 
                   1331: static char *
                   1332: ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
                   1333: {
                   1334:     ngx_http_log_main_conf_t *lmcf = conf;
                   1335: 
                   1336:     ngx_str_t           *value;
                   1337:     ngx_uint_t           i;
                   1338:     ngx_http_log_fmt_t  *fmt;
                   1339: 
                   1340:     if (cf->cmd_type != NGX_HTTP_MAIN_CONF) {
                   1341:         ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
                   1342:                            "the \"log_format\" directive may be used "
                   1343:                            "only on \"http\" level");
                   1344:     }
                   1345: 
                   1346:     value = cf->args->elts;
                   1347: 
                   1348:     fmt = lmcf->formats.elts;
                   1349:     for (i = 0; i < lmcf->formats.nelts; i++) {
                   1350:         if (fmt[i].name.len == value[1].len
                   1351:             && ngx_strcmp(fmt[i].name.data, value[1].data) == 0)
                   1352:         {
                   1353:             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                   1354:                                "duplicate \"log_format\" name \"%V\"",
                   1355:                                &value[1]);
                   1356:             return NGX_CONF_ERROR;
                   1357:         }
                   1358:     }
                   1359: 
                   1360:     fmt = ngx_array_push(&lmcf->formats);
                   1361:     if (fmt == NULL) {
                   1362:         return NGX_CONF_ERROR;
                   1363:     }
                   1364: 
                   1365:     fmt->name = value[1];
                   1366: 
                   1367:     fmt->flushes = ngx_array_create(cf->pool, 4, sizeof(ngx_int_t));
                   1368:     if (fmt->flushes == NULL) {
                   1369:         return NGX_CONF_ERROR;
                   1370:     }
                   1371: 
                   1372:     fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_http_log_op_t));
                   1373:     if (fmt->ops == NULL) {
                   1374:         return NGX_CONF_ERROR;
                   1375:     }
                   1376: 
                   1377:     return ngx_http_log_compile_format(cf, fmt->flushes, fmt->ops, cf->args, 2);
                   1378: }
                   1379: 
                   1380: 
                   1381: static char *
                   1382: ngx_http_log_compile_format(ngx_conf_t *cf, ngx_array_t *flushes,
                   1383:     ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s)
                   1384: {
                   1385:     u_char              *data, *p, ch;
                   1386:     size_t               i, len;
                   1387:     ngx_str_t           *value, var;
                   1388:     ngx_int_t           *flush;
                   1389:     ngx_uint_t           bracket;
                   1390:     ngx_http_log_op_t   *op;
                   1391:     ngx_http_log_var_t  *v;
                   1392: 
                   1393:     value = args->elts;
                   1394: 
                   1395:     for ( /* void */ ; s < args->nelts; s++) {
                   1396: 
                   1397:         i = 0;
                   1398: 
                   1399:         while (i < value[s].len) {
                   1400: 
                   1401:             op = ngx_array_push(ops);
                   1402:             if (op == NULL) {
                   1403:                 return NGX_CONF_ERROR;
                   1404:             }
                   1405: 
                   1406:             data = &value[s].data[i];
                   1407: 
                   1408:             if (value[s].data[i] == '$') {
                   1409: 
                   1410:                 if (++i == value[s].len) {
                   1411:                     goto invalid;
                   1412:                 }
                   1413: 
                   1414:                 if (value[s].data[i] == '{') {
                   1415:                     bracket = 1;
                   1416: 
                   1417:                     if (++i == value[s].len) {
                   1418:                         goto invalid;
                   1419:                     }
                   1420: 
                   1421:                     var.data = &value[s].data[i];
                   1422: 
                   1423:                 } else {
                   1424:                     bracket = 0;
                   1425:                     var.data = &value[s].data[i];
                   1426:                 }
                   1427: 
                   1428:                 for (var.len = 0; i < value[s].len; i++, var.len++) {
                   1429:                     ch = value[s].data[i];
                   1430: 
                   1431:                     if (ch == '}' && bracket) {
                   1432:                         i++;
                   1433:                         bracket = 0;
                   1434:                         break;
                   1435:                     }
                   1436: 
                   1437:                     if ((ch >= 'A' && ch <= 'Z')
                   1438:                         || (ch >= 'a' && ch <= 'z')
                   1439:                         || (ch >= '0' && ch <= '9')
                   1440:                         || ch == '_')
                   1441:                     {
                   1442:                         continue;
                   1443:                     }
                   1444: 
                   1445:                     break;
                   1446:                 }
                   1447: 
                   1448:                 if (bracket) {
                   1449:                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                   1450:                                        "the closing bracket in \"%V\" "
                   1451:                                        "variable is missing", &var);
                   1452:                     return NGX_CONF_ERROR;
                   1453:                 }
                   1454: 
                   1455:                 if (var.len == 0) {
                   1456:                     goto invalid;
                   1457:                 }
                   1458: 
                   1459:                 for (v = ngx_http_log_vars; v->name.len; v++) {
                   1460: 
                   1461:                     if (v->name.len == var.len
                   1462:                         && ngx_strncmp(v->name.data, var.data, var.len) == 0)
                   1463:                     {
                   1464:                         op->len = v->len;
                   1465:                         op->getlen = NULL;
                   1466:                         op->run = v->run;
                   1467:                         op->data = 0;
                   1468: 
                   1469:                         goto found;
                   1470:                     }
                   1471:                 }
                   1472: 
                   1473:                 if (ngx_http_log_variable_compile(cf, op, &var) != NGX_OK) {
                   1474:                     return NGX_CONF_ERROR;
                   1475:                 }
                   1476: 
                   1477:                 if (flushes) {
                   1478: 
                   1479:                     flush = ngx_array_push(flushes);
                   1480:                     if (flush == NULL) {
                   1481:                         return NGX_CONF_ERROR;
                   1482:                     }
                   1483: 
                   1484:                     *flush = op->data; /* variable index */
                   1485:                 }
                   1486: 
                   1487:             found:
                   1488: 
                   1489:                 continue;
                   1490:             }
                   1491: 
                   1492:             i++;
                   1493: 
                   1494:             while (i < value[s].len && value[s].data[i] != '$') {
                   1495:                 i++;
                   1496:             }
                   1497: 
                   1498:             len = &value[s].data[i] - data;
                   1499: 
                   1500:             if (len) {
                   1501: 
                   1502:                 op->len = len;
                   1503:                 op->getlen = NULL;
                   1504: 
                   1505:                 if (len <= sizeof(uintptr_t)) {
                   1506:                     op->run = ngx_http_log_copy_short;
                   1507:                     op->data = 0;
                   1508: 
                   1509:                     while (len--) {
                   1510:                         op->data <<= 8;
                   1511:                         op->data |= data[len];
                   1512:                     }
                   1513: 
                   1514:                 } else {
                   1515:                     op->run = ngx_http_log_copy_long;
                   1516: 
                   1517:                     p = ngx_pnalloc(cf->pool, len);
                   1518:                     if (p == NULL) {
                   1519:                         return NGX_CONF_ERROR;
                   1520:                     }
                   1521: 
                   1522:                     ngx_memcpy(p, data, len);
                   1523:                     op->data = (uintptr_t) p;
                   1524:                 }
                   1525:             }
                   1526:         }
                   1527:     }
                   1528: 
                   1529:     return NGX_CONF_OK;
                   1530: 
                   1531: invalid:
                   1532: 
                   1533:     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%s\"", data);
                   1534: 
                   1535:     return NGX_CONF_ERROR;
                   1536: }
                   1537: 
                   1538: 
                   1539: static char *
                   1540: ngx_http_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
                   1541: {
                   1542:     ngx_http_log_loc_conf_t *llcf = conf;
                   1543: 
                   1544:     time_t       inactive, valid;
                   1545:     ngx_str_t   *value, s;
                   1546:     ngx_int_t    max, min_uses;
                   1547:     ngx_uint_t   i;
                   1548: 
                   1549:     if (llcf->open_file_cache != NGX_CONF_UNSET_PTR) {
                   1550:         return "is duplicate";
                   1551:     }
                   1552: 
                   1553:     value = cf->args->elts;
                   1554: 
                   1555:     max = 0;
                   1556:     inactive = 10;
                   1557:     valid = 60;
                   1558:     min_uses = 1;
                   1559: 
                   1560:     for (i = 1; i < cf->args->nelts; i++) {
                   1561: 
                   1562:         if (ngx_strncmp(value[i].data, "max=", 4) == 0) {
                   1563: 
                   1564:             max = ngx_atoi(value[i].data + 4, value[i].len - 4);
                   1565:             if (max == NGX_ERROR) {
                   1566:                 goto failed;
                   1567:             }
                   1568: 
                   1569:             continue;
                   1570:         }
                   1571: 
                   1572:         if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) {
                   1573: 
                   1574:             s.len = value[i].len - 9;
                   1575:             s.data = value[i].data + 9;
                   1576: 
                   1577:             inactive = ngx_parse_time(&s, 1);
                   1578:             if (inactive == (time_t) NGX_ERROR) {
                   1579:                 goto failed;
                   1580:             }
                   1581: 
                   1582:             continue;
                   1583:         }
                   1584: 
                   1585:         if (ngx_strncmp(value[i].data, "min_uses=", 9) == 0) {
                   1586: 
                   1587:             min_uses = ngx_atoi(value[i].data + 9, value[i].len - 9);
                   1588:             if (min_uses == NGX_ERROR) {
                   1589:                 goto failed;
                   1590:             }
                   1591: 
                   1592:             continue;
                   1593:         }
                   1594: 
                   1595:         if (ngx_strncmp(value[i].data, "valid=", 6) == 0) {
                   1596: 
                   1597:             s.len = value[i].len - 6;
                   1598:             s.data = value[i].data + 6;
                   1599: 
                   1600:             valid = ngx_parse_time(&s, 1);
                   1601:             if (valid == (time_t) NGX_ERROR) {
                   1602:                 goto failed;
                   1603:             }
                   1604: 
                   1605:             continue;
                   1606:         }
                   1607: 
                   1608:         if (ngx_strcmp(value[i].data, "off") == 0) {
                   1609: 
                   1610:             llcf->open_file_cache = NULL;
                   1611: 
                   1612:             continue;
                   1613:         }
                   1614: 
                   1615:     failed:
                   1616: 
                   1617:         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                   1618:                            "invalid \"open_log_file_cache\" parameter \"%V\"",
                   1619:                            &value[i]);
                   1620:         return NGX_CONF_ERROR;
                   1621:     }
                   1622: 
                   1623:     if (llcf->open_file_cache == NULL) {
                   1624:         return NGX_CONF_OK;
                   1625:     }
                   1626: 
                   1627:     if (max == 0) {
                   1628:         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                   1629:                         "\"open_log_file_cache\" must have \"max\" parameter");
                   1630:         return NGX_CONF_ERROR;
                   1631:     }
                   1632: 
                   1633:     llcf->open_file_cache = ngx_open_file_cache_init(cf->pool, max, inactive);
                   1634: 
                   1635:     if (llcf->open_file_cache) {
                   1636: 
                   1637:         llcf->open_file_cache_valid = valid;
                   1638:         llcf->open_file_cache_min_uses = min_uses;
                   1639: 
                   1640:         return NGX_CONF_OK;
                   1641:     }
                   1642: 
                   1643:     return NGX_CONF_ERROR;
                   1644: }
                   1645: 
                   1646: 
                   1647: static ngx_int_t
                   1648: ngx_http_log_init(ngx_conf_t *cf)
                   1649: {
                   1650:     ngx_str_t                  *value;
                   1651:     ngx_array_t                 a;
                   1652:     ngx_http_handler_pt        *h;
                   1653:     ngx_http_log_fmt_t         *fmt;
                   1654:     ngx_http_log_main_conf_t   *lmcf;
                   1655:     ngx_http_core_main_conf_t  *cmcf;
                   1656: 
                   1657:     lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);
                   1658: 
                   1659:     if (lmcf->combined_used) {
                   1660:         if (ngx_array_init(&a, cf->pool, 1, sizeof(ngx_str_t)) != NGX_OK) {
                   1661:             return NGX_ERROR;
                   1662:         }
                   1663: 
                   1664:         value = ngx_array_push(&a);
                   1665:         if (value == NULL) {
                   1666:             return NGX_ERROR;
                   1667:         }
                   1668: 
                   1669:         *value = ngx_http_combined_fmt;
                   1670:         fmt = lmcf->formats.elts;
                   1671: 
                   1672:         if (ngx_http_log_compile_format(cf, NULL, fmt->ops, &a, 0)
                   1673:             != NGX_CONF_OK)
                   1674:         {
                   1675:             return NGX_ERROR;
                   1676:         }
                   1677:     }
                   1678: 
                   1679:     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
                   1680: 
                   1681:     h = ngx_array_push(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers);
                   1682:     if (h == NULL) {
                   1683:         return NGX_ERROR;
                   1684:     }
                   1685: 
                   1686:     *h = ngx_http_log_handler;
                   1687: 
                   1688:     return NGX_OK;
                   1689: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>