Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.13.12 ]​[ nginx-1.12.2 ]​

0001 
0002 /*
0003  * Copyright (C) Igor Sysoev
0004  * Copyright (C) Nginx, Inc.
0005  */
0006 
0007 
0008 #include <ngx_config.h>
0009 #include <ngx_core.h>
0010 #include <ngx_http.h>
0011 
0012 #if (NGX_ZLIB)
0013 #include <zlib.h>
0014 #endif
0015 
0016 
0017 typedef struct ngx_http_log_op_s  ngx_http_log_op_t;
0018 
0019 typedef u_char *(*ngx_http_log_op_run_pt) (ngx_http_request_t *r, u_char *buf,
0020     ngx_http_log_op_t *op);
0021 
0022 typedef size_t (*ngx_http_log_op_getlen_pt) (ngx_http_request_t *r,
0023     uintptr_t data);
0024 
0025 
0026 struct ngx_http_log_op_s {
0027     size_t                      len;
0028     ngx_http_log_op_getlen_pt   getlen;
0029     ngx_http_log_op_run_pt      run;
0030     uintptr_t                   data;
0031 };
0032 
0033 
0034 typedef struct {
0035     ngx_str_t                   name;
0036     ngx_array_t                *flushes;
0037     ngx_array_t                *ops;        /* array of ngx_http_log_op_t */
0038 } ngx_http_log_fmt_t;
0039 
0040 
0041 typedef struct {
0042     ngx_array_t                 formats;    /* array of ngx_http_log_fmt_t */
0043     ngx_uint_t                  combined_used; /* unsigned  combined_used:1 */
0044 } ngx_http_log_main_conf_t;
0045 
0046 
0047 typedef struct {
0048     u_char                     *start;
0049     u_char                     *pos;
0050     u_char                     *last;
0051 
0052     ngx_event_t                *event;
0053     ngx_msec_t                  flush;
0054     ngx_int_t                   gzip;
0055 } ngx_http_log_buf_t;
0056 
0057 
0058 typedef struct {
0059     ngx_array_t                *lengths;
0060     ngx_array_t                *values;
0061 } ngx_http_log_script_t;
0062 
0063 
0064 typedef struct {
0065     ngx_open_file_t            *file;
0066     ngx_http_log_script_t      *script;
0067     time_t                      disk_full_time;
0068     time_t                      error_log_time;
0069     ngx_syslog_peer_t          *syslog_peer;
0070     ngx_http_log_fmt_t         *format;
0071     ngx_http_complex_value_t   *filter;
0072 } ngx_http_log_t;
0073 
0074 
0075 typedef struct {
0076     ngx_array_t                *logs;       /* array of ngx_http_log_t */
0077 
0078     ngx_open_file_cache_t      *open_file_cache;
0079     time_t                      open_file_cache_valid;
0080     ngx_uint_t                  open_file_cache_min_uses;
0081 
0082     ngx_uint_t                  off;        /* unsigned  off:1 */
0083 } ngx_http_log_loc_conf_t;
0084 
0085 
0086 typedef struct {
0087     ngx_str_t                   name;
0088     size_t                      len;
0089     ngx_http_log_op_run_pt      run;
0090 } ngx_http_log_var_t;
0091 
0092 
0093 static void ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log,
0094     u_char *buf, size_t len);
0095 static ssize_t ngx_http_log_script_write(ngx_http_request_t *r,
0096     ngx_http_log_script_t *script, u_char **name, u_char *buf, size_t len);
0097 
0098 #if (NGX_ZLIB)
0099 static ssize_t ngx_http_log_gzip(ngx_fd_t fd, u_char *buf, size_t len,
0100     ngx_int_t level, ngx_log_t *log);
0101 
0102 static void *ngx_http_log_gzip_alloc(void *opaque, u_int items, u_int size);
0103 static void ngx_http_log_gzip_free(void *opaque, void *address);
0104 #endif
0105 
0106 static void ngx_http_log_flush(ngx_open_file_t *file, ngx_log_t *log);
0107 static void ngx_http_log_flush_handler(ngx_event_t *ev);
0108 
0109 static u_char *ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf,
0110     ngx_http_log_op_t *op);
0111 static u_char *ngx_http_log_time(ngx_http_request_t *r, u_char *buf,
0112     ngx_http_log_op_t *op);
0113 static u_char *ngx_http_log_iso8601(ngx_http_request_t *r, u_char *buf,
0114     ngx_http_log_op_t *op);
0115 static u_char *ngx_http_log_msec(ngx_http_request_t *r, u_char *buf,
0116     ngx_http_log_op_t *op);
0117 static u_char *ngx_http_log_request_time(ngx_http_request_t *r, u_char *buf,
0118     ngx_http_log_op_t *op);
0119 static u_char *ngx_http_log_status(ngx_http_request_t *r, u_char *buf,
0120     ngx_http_log_op_t *op);
0121 static u_char *ngx_http_log_bytes_sent(ngx_http_request_t *r, u_char *buf,
0122     ngx_http_log_op_t *op);
0123 static u_char *ngx_http_log_body_bytes_sent(ngx_http_request_t *r,
0124     u_char *buf, ngx_http_log_op_t *op);
0125 static u_char *ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf,
0126     ngx_http_log_op_t *op);
0127 
0128 static ngx_int_t ngx_http_log_variable_compile(ngx_conf_t *cf,
0129     ngx_http_log_op_t *op, ngx_str_t *value, ngx_uint_t json);
0130 static size_t ngx_http_log_variable_getlen(ngx_http_request_t *r,
0131     uintptr_t data);
0132 static u_char *ngx_http_log_variable(ngx_http_request_t *r, u_char *buf,
0133     ngx_http_log_op_t *op);
0134 static uintptr_t ngx_http_log_escape(u_char *dst, u_char *src, size_t size);
0135 static size_t ngx_http_log_json_variable_getlen(ngx_http_request_t *r,
0136     uintptr_t data);
0137 static u_char *ngx_http_log_json_variable(ngx_http_request_t *r, u_char *buf,
0138     ngx_http_log_op_t *op);
0139 
0140 
0141 static void *ngx_http_log_create_main_conf(ngx_conf_t *cf);
0142 static void *ngx_http_log_create_loc_conf(ngx_conf_t *cf);
0143 static char *ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent,
0144     void *child);
0145 static char *ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd,
0146     void *conf);
0147 static char *ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd,
0148     void *conf);
0149 static char *ngx_http_log_compile_format(ngx_conf_t *cf,
0150     ngx_array_t *flushes, ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s);
0151 static char *ngx_http_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd,
0152     void *conf);
0153 static ngx_int_t ngx_http_log_init(ngx_conf_t *cf);
0154 
0155 
0156 static ngx_command_t  ngx_http_log_commands[] = {
0157 
0158     { ngx_string("log_format"),
0159       NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE,
0160       ngx_http_log_set_format,
0161       NGX_HTTP_MAIN_CONF_OFFSET,
0162       0,
0163       NULL },
0164 
0165     { ngx_string("access_log"),
0166       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
0167                         |NGX_HTTP_LMT_CONF|NGX_CONF_1MORE,
0168       ngx_http_log_set_log,
0169       NGX_HTTP_LOC_CONF_OFFSET,
0170       0,
0171       NULL },
0172 
0173     { ngx_string("open_log_file_cache"),
0174       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
0175       ngx_http_log_open_file_cache,
0176       NGX_HTTP_LOC_CONF_OFFSET,
0177       0,
0178       NULL },
0179 
0180       ngx_null_command
0181 };
0182 
0183 
0184 static ngx_http_module_t  ngx_http_log_module_ctx = {
0185     NULL,                                  /* preconfiguration */
0186     ngx_http_log_init,                     /* postconfiguration */
0187 
0188     ngx_http_log_create_main_conf,         /* create main configuration */
0189     NULL,                                  /* init main configuration */
0190 
0191     NULL,                                  /* create server configuration */
0192     NULL,                                  /* merge server configuration */
0193 
0194     ngx_http_log_create_loc_conf,          /* create location configuration */
0195     ngx_http_log_merge_loc_conf            /* merge location configuration */
0196 };
0197 
0198 
0199 ngx_module_t  ngx_http_log_module = {
0200     NGX_MODULE_V1,
0201     &ngx_http_log_module_ctx,              /* module context */
0202     ngx_http_log_commands,                 /* module directives */
0203     NGX_HTTP_MODULE,                       /* module type */
0204     NULL,                                  /* init master */
0205     NULL,                                  /* init module */
0206     NULL,                                  /* init process */
0207     NULL,                                  /* init thread */
0208     NULL,                                  /* exit thread */
0209     NULL,                                  /* exit process */
0210     NULL,                                  /* exit master */
0211     NGX_MODULE_V1_PADDING
0212 };
0213 
0214 
0215 static ngx_str_t  ngx_http_access_log = ngx_string(NGX_HTTP_LOG_PATH);
0216 
0217 
0218 static ngx_str_t  ngx_http_combined_fmt =
0219     ngx_string("$remote_addr - $remote_user [$time_local] "
0220                "\"$request\" $status $body_bytes_sent "
0221                "\"$http_referer\" \"$http_user_agent\"");
0222 
0223 
0224 static ngx_http_log_var_t  ngx_http_log_vars[] = {
0225     { ngx_string("pipe"), 1, ngx_http_log_pipe },
0226     { ngx_string("time_local"), sizeof("28/Sep/1970:12:00:00 +0600") - 1,
0227                           ngx_http_log_time },
0228     { ngx_string("time_iso8601"), sizeof("1970-09-28T12:00:00+06:00") - 1,
0229                           ngx_http_log_iso8601 },
0230     { ngx_string("msec"), NGX_TIME_T_LEN + 4, ngx_http_log_msec },
0231     { ngx_string("request_time"), NGX_TIME_T_LEN + 4,
0232                           ngx_http_log_request_time },
0233     { ngx_string("status"), NGX_INT_T_LEN, ngx_http_log_status },
0234     { ngx_string("bytes_sent"), NGX_OFF_T_LEN, ngx_http_log_bytes_sent },
0235     { ngx_string("body_bytes_sent"), NGX_OFF_T_LEN,
0236                           ngx_http_log_body_bytes_sent },
0237     { ngx_string("request_length"), NGX_SIZE_T_LEN,
0238                           ngx_http_log_request_length },
0239 
0240     { ngx_null_string, 0, NULL }
0241 };
0242 
0243 
0244 static ngx_int_t
0245 ngx_http_log_handler(ngx_http_request_t *r)
0246 {
0247     u_char                   *line, *p;
0248     size_t                    len, size;
0249     ssize_t                   n;
0250     ngx_str_t                 val;
0251     ngx_uint_t                i, l;
0252     ngx_http_log_t           *log;
0253     ngx_http_log_op_t        *op;
0254     ngx_http_log_buf_t       *buffer;
0255     ngx_http_log_loc_conf_t  *lcf;
0256 
0257     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0258                    "http log handler");
0259 
0260     lcf = ngx_http_get_module_loc_conf(r, ngx_http_log_module);
0261 
0262     if (lcf->off) {
0263         return NGX_OK;
0264     }
0265 
0266     log = lcf->logs->elts;
0267     for (l = 0; l < lcf->logs->nelts; l++) {
0268 
0269         if (log[l].filter) {
0270             if (ngx_http_complex_value(r, log[l].filter, &val) != NGX_OK) {
0271                 return NGX_ERROR;
0272             }
0273 
0274             if (val.len == 0 || (val.len == 1 && val.data[0] == '0')) {
0275                 continue;
0276             }
0277         }
0278 
0279         if (ngx_time() == log[l].disk_full_time) {
0280 
0281             /*
0282              * on FreeBSD writing to a full filesystem with enabled softupdates
0283              * may block process for much longer time than writing to non-full
0284              * filesystem, so we skip writing to a log for one second
0285              */
0286 
0287             continue;
0288         }
0289 
0290         ngx_http_script_flush_no_cacheable_variables(r, log[l].format->flushes);
0291 
0292         len = 0;
0293         op = log[l].format->ops->elts;
0294         for (i = 0; i < log[l].format->ops->nelts; i++) {
0295             if (op[i].len == 0) {
0296                 len += op[i].getlen(r, op[i].data);
0297 
0298             } else {
0299                 len += op[i].len;
0300             }
0301         }
0302 
0303         if (log[l].syslog_peer) {
0304 
0305             /* length of syslog's PRI and HEADER message parts */
0306             len += sizeof("<255>Jan 01 00:00:00 ") - 1
0307                    + ngx_cycle->hostname.len + 1
0308                    + log[l].syslog_peer->tag.len + 2;
0309 
0310             goto alloc_line;
0311         }
0312 
0313         len += NGX_LINEFEED_SIZE;
0314 
0315         buffer = log[l].file ? log[l].file->data : NULL;
0316 
0317         if (buffer) {
0318 
0319             if (len > (size_t) (buffer->last - buffer->pos)) {
0320 
0321                 ngx_http_log_write(r, &log[l], buffer->start,
0322                                    buffer->pos - buffer->start);
0323 
0324                 buffer->pos = buffer->start;
0325             }
0326 
0327             if (len <= (size_t) (buffer->last - buffer->pos)) {
0328 
0329                 p = buffer->pos;
0330 
0331                 if (buffer->event && p == buffer->start) {
0332                     ngx_add_timer(buffer->event, buffer->flush);
0333                 }
0334 
0335                 for (i = 0; i < log[l].format->ops->nelts; i++) {
0336                     p = op[i].run(r, p, &op[i]);
0337                 }
0338 
0339                 ngx_linefeed(p);
0340 
0341                 buffer->pos = p;
0342 
0343                 continue;
0344             }
0345 
0346             if (buffer->event && buffer->event->timer_set) {
0347                 ngx_del_timer(buffer->event);
0348             }
0349         }
0350 
0351     alloc_line:
0352 
0353         line = ngx_pnalloc(r->pool, len);
0354         if (line == NULL) {
0355             return NGX_ERROR;
0356         }
0357 
0358         p = line;
0359 
0360         if (log[l].syslog_peer) {
0361             p = ngx_syslog_add_header(log[l].syslog_peer, line);
0362         }
0363 
0364         for (i = 0; i < log[l].format->ops->nelts; i++) {
0365             p = op[i].run(r, p, &op[i]);
0366         }
0367 
0368         if (log[l].syslog_peer) {
0369 
0370             size = p - line;
0371 
0372             n = ngx_syslog_send(log[l].syslog_peer, line, size);
0373 
0374             if (n < 0) {
0375                 ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
0376                               "send() to syslog failed");
0377 
0378             } else if ((size_t) n != size) {
0379                 ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
0380                               "send() to syslog has written only %z of %uz",
0381                               n, size);
0382             }
0383 
0384             continue;
0385         }
0386 
0387         ngx_linefeed(p);
0388 
0389         ngx_http_log_write(r, &log[l], line, p - line);
0390     }
0391 
0392     return NGX_OK;
0393 }
0394 
0395 
0396 static void
0397 ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log, u_char *buf,
0398     size_t len)
0399 {
0400     u_char              *name;
0401     time_t               now;
0402     ssize_t              n;
0403     ngx_err_t            err;
0404 #if (NGX_ZLIB)
0405     ngx_http_log_buf_t  *buffer;
0406 #endif
0407 
0408     if (log->script == NULL) {
0409         name = log->file->name.data;
0410 
0411 #if (NGX_ZLIB)
0412         buffer = log->file->data;
0413 
0414         if (buffer && buffer->gzip) {
0415             n = ngx_http_log_gzip(log->file->fd, buf, len, buffer->gzip,
0416                                   r->connection->log);
0417         } else {
0418             n = ngx_write_fd(log->file->fd, buf, len);
0419         }
0420 #else
0421         n = ngx_write_fd(log->file->fd, buf, len);
0422 #endif
0423 
0424     } else {
0425         name = NULL;
0426         n = ngx_http_log_script_write(r, log->script, &name, buf, len);
0427     }
0428 
0429     if (n == (ssize_t) len) {
0430         return;
0431     }
0432 
0433     now = ngx_time();
0434 
0435     if (n == -1) {
0436         err = ngx_errno;
0437 
0438         if (err == NGX_ENOSPC) {
0439             log->disk_full_time = now;
0440         }
0441 
0442         if (now - log->error_log_time > 59) {
0443             ngx_log_error(NGX_LOG_ALERT, r->connection->log, err,
0444                           ngx_write_fd_n " to \"%s\" failed", name);
0445 
0446             log->error_log_time = now;
0447         }
0448 
0449         return;
0450     }
0451 
0452     if (now - log->error_log_time > 59) {
0453         ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
0454                       ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz",
0455                       name, n, len);
0456 
0457         log->error_log_time = now;
0458     }
0459 }
0460 
0461 
0462 static ssize_t
0463 ngx_http_log_script_write(ngx_http_request_t *r, ngx_http_log_script_t *script,
0464     u_char **name, u_char *buf, size_t len)
0465 {
0466     size_t                     root;
0467     ssize_t                    n;
0468     ngx_str_t                  log, path;
0469     ngx_open_file_info_t       of;
0470     ngx_http_log_loc_conf_t   *llcf;
0471     ngx_http_core_loc_conf_t  *clcf;
0472 
0473     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
0474 
0475     if (!r->root_tested) {
0476 
0477         /* test root directory existence */
0478 
0479         if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) {
0480             /* simulate successful logging */
0481             return len;
0482         }
0483 
0484         path.data[root] = '\0';
0485 
0486         ngx_memzero(&of, sizeof(ngx_open_file_info_t));
0487 
0488         of.valid = clcf->open_file_cache_valid;
0489         of.min_uses = clcf->open_file_cache_min_uses;
0490         of.test_dir = 1;
0491         of.test_only = 1;
0492         of.errors = clcf->open_file_cache_errors;
0493         of.events = clcf->open_file_cache_events;
0494 
0495         if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) {
0496             /* simulate successful logging */
0497             return len;
0498         }
0499 
0500         if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
0501             != NGX_OK)
0502         {
0503             if (of.err == 0) {
0504                 /* simulate successful logging */
0505                 return len;
0506             }
0507 
0508             ngx_log_error(NGX_LOG_ERR, r->connection->log, of.err,
0509                           "testing \"%s\" existence failed", path.data);
0510 
0511             /* simulate successful logging */
0512             return len;
0513         }
0514 
0515         if (!of.is_dir) {
0516             ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_ENOTDIR,
0517                           "testing \"%s\" existence failed", path.data);
0518 
0519             /* simulate successful logging */
0520             return len;
0521         }
0522     }
0523 
0524     if (ngx_http_script_run(r, &log, script->lengths->elts, 1,
0525                             script->values->elts)
0526         == NULL)
0527     {
0528         /* simulate successful logging */
0529         return len;
0530     }
0531 
0532     log.data[log.len - 1] = '\0';
0533     *name = log.data;
0534 
0535     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0536                    "http log \"%s\"", log.data);
0537 
0538     llcf = ngx_http_get_module_loc_conf(r, ngx_http_log_module);
0539 
0540     ngx_memzero(&of, sizeof(ngx_open_file_info_t));
0541 
0542     of.log = 1;
0543     of.valid = llcf->open_file_cache_valid;
0544     of.min_uses = llcf->open_file_cache_min_uses;
0545     of.directio = NGX_OPEN_FILE_DIRECTIO_OFF;
0546 
0547     if (ngx_http_set_disable_symlinks(r, clcf, &log, &of) != NGX_OK) {
0548         /* simulate successful logging */
0549         return len;
0550     }
0551 
0552     if (ngx_open_cached_file(llcf->open_file_cache, &log, &of, r->pool)
0553         != NGX_OK)
0554     {
0555         if (of.err == 0) {
0556             /* simulate successful logging */
0557             return len;
0558         }
0559 
0560         ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
0561                       "%s \"%s\" failed", of.failed, log.data);
0562         /* simulate successful logging */
0563         return len;
0564     }
0565 
0566     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0567                    "http log #%d", of.fd);
0568 
0569     n = ngx_write_fd(of.fd, buf, len);
0570 
0571     return n;
0572 }
0573 
0574 
0575 #if (NGX_ZLIB)
0576 
0577 static ssize_t
0578 ngx_http_log_gzip(ngx_fd_t fd, u_char *buf, size_t len, ngx_int_t level,
0579     ngx_log_t *log)
0580 {
0581     int          rc, wbits, memlevel;
0582     u_char      *out;
0583     size_t       size;
0584     ssize_t      n;
0585     z_stream     zstream;
0586     ngx_err_t    err;
0587     ngx_pool_t  *pool;
0588 
0589     wbits = MAX_WBITS;
0590     memlevel = MAX_MEM_LEVEL - 1;
0591 
0592     while ((ssize_t) len < ((1 << (wbits - 1)) - 262)) {
0593         wbits--;
0594         memlevel--;
0595     }
0596 
0597     /*
0598      * This is a formula from deflateBound() for conservative upper bound of
0599      * compressed data plus 18 bytes of gzip wrapper.
0600      */
0601 
0602     size = len + ((len + 7) >> 3) + ((len + 63) >> 6) + 5 + 18;
0603 
0604     ngx_memzero(&zstream, sizeof(z_stream));
0605 
0606     pool = ngx_create_pool(256, log);
0607     if (pool == NULL) {
0608         /* simulate successful logging */
0609         return len;
0610     }
0611 
0612     pool->log = log;
0613 
0614     zstream.zalloc = ngx_http_log_gzip_alloc;
0615     zstream.zfree = ngx_http_log_gzip_free;
0616     zstream.opaque = pool;
0617 
0618     out = ngx_pnalloc(pool, size);
0619     if (out == NULL) {
0620         goto done;
0621     }
0622 
0623     zstream.next_in = buf;
0624     zstream.avail_in = len;
0625     zstream.next_out = out;
0626     zstream.avail_out = size;
0627 
0628     rc = deflateInit2(&zstream, (int) level, Z_DEFLATED, wbits + 16, memlevel,
0629                       Z_DEFAULT_STRATEGY);
0630 
0631     if (rc != Z_OK) {
0632         ngx_log_error(NGX_LOG_ALERT, log, 0, "deflateInit2() failed: %d", rc);
0633         goto done;
0634     }
0635 
0636     ngx_log_debug4(NGX_LOG_DEBUG_HTTP, log, 0,
0637                    "deflate in: ni:%p no:%p ai:%ud ao:%ud",
0638                    zstream.next_in, zstream.next_out,
0639                    zstream.avail_in, zstream.avail_out);
0640 
0641     rc = deflate(&zstream, Z_FINISH);
0642 
0643     if (rc != Z_STREAM_END) {
0644         ngx_log_error(NGX_LOG_ALERT, log, 0,
0645                       "deflate(Z_FINISH) failed: %d", rc);
0646         goto done;
0647     }
0648 
0649     ngx_log_debug5(NGX_LOG_DEBUG_HTTP, log, 0,
0650                    "deflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d",
0651                    zstream.next_in, zstream.next_out,
0652                    zstream.avail_in, zstream.avail_out,
0653                    rc);
0654 
0655     size -= zstream.avail_out;
0656 
0657     rc = deflateEnd(&zstream);
0658 
0659     if (rc != Z_OK) {
0660         ngx_log_error(NGX_LOG_ALERT, log, 0, "deflateEnd() failed: %d", rc);
0661         goto done;
0662     }
0663 
0664     n = ngx_write_fd(fd, out, size);
0665 
0666     if (n != (ssize_t) size) {
0667         err = (n == -1) ? ngx_errno : 0;
0668 
0669         ngx_destroy_pool(pool);
0670 
0671         ngx_set_errno(err);
0672         return -1;
0673     }
0674 
0675 done:
0676 
0677     ngx_destroy_pool(pool);
0678 
0679     /* simulate successful logging */
0680     return len;
0681 }
0682 
0683 
0684 static void *
0685 ngx_http_log_gzip_alloc(void *opaque, u_int items, u_int size)
0686 {
0687     ngx_pool_t *pool = opaque;
0688 
0689     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pool->log, 0,
0690                    "gzip alloc: n:%ud s:%ud", items, size);
0691 
0692     return ngx_palloc(pool, items * size);
0693 }
0694 
0695 
0696 static void
0697 ngx_http_log_gzip_free(void *opaque, void *address)
0698 {
0699 #if 0
0700     ngx_pool_t *pool = opaque;
0701 
0702     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pool->log, 0, "gzip free: %p", address);
0703 #endif
0704 }
0705 
0706 #endif
0707 
0708 
0709 static void
0710 ngx_http_log_flush(ngx_open_file_t *file, ngx_log_t *log)
0711 {
0712     size_t               len;
0713     ssize_t              n;
0714     ngx_http_log_buf_t  *buffer;
0715 
0716     buffer = file->data;
0717 
0718     len = buffer->pos - buffer->start;
0719 
0720     if (len == 0) {
0721         return;
0722     }
0723 
0724 #if (NGX_ZLIB)
0725     if (buffer->gzip) {
0726         n = ngx_http_log_gzip(file->fd, buffer->start, len, buffer->gzip, log);
0727     } else {
0728         n = ngx_write_fd(file->fd, buffer->start, len);
0729     }
0730 #else
0731     n = ngx_write_fd(file->fd, buffer->start, len);
0732 #endif
0733 
0734     if (n == -1) {
0735         ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
0736                       ngx_write_fd_n " to \"%s\" failed",
0737                       file->name.data);
0738 
0739     } else if ((size_t) n != len) {
0740         ngx_log_error(NGX_LOG_ALERT, log, 0,
0741                       ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz",
0742                       file->name.data, n, len);
0743     }
0744 
0745     buffer->pos = buffer->start;
0746 
0747     if (buffer->event && buffer->event->timer_set) {
0748         ngx_del_timer(buffer->event);
0749     }
0750 }
0751 
0752 
0753 static void
0754 ngx_http_log_flush_handler(ngx_event_t *ev)
0755 {
0756     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0,
0757                    "http log buffer flush handler");
0758 
0759     ngx_http_log_flush(ev->data, ev->log);
0760 }
0761 
0762 
0763 static u_char *
0764 ngx_http_log_copy_short(ngx_http_request_t *r, u_char *buf,
0765     ngx_http_log_op_t *op)
0766 {
0767     size_t     len;
0768     uintptr_t  data;
0769 
0770     len = op->len;
0771     data = op->data;
0772 
0773     while (len--) {
0774         *buf++ = (u_char) (data & 0xff);
0775         data >>= 8;
0776     }
0777 
0778     return buf;
0779 }
0780 
0781 
0782 static u_char *
0783 ngx_http_log_copy_long(ngx_http_request_t *r, u_char *buf,
0784     ngx_http_log_op_t *op)
0785 {
0786     return ngx_cpymem(buf, (u_char *) op->data, op->len);
0787 }
0788 
0789 
0790 static u_char *
0791 ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
0792 {
0793     if (r->pipeline) {
0794         *buf = 'p';
0795     } else {
0796         *buf = '.';
0797     }
0798 
0799     return buf + 1;
0800 }
0801 
0802 
0803 static u_char *
0804 ngx_http_log_time(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
0805 {
0806     return ngx_cpymem(buf, ngx_cached_http_log_time.data,
0807                       ngx_cached_http_log_time.len);
0808 }
0809 
0810 static u_char *
0811 ngx_http_log_iso8601(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
0812 {
0813     return ngx_cpymem(buf, ngx_cached_http_log_iso8601.data,
0814                       ngx_cached_http_log_iso8601.len);
0815 }
0816 
0817 static u_char *
0818 ngx_http_log_msec(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
0819 {
0820     ngx_time_t  *tp;
0821 
0822     tp = ngx_timeofday();
0823 
0824     return ngx_sprintf(buf, "%T.%03M", tp->sec, tp->msec);
0825 }
0826 
0827 
0828 static u_char *
0829 ngx_http_log_request_time(ngx_http_request_t *r, u_char *buf,
0830     ngx_http_log_op_t *op)
0831 {
0832     ngx_time_t      *tp;
0833     ngx_msec_int_t   ms;
0834 
0835     tp = ngx_timeofday();
0836 
0837     ms = (ngx_msec_int_t)
0838              ((tp->sec - r->start_sec) * 1000 + (tp->msec - r->start_msec));
0839     ms = ngx_max(ms, 0);
0840 
0841     return ngx_sprintf(buf, "%T.%03M", (time_t) ms / 1000, ms % 1000);
0842 }
0843 
0844 
0845 static u_char *
0846 ngx_http_log_status(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
0847 {
0848     ngx_uint_t  status;
0849 
0850     if (r->err_status) {
0851         status = r->err_status;
0852 
0853     } else if (r->headers_out.status) {
0854         status = r->headers_out.status;
0855 
0856     } else if (r->http_version == NGX_HTTP_VERSION_9) {
0857         status = 9;
0858 
0859     } else {
0860         status = 0;
0861     }
0862 
0863     return ngx_sprintf(buf, "%03ui", status);
0864 }
0865 
0866 
0867 static u_char *
0868 ngx_http_log_bytes_sent(ngx_http_request_t *r, u_char *buf,
0869     ngx_http_log_op_t *op)
0870 {
0871     return ngx_sprintf(buf, "%O", r->connection->sent);
0872 }
0873 
0874 
0875 /*
0876  * although there is a real $body_bytes_sent variable,
0877  * this log operation code function is more optimized for logging
0878  */
0879 
0880 static u_char *
0881 ngx_http_log_body_bytes_sent(ngx_http_request_t *r, u_char *buf,
0882     ngx_http_log_op_t *op)
0883 {
0884     off_t  length;
0885 
0886     length = r->connection->sent - r->header_size;
0887 
0888     if (length > 0) {
0889         return ngx_sprintf(buf, "%O", length);
0890     }
0891 
0892     *buf = '0';
0893 
0894     return buf + 1;
0895 }
0896 
0897 
0898 static u_char *
0899 ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf,
0900     ngx_http_log_op_t *op)
0901 {
0902     return ngx_sprintf(buf, "%O", r->request_length);
0903 }
0904 
0905 
0906 static ngx_int_t
0907 ngx_http_log_variable_compile(ngx_conf_t *cf, ngx_http_log_op_t *op,
0908     ngx_str_t *value, ngx_uint_t json)
0909 {
0910     ngx_int_t  index;
0911 
0912     index = ngx_http_get_variable_index(cf, value);
0913     if (index == NGX_ERROR) {
0914         return NGX_ERROR;
0915     }
0916 
0917     op->len = 0;
0918 
0919     if (json) {
0920         op->getlen = ngx_http_log_json_variable_getlen;
0921         op->run = ngx_http_log_json_variable;
0922 
0923     } else {
0924         op->getlen = ngx_http_log_variable_getlen;
0925         op->run = ngx_http_log_variable;
0926     }
0927 
0928     op->data = index;
0929 
0930     return NGX_OK;
0931 }
0932 
0933 
0934 static size_t
0935 ngx_http_log_variable_getlen(ngx_http_request_t *r, uintptr_t data)
0936 {
0937     uintptr_t                   len;
0938     ngx_http_variable_value_t  *value;
0939 
0940     value = ngx_http_get_indexed_variable(r, data);
0941 
0942     if (value == NULL || value->not_found) {
0943         return 1;
0944     }
0945 
0946     len = ngx_http_log_escape(NULL, value->data, value->len);
0947 
0948     value->escape = len ? 1 : 0;
0949 
0950     return value->len + len * 3;
0951 }
0952 
0953 
0954 static u_char *
0955 ngx_http_log_variable(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
0956 {
0957     ngx_http_variable_value_t  *value;
0958 
0959     value = ngx_http_get_indexed_variable(r, op->data);
0960 
0961     if (value == NULL || value->not_found) {
0962         *buf = '-';
0963         return buf + 1;
0964     }
0965 
0966     if (value->escape == 0) {
0967         return ngx_cpymem(buf, value->data, value->len);
0968 
0969     } else {
0970         return (u_char *) ngx_http_log_escape(buf, value->data, value->len);
0971     }
0972 }
0973 
0974 
0975 static uintptr_t
0976 ngx_http_log_escape(u_char *dst, u_char *src, size_t size)
0977 {
0978     ngx_uint_t      n;
0979     static u_char   hex[] = "0123456789ABCDEF";
0980 
0981     static uint32_t   escape[] = {
0982         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
0983 
0984                     /* ?>=< ;:98 7654 3210  /.-, +*)( '&%$ #"!  */
0985         0x00000004, /* 0000 0000 0000 0000  0000 0000 0000 0100 */
0986 
0987                     /* _^]\ [ZYX WVUT SRQP  ONML KJIH GFED CBA@ */
0988         0x10000000, /* 0001 0000 0000 0000  0000 0000 0000 0000 */
0989 
0990                     /*  ~}| {zyx wvut srqp  onml kjih gfed cba` */
0991         0x80000000, /* 1000 0000 0000 0000  0000 0000 0000 0000 */
0992 
0993         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
0994         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
0995         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
0996         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
0997     };
0998 
0999 
1000     if (dst == NULL) {
1001 
1002         /* find the number of the characters to be escaped */
1003 
1004         n = 0;
1005 
1006         while (size) {
1007             if (escape[*src >> 5] & (1U << (*src & 0x1f))) {
1008                 n++;
1009             }
1010             src++;
1011             size--;
1012         }
1013 
1014         return (uintptr_t) n;
1015     }
1016 
1017     while (size) {
1018         if (escape[*src >> 5] & (1U << (*src & 0x1f))) {
1019             *dst++ = '\\';
1020             *dst++ = 'x';
1021             *dst++ = hex[*src >> 4];
1022             *dst++ = hex[*src & 0xf];
1023             src++;
1024 
1025         } else {
1026             *dst++ = *src++;
1027         }
1028         size--;
1029     }
1030 
1031     return (uintptr_t) dst;
1032 }
1033 
1034 
1035 static size_t
1036 ngx_http_log_json_variable_getlen(ngx_http_request_t *r, uintptr_t data)
1037 {
1038     uintptr_t                   len;
1039     ngx_http_variable_value_t  *value;
1040 
1041     value = ngx_http_get_indexed_variable(r, data);
1042 
1043     if (value == NULL || value->not_found) {
1044         return 0;
1045     }
1046 
1047     len = ngx_escape_json(NULL, value->data, value->len);
1048 
1049     value->escape = len ? 1 : 0;
1050 
1051     return value->len + len;
1052 }
1053 
1054 
1055 static u_char *
1056 ngx_http_log_json_variable(ngx_http_request_t *r, u_char *buf,
1057     ngx_http_log_op_t *op)
1058 {
1059     ngx_http_variable_value_t  *value;
1060 
1061     value = ngx_http_get_indexed_variable(r, op->data);
1062 
1063     if (value == NULL || value->not_found) {
1064         return buf;
1065     }
1066 
1067     if (value->escape == 0) {
1068         return ngx_cpymem(buf, value->data, value->len);
1069 
1070     } else {
1071         return (u_char *) ngx_escape_json(buf, value->data, value->len);
1072     }
1073 }
1074 
1075 
1076 static void *
1077 ngx_http_log_create_main_conf(ngx_conf_t *cf)
1078 {
1079     ngx_http_log_main_conf_t  *conf;
1080 
1081     ngx_http_log_fmt_t  *fmt;
1082 
1083     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_main_conf_t));
1084     if (conf == NULL) {
1085         return NULL;
1086     }
1087 
1088     if (ngx_array_init(&conf->formats, cf->pool, 4, sizeof(ngx_http_log_fmt_t))
1089         != NGX_OK)
1090     {
1091         return NULL;
1092     }
1093 
1094     fmt = ngx_array_push(&conf->formats);
1095     if (fmt == NULL) {
1096         return NULL;
1097     }
1098 
1099     ngx_str_set(&fmt->name, "combined");
1100 
1101     fmt->flushes = NULL;
1102 
1103     fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_http_log_op_t));
1104     if (fmt->ops == NULL) {
1105         return NULL;
1106     }
1107 
1108     return conf;
1109 }
1110 
1111 
1112 static void *
1113 ngx_http_log_create_loc_conf(ngx_conf_t *cf)
1114 {
1115     ngx_http_log_loc_conf_t  *conf;
1116 
1117     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_loc_conf_t));
1118     if (conf == NULL) {
1119         return NULL;
1120     }
1121 
1122     conf->open_file_cache = NGX_CONF_UNSET_PTR;
1123 
1124     return conf;
1125 }
1126 
1127 
1128 static char *
1129 ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
1130 {
1131     ngx_http_log_loc_conf_t *prev = parent;
1132     ngx_http_log_loc_conf_t *conf = child;
1133 
1134     ngx_http_log_t            *log;
1135     ngx_http_log_fmt_t        *fmt;
1136     ngx_http_log_main_conf_t  *lmcf;
1137 
1138     if (conf->open_file_cache == NGX_CONF_UNSET_PTR) {
1139 
1140         conf->open_file_cache = prev->open_file_cache;
1141         conf->open_file_cache_valid = prev->open_file_cache_valid;
1142         conf->open_file_cache_min_uses = prev->open_file_cache_min_uses;
1143 
1144         if (conf->open_file_cache == NGX_CONF_UNSET_PTR) {
1145             conf->open_file_cache = NULL;
1146         }
1147     }
1148 
1149     if (conf->logs || conf->off) {
1150         return NGX_CONF_OK;
1151     }
1152 
1153     conf->logs = prev->logs;
1154     conf->off = prev->off;
1155 
1156     if (conf->logs || conf->off) {
1157         return NGX_CONF_OK;
1158     }
1159 
1160     conf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_http_log_t));
1161     if (conf->logs == NULL) {
1162         return NGX_CONF_ERROR;
1163     }
1164 
1165     log = ngx_array_push(conf->logs);
1166     if (log == NULL) {
1167         return NGX_CONF_ERROR;
1168     }
1169 
1170     ngx_memzero(log, sizeof(ngx_http_log_t));
1171 
1172     log->file = ngx_conf_open_file(cf->cycle, &ngx_http_access_log);
1173     if (log->file == NULL) {
1174         return NGX_CONF_ERROR;
1175     }
1176 
1177     lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);
1178     fmt = lmcf->formats.elts;
1179 
1180     /* the default "combined" format */
1181     log->format = &fmt[0];
1182     lmcf->combined_used = 1;
1183 
1184     return NGX_CONF_OK;
1185 }
1186 
1187 
1188 static char *
1189 ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1190 {
1191     ngx_http_log_loc_conf_t *llcf = conf;
1192 
1193     ssize_t                            size;
1194     ngx_int_t                          gzip;
1195     ngx_uint_t                         i, n;
1196     ngx_msec_t                         flush;
1197     ngx_str_t                         *value, name, s;
1198     ngx_http_log_t                    *log;
1199     ngx_syslog_peer_t                 *peer;
1200     ngx_http_log_buf_t                *buffer;
1201     ngx_http_log_fmt_t                *fmt;
1202     ngx_http_log_main_conf_t          *lmcf;
1203     ngx_http_script_compile_t          sc;
1204     ngx_http_compile_complex_value_t   ccv;
1205 
1206     value = cf->args->elts;
1207 
1208     if (ngx_strcmp(value[1].data, "off") == 0) {
1209         llcf->off = 1;
1210         if (cf->args->nelts == 2) {
1211             return NGX_CONF_OK;
1212         }
1213 
1214         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1215                            "invalid parameter \"%V\"", &value[2]);
1216         return NGX_CONF_ERROR;
1217     }
1218 
1219     if (llcf->logs == NULL) {
1220         llcf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_http_log_t));
1221         if (llcf->logs == NULL) {
1222             return NGX_CONF_ERROR;
1223         }
1224     }
1225 
1226     lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);
1227 
1228     log = ngx_array_push(llcf->logs);
1229     if (log == NULL) {
1230         return NGX_CONF_ERROR;
1231     }
1232 
1233     ngx_memzero(log, sizeof(ngx_http_log_t));
1234 
1235 
1236     if (ngx_strncmp(value[1].data, "syslog:", 7) == 0) {
1237 
1238         peer = ngx_pcalloc(cf->pool, sizeof(ngx_syslog_peer_t));
1239         if (peer == NULL) {
1240             return NGX_CONF_ERROR;
1241         }
1242 
1243         if (ngx_syslog_process_conf(cf, peer) != NGX_CONF_OK) {
1244             return NGX_CONF_ERROR;
1245         }
1246 
1247         log->syslog_peer = peer;
1248 
1249         goto process_formats;
1250     }
1251 
1252     n = ngx_http_script_variables_count(&value[1]);
1253 
1254     if (n == 0) {
1255         log->file = ngx_conf_open_file(cf->cycle, &value[1]);
1256         if (log->file == NULL) {
1257             return NGX_CONF_ERROR;
1258         }
1259 
1260     } else {
1261         if (ngx_conf_full_name(cf->cycle, &value[1], 0) != NGX_OK) {
1262             return NGX_CONF_ERROR;
1263         }
1264 
1265         log->script = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_script_t));
1266         if (log->script == NULL) {
1267             return NGX_CONF_ERROR;
1268         }
1269 
1270         ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
1271 
1272         sc.cf = cf;
1273         sc.source = &value[1];
1274         sc.lengths = &log->script->lengths;
1275         sc.values = &log->script->values;
1276         sc.variables = n;
1277         sc.complete_lengths = 1;
1278         sc.complete_values = 1;
1279 
1280         if (ngx_http_script_compile(&sc) != NGX_OK) {
1281             return NGX_CONF_ERROR;
1282         }
1283     }
1284 
1285 process_formats:
1286 
1287     if (cf->args->nelts >= 3) {
1288         name = value[2];
1289 
1290         if (ngx_strcmp(name.data, "combined") == 0) {
1291             lmcf->combined_used = 1;
1292         }
1293 
1294     } else {
1295         ngx_str_set(&name, "combined");
1296         lmcf->combined_used = 1;
1297     }
1298 
1299     fmt = lmcf->formats.elts;
1300     for (i = 0; i < lmcf->formats.nelts; i++) {
1301         if (fmt[i].name.len == name.len
1302             && ngx_strcasecmp(fmt[i].name.data, name.data) == 0)
1303         {
1304             log->format = &fmt[i];
1305             break;
1306         }
1307     }
1308 
1309     if (log->format == NULL) {
1310         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1311                            "unknown log format \"%V\"", &name);
1312         return NGX_CONF_ERROR;
1313     }
1314 
1315     size = 0;
1316     flush = 0;
1317     gzip = 0;
1318 
1319     for (i = 3; i < cf->args->nelts; i++) {
1320 
1321         if (ngx_strncmp(value[i].data, "buffer=", 7) == 0) {
1322             s.len = value[i].len - 7;
1323             s.data = value[i].data + 7;
1324 
1325             size = ngx_parse_size(&s);
1326 
1327             if (size == NGX_ERROR || size == 0) {
1328                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1329                                    "invalid buffer size \"%V\"", &s);
1330                 return NGX_CONF_ERROR;
1331             }
1332 
1333             continue;
1334         }
1335 
1336         if (ngx_strncmp(value[i].data, "flush=", 6) == 0) {
1337             s.len = value[i].len - 6;
1338             s.data = value[i].data + 6;
1339 
1340             flush = ngx_parse_time(&s, 0);
1341 
1342             if (flush == (ngx_msec_t) NGX_ERROR || flush == 0) {
1343                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1344                                    "invalid flush time \"%V\"", &s);
1345                 return NGX_CONF_ERROR;
1346             }
1347 
1348             continue;
1349         }
1350 
1351         if (ngx_strncmp(value[i].data, "gzip", 4) == 0
1352             && (value[i].len == 4 || value[i].data[4] == '='))
1353         {
1354 #if (NGX_ZLIB)
1355             if (size == 0) {
1356                 size = 64 * 1024;
1357             }
1358 
1359             if (value[i].len == 4) {
1360                 gzip = Z_BEST_SPEED;
1361                 continue;
1362             }
1363 
1364             s.len = value[i].len - 5;
1365             s.data = value[i].data + 5;
1366 
1367             gzip = ngx_atoi(s.data, s.len);
1368 
1369             if (gzip < 1 || gzip > 9) {
1370                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1371                                    "invalid compression level \"%V\"", &s);
1372                 return NGX_CONF_ERROR;
1373             }
1374 
1375             continue;
1376 
1377 #else
1378             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1379                                "nginx was built without zlib support");
1380             return NGX_CONF_ERROR;
1381 #endif
1382         }
1383 
1384         if (ngx_strncmp(value[i].data, "if=", 3) == 0) {
1385             s.len = value[i].len - 3;
1386             s.data = value[i].data + 3;
1387 
1388             ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
1389 
1390             ccv.cf = cf;
1391             ccv.value = &s;
1392             ccv.complex_value = ngx_palloc(cf->pool,
1393                                            sizeof(ngx_http_complex_value_t));
1394             if (ccv.complex_value == NULL) {
1395                 return NGX_CONF_ERROR;
1396             }
1397 
1398             if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
1399                 return NGX_CONF_ERROR;
1400             }
1401 
1402             log->filter = ccv.complex_value;
1403 
1404             continue;
1405         }
1406 
1407         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1408                            "invalid parameter \"%V\"", &value[i]);
1409         return NGX_CONF_ERROR;
1410     }
1411 
1412     if (flush && size == 0) {
1413         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1414                            "no buffer is defined for access_log \"%V\"",
1415                            &value[1]);
1416         return NGX_CONF_ERROR;
1417     }
1418 
1419     if (size) {
1420 
1421         if (log->script) {
1422             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1423                                "buffered logs cannot have variables in name");
1424             return NGX_CONF_ERROR;
1425         }
1426 
1427         if (log->syslog_peer) {
1428             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1429                                "logs to syslog cannot be buffered");
1430             return NGX_CONF_ERROR;
1431         }
1432 
1433         if (log->file->data) {
1434             buffer = log->file->data;
1435 
1436             if (buffer->last - buffer->start != size
1437                 || buffer->flush != flush
1438                 || buffer->gzip != gzip)
1439             {
1440                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1441                                    "access_log \"%V\" already defined "
1442                                    "with conflicting parameters",
1443                                    &value[1]);
1444                 return NGX_CONF_ERROR;
1445             }
1446 
1447             return NGX_CONF_OK;
1448         }
1449 
1450         buffer = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_buf_t));
1451         if (buffer == NULL) {
1452             return NGX_CONF_ERROR;
1453         }
1454 
1455         buffer->start = ngx_pnalloc(cf->pool, size);
1456         if (buffer->start == NULL) {
1457             return NGX_CONF_ERROR;
1458         }
1459 
1460         buffer->pos = buffer->start;
1461         buffer->last = buffer->start + size;
1462 
1463         if (flush) {
1464             buffer->event = ngx_pcalloc(cf->pool, sizeof(ngx_event_t));
1465             if (buffer->event == NULL) {
1466                 return NGX_CONF_ERROR;
1467             }
1468 
1469             buffer->event->data = log->file;
1470             buffer->event->handler = ngx_http_log_flush_handler;
1471             buffer->event->log = &cf->cycle->new_log;
1472             buffer->event->cancelable = 1;
1473 
1474             buffer->flush = flush;
1475         }
1476 
1477         buffer->gzip = gzip;
1478 
1479         log->file->flush = ngx_http_log_flush;
1480         log->file->data = buffer;
1481     }
1482 
1483     return NGX_CONF_OK;
1484 }
1485 
1486 
1487 static char *
1488 ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1489 {
1490     ngx_http_log_main_conf_t *lmcf = conf;
1491 
1492     ngx_str_t           *value;
1493     ngx_uint_t           i;
1494     ngx_http_log_fmt_t  *fmt;
1495 
1496     value = cf->args->elts;
1497 
1498     fmt = lmcf->formats.elts;
1499     for (i = 0; i < lmcf->formats.nelts; i++) {
1500         if (fmt[i].name.len == value[1].len
1501             && ngx_strcmp(fmt[i].name.data, value[1].data) == 0)
1502         {
1503             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1504                                "duplicate \"log_format\" name \"%V\"",
1505                                &value[1]);
1506             return NGX_CONF_ERROR;
1507         }
1508     }
1509 
1510     fmt = ngx_array_push(&lmcf->formats);
1511     if (fmt == NULL) {
1512         return NGX_CONF_ERROR;
1513     }
1514 
1515     fmt->name = value[1];
1516 
1517     fmt->flushes = ngx_array_create(cf->pool, 4, sizeof(ngx_int_t));
1518     if (fmt->flushes == NULL) {
1519         return NGX_CONF_ERROR;
1520     }
1521 
1522     fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_http_log_op_t));
1523     if (fmt->ops == NULL) {
1524         return NGX_CONF_ERROR;
1525     }
1526 
1527     return ngx_http_log_compile_format(cf, fmt->flushes, fmt->ops, cf->args, 2);
1528 }
1529 
1530 
1531 static char *
1532 ngx_http_log_compile_format(ngx_conf_t *cf, ngx_array_t *flushes,
1533     ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s)
1534 {
1535     u_char              *data, *p, ch;
1536     size_t               i, len;
1537     ngx_str_t           *value, var;
1538     ngx_int_t           *flush;
1539     ngx_uint_t           bracket, json;
1540     ngx_http_log_op_t   *op;
1541     ngx_http_log_var_t  *v;
1542 
1543     json = 0;
1544     value = args->elts;
1545 
1546     if (s < args->nelts && ngx_strncmp(value[s].data, "escape=", 7) == 0) {
1547         data = value[s].data + 7;
1548 
1549         if (ngx_strcmp(data, "json") == 0) {
1550             json = 1;
1551 
1552         } else if (ngx_strcmp(data, "default") != 0) {
1553             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1554                                "unknown log format escaping \"%s\"", data);
1555             return NGX_CONF_ERROR;
1556         }
1557 
1558         s++;
1559     }
1560 
1561     for ( /* void */ ; s < args->nelts; s++) {
1562 
1563         i = 0;
1564 
1565         while (i < value[s].len) {
1566 
1567             op = ngx_array_push(ops);
1568             if (op == NULL) {
1569                 return NGX_CONF_ERROR;
1570             }
1571 
1572             data = &value[s].data[i];
1573 
1574             if (value[s].data[i] == '$') {
1575 
1576                 if (++i == value[s].len) {
1577                     goto invalid;
1578                 }
1579 
1580                 if (value[s].data[i] == '{') {
1581                     bracket = 1;
1582 
1583                     if (++i == value[s].len) {
1584                         goto invalid;
1585                     }
1586 
1587                     var.data = &value[s].data[i];
1588 
1589                 } else {
1590                     bracket = 0;
1591                     var.data = &value[s].data[i];
1592                 }
1593 
1594                 for (var.len = 0; i < value[s].len; i++, var.len++) {
1595                     ch = value[s].data[i];
1596 
1597                     if (ch == '}' && bracket) {
1598                         i++;
1599                         bracket = 0;
1600                         break;
1601                     }
1602 
1603                     if ((ch >= 'A' && ch <= 'Z')
1604                         || (ch >= 'a' && ch <= 'z')
1605                         || (ch >= '0' && ch <= '9')
1606                         || ch == '_')
1607                     {
1608                         continue;
1609                     }
1610 
1611                     break;
1612                 }
1613 
1614                 if (bracket) {
1615                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1616                                        "the closing bracket in \"%V\" "
1617                                        "variable is missing", &var);
1618                     return NGX_CONF_ERROR;
1619                 }
1620 
1621                 if (var.len == 0) {
1622                     goto invalid;
1623                 }
1624 
1625                 for (v = ngx_http_log_vars; v->name.len; v++) {
1626 
1627                     if (v->name.len == var.len
1628                         && ngx_strncmp(v->name.data, var.data, var.len) == 0)
1629                     {
1630                         op->len = v->len;
1631                         op->getlen = NULL;
1632                         op->run = v->run;
1633                         op->data = 0;
1634 
1635                         goto found;
1636                     }
1637                 }
1638 
1639                 if (ngx_http_log_variable_compile(cf, op, &var, json)
1640                     != NGX_OK)
1641                 {
1642                     return NGX_CONF_ERROR;
1643                 }
1644 
1645                 if (flushes) {
1646 
1647                     flush = ngx_array_push(flushes);
1648                     if (flush == NULL) {
1649                         return NGX_CONF_ERROR;
1650                     }
1651 
1652                     *flush = op->data; /* variable index */
1653                 }
1654 
1655             found:
1656 
1657                 continue;
1658             }
1659 
1660             i++;
1661 
1662             while (i < value[s].len && value[s].data[i] != '$') {
1663                 i++;
1664             }
1665 
1666             len = &value[s].data[i] - data;
1667 
1668             if (len) {
1669 
1670                 op->len = len;
1671                 op->getlen = NULL;
1672 
1673                 if (len <= sizeof(uintptr_t)) {
1674                     op->run = ngx_http_log_copy_short;
1675                     op->data = 0;
1676 
1677                     while (len--) {
1678                         op->data <<= 8;
1679                         op->data |= data[len];
1680                     }
1681 
1682                 } else {
1683                     op->run = ngx_http_log_copy_long;
1684 
1685                     p = ngx_pnalloc(cf->pool, len);
1686                     if (p == NULL) {
1687                         return NGX_CONF_ERROR;
1688                     }
1689 
1690                     ngx_memcpy(p, data, len);
1691                     op->data = (uintptr_t) p;
1692                 }
1693             }
1694         }
1695     }
1696 
1697     return NGX_CONF_OK;
1698 
1699 invalid:
1700 
1701     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%s\"", data);
1702 
1703     return NGX_CONF_ERROR;
1704 }
1705 
1706 
1707 static char *
1708 ngx_http_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1709 {
1710     ngx_http_log_loc_conf_t *llcf = conf;
1711 
1712     time_t       inactive, valid;
1713     ngx_str_t   *value, s;
1714     ngx_int_t    max, min_uses;
1715     ngx_uint_t   i;
1716 
1717     if (llcf->open_file_cache != NGX_CONF_UNSET_PTR) {
1718         return "is duplicate";
1719     }
1720 
1721     value = cf->args->elts;
1722 
1723     max = 0;
1724     inactive = 10;
1725     valid = 60;
1726     min_uses = 1;
1727 
1728     for (i = 1; i < cf->args->nelts; i++) {
1729 
1730         if (ngx_strncmp(value[i].data, "max=", 4) == 0) {
1731 
1732             max = ngx_atoi(value[i].data + 4, value[i].len - 4);
1733             if (max == NGX_ERROR) {
1734                 goto failed;
1735             }
1736 
1737             continue;
1738         }
1739 
1740         if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) {
1741 
1742             s.len = value[i].len - 9;
1743             s.data = value[i].data + 9;
1744 
1745             inactive = ngx_parse_time(&s, 1);
1746             if (inactive == (time_t) NGX_ERROR) {
1747                 goto failed;
1748             }
1749 
1750             continue;
1751         }
1752 
1753         if (ngx_strncmp(value[i].data, "min_uses=", 9) == 0) {
1754 
1755             min_uses = ngx_atoi(value[i].data + 9, value[i].len - 9);
1756             if (min_uses == NGX_ERROR) {
1757                 goto failed;
1758             }
1759 
1760             continue;
1761         }
1762 
1763         if (ngx_strncmp(value[i].data, "valid=", 6) == 0) {
1764 
1765             s.len = value[i].len - 6;
1766             s.data = value[i].data + 6;
1767 
1768             valid = ngx_parse_time(&s, 1);
1769             if (valid == (time_t) NGX_ERROR) {
1770                 goto failed;
1771             }
1772 
1773             continue;
1774         }
1775 
1776         if (ngx_strcmp(value[i].data, "off") == 0) {
1777 
1778             llcf->open_file_cache = NULL;
1779 
1780             continue;
1781         }
1782 
1783     failed:
1784 
1785         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1786                            "invalid \"open_log_file_cache\" parameter \"%V\"",
1787                            &value[i]);
1788         return NGX_CONF_ERROR;
1789     }
1790 
1791     if (llcf->open_file_cache == NULL) {
1792         return NGX_CONF_OK;
1793     }
1794 
1795     if (max == 0) {
1796         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1797                         "\"open_log_file_cache\" must have \"max\" parameter");
1798         return NGX_CONF_ERROR;
1799     }
1800 
1801     llcf->open_file_cache = ngx_open_file_cache_init(cf->pool, max, inactive);
1802 
1803     if (llcf->open_file_cache) {
1804 
1805         llcf->open_file_cache_valid = valid;
1806         llcf->open_file_cache_min_uses = min_uses;
1807 
1808         return NGX_CONF_OK;
1809     }
1810 
1811     return NGX_CONF_ERROR;
1812 }
1813 
1814 
1815 static ngx_int_t
1816 ngx_http_log_init(ngx_conf_t *cf)
1817 {
1818     ngx_str_t                  *value;
1819     ngx_array_t                 a;
1820     ngx_http_handler_pt        *h;
1821     ngx_http_log_fmt_t         *fmt;
1822     ngx_http_log_main_conf_t   *lmcf;
1823     ngx_http_core_main_conf_t  *cmcf;
1824 
1825     lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);
1826 
1827     if (lmcf->combined_used) {
1828         if (ngx_array_init(&a, cf->pool, 1, sizeof(ngx_str_t)) != NGX_OK) {
1829             return NGX_ERROR;
1830         }
1831 
1832         value = ngx_array_push(&a);
1833         if (value == NULL) {
1834             return NGX_ERROR;
1835         }
1836 
1837         *value = ngx_http_combined_fmt;
1838         fmt = lmcf->formats.elts;
1839 
1840         if (ngx_http_log_compile_format(cf, NULL, fmt->ops, &a, 0)
1841             != NGX_CONF_OK)
1842         {
1843             return NGX_ERROR;
1844         }
1845     }
1846 
1847     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
1848 
1849     h = ngx_array_push(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers);
1850     if (h == NULL) {
1851         return NGX_ERROR;
1852     }
1853 
1854     *h = ngx_http_log_handler;
1855 
1856     return NGX_OK;
1857 }