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_stream.h>
0011 
0012 #if (NGX_ZLIB)
0013 #include <zlib.h>
0014 #endif
0015 
0016 
0017 typedef struct ngx_stream_log_op_s  ngx_stream_log_op_t;
0018 
0019 typedef u_char *(*ngx_stream_log_op_run_pt) (ngx_stream_session_t *s,
0020     u_char *buf, ngx_stream_log_op_t *op);
0021 
0022 typedef size_t (*ngx_stream_log_op_getlen_pt) (ngx_stream_session_t *s,
0023     uintptr_t data);
0024 
0025 
0026 struct ngx_stream_log_op_s {
0027     size_t                       len;
0028     ngx_stream_log_op_getlen_pt  getlen;
0029     ngx_stream_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_stream_log_op_t */
0038 } ngx_stream_log_fmt_t;
0039 
0040 
0041 typedef struct {
0042     ngx_array_t                  formats;    /* array of ngx_stream_log_fmt_t */
0043 } ngx_stream_log_main_conf_t;
0044 
0045 
0046 typedef struct {
0047     u_char                      *start;
0048     u_char                      *pos;
0049     u_char                      *last;
0050 
0051     ngx_event_t                 *event;
0052     ngx_msec_t                   flush;
0053     ngx_int_t                    gzip;
0054 } ngx_stream_log_buf_t;
0055 
0056 
0057 typedef struct {
0058     ngx_array_t                 *lengths;
0059     ngx_array_t                 *values;
0060 } ngx_stream_log_script_t;
0061 
0062 
0063 typedef struct {
0064     ngx_open_file_t             *file;
0065     ngx_stream_log_script_t     *script;
0066     time_t                       disk_full_time;
0067     time_t                       error_log_time;
0068     ngx_syslog_peer_t           *syslog_peer;
0069     ngx_stream_log_fmt_t        *format;
0070     ngx_stream_complex_value_t  *filter;
0071 } ngx_stream_log_t;
0072 
0073 
0074 typedef struct {
0075     ngx_array_t                 *logs;       /* array of ngx_stream_log_t */
0076 
0077     ngx_open_file_cache_t       *open_file_cache;
0078     time_t                       open_file_cache_valid;
0079     ngx_uint_t                   open_file_cache_min_uses;
0080 
0081     ngx_uint_t                   off;        /* unsigned  off:1 */
0082 } ngx_stream_log_srv_conf_t;
0083 
0084 
0085 typedef struct {
0086     ngx_str_t                    name;
0087     size_t                       len;
0088     ngx_stream_log_op_run_pt     run;
0089 } ngx_stream_log_var_t;
0090 
0091 
0092 #define NGX_STREAM_LOG_ESCAPE_DEFAULT  0
0093 #define NGX_STREAM_LOG_ESCAPE_JSON     1
0094 #define NGX_STREAM_LOG_ESCAPE_NONE     2
0095 
0096 
0097 static void ngx_stream_log_write(ngx_stream_session_t *s, ngx_stream_log_t *log,
0098     u_char *buf, size_t len);
0099 static ssize_t ngx_stream_log_script_write(ngx_stream_session_t *s,
0100     ngx_stream_log_script_t *script, u_char **name, u_char *buf, size_t len);
0101 
0102 #if (NGX_ZLIB)
0103 static ssize_t ngx_stream_log_gzip(ngx_fd_t fd, u_char *buf, size_t len,
0104     ngx_int_t level, ngx_log_t *log);
0105 
0106 static void *ngx_stream_log_gzip_alloc(void *opaque, u_int items, u_int size);
0107 static void ngx_stream_log_gzip_free(void *opaque, void *address);
0108 #endif
0109 
0110 static void ngx_stream_log_flush(ngx_open_file_t *file, ngx_log_t *log);
0111 static void ngx_stream_log_flush_handler(ngx_event_t *ev);
0112 
0113 static ngx_int_t ngx_stream_log_variable_compile(ngx_conf_t *cf,
0114     ngx_stream_log_op_t *op, ngx_str_t *value, ngx_uint_t escape);
0115 static size_t ngx_stream_log_variable_getlen(ngx_stream_session_t *s,
0116     uintptr_t data);
0117 static u_char *ngx_stream_log_variable(ngx_stream_session_t *s, u_char *buf,
0118     ngx_stream_log_op_t *op);
0119 static uintptr_t ngx_stream_log_escape(u_char *dst, u_char *src, size_t size);
0120 static size_t ngx_stream_log_json_variable_getlen(ngx_stream_session_t *s,
0121     uintptr_t data);
0122 static u_char *ngx_stream_log_json_variable(ngx_stream_session_t *s,
0123     u_char *buf, ngx_stream_log_op_t *op);
0124 static size_t ngx_stream_log_unescaped_variable_getlen(ngx_stream_session_t *s,
0125     uintptr_t data);
0126 static u_char *ngx_stream_log_unescaped_variable(ngx_stream_session_t *s,
0127     u_char *buf, ngx_stream_log_op_t *op);
0128 
0129 
0130 static void *ngx_stream_log_create_main_conf(ngx_conf_t *cf);
0131 static void *ngx_stream_log_create_srv_conf(ngx_conf_t *cf);
0132 static char *ngx_stream_log_merge_srv_conf(ngx_conf_t *cf, void *parent,
0133     void *child);
0134 static char *ngx_stream_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd,
0135     void *conf);
0136 static char *ngx_stream_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd,
0137     void *conf);
0138 static char *ngx_stream_log_compile_format(ngx_conf_t *cf,
0139     ngx_array_t *flushes, ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s);
0140 static char *ngx_stream_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd,
0141     void *conf);
0142 static ngx_int_t ngx_stream_log_init(ngx_conf_t *cf);
0143 
0144 
0145 static ngx_command_t  ngx_stream_log_commands[] = {
0146 
0147     { ngx_string("log_format"),
0148       NGX_STREAM_MAIN_CONF|NGX_CONF_2MORE,
0149       ngx_stream_log_set_format,
0150       NGX_STREAM_MAIN_CONF_OFFSET,
0151       0,
0152       NULL },
0153 
0154     { ngx_string("access_log"),
0155       NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_1MORE,
0156       ngx_stream_log_set_log,
0157       NGX_STREAM_SRV_CONF_OFFSET,
0158       0,
0159       NULL },
0160 
0161     { ngx_string("open_log_file_cache"),
0162       NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1234,
0163       ngx_stream_log_open_file_cache,
0164       NGX_STREAM_SRV_CONF_OFFSET,
0165       0,
0166       NULL },
0167 
0168       ngx_null_command
0169 };
0170 
0171 
0172 static ngx_stream_module_t  ngx_stream_log_module_ctx = {
0173     NULL,                                  /* preconfiguration */
0174     ngx_stream_log_init,                   /* postconfiguration */
0175 
0176     ngx_stream_log_create_main_conf,       /* create main configuration */
0177     NULL,                                  /* init main configuration */
0178 
0179     ngx_stream_log_create_srv_conf,        /* create server configuration */
0180     ngx_stream_log_merge_srv_conf          /* merge server configuration */
0181 };
0182 
0183 
0184 ngx_module_t  ngx_stream_log_module = {
0185     NGX_MODULE_V1,
0186     &ngx_stream_log_module_ctx,            /* module context */
0187     ngx_stream_log_commands,               /* module directives */
0188     NGX_STREAM_MODULE,                     /* module type */
0189     NULL,                                  /* init master */
0190     NULL,                                  /* init module */
0191     NULL,                                  /* init process */
0192     NULL,                                  /* init thread */
0193     NULL,                                  /* exit thread */
0194     NULL,                                  /* exit process */
0195     NULL,                                  /* exit master */
0196     NGX_MODULE_V1_PADDING
0197 };
0198 
0199 
0200 static ngx_int_t
0201 ngx_stream_log_handler(ngx_stream_session_t *s)
0202 {
0203     u_char                     *line, *p;
0204     size_t                      len, size;
0205     ssize_t                     n;
0206     ngx_str_t                   val;
0207     ngx_uint_t                  i, l;
0208     ngx_stream_log_t           *log;
0209     ngx_stream_log_op_t        *op;
0210     ngx_stream_log_buf_t       *buffer;
0211     ngx_stream_log_srv_conf_t  *lscf;
0212 
0213     ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
0214                    "stream log handler");
0215 
0216     lscf = ngx_stream_get_module_srv_conf(s, ngx_stream_log_module);
0217 
0218     if (lscf->off || lscf->logs == NULL) {
0219         return NGX_OK;
0220     }
0221 
0222     log = lscf->logs->elts;
0223     for (l = 0; l < lscf->logs->nelts; l++) {
0224 
0225         if (log[l].filter) {
0226             if (ngx_stream_complex_value(s, log[l].filter, &val) != NGX_OK) {
0227                 return NGX_ERROR;
0228             }
0229 
0230             if (val.len == 0 || (val.len == 1 && val.data[0] == '0')) {
0231                 continue;
0232             }
0233         }
0234 
0235         if (ngx_time() == log[l].disk_full_time) {
0236 
0237             /*
0238              * on FreeBSD writing to a full filesystem with enabled softupdates
0239              * may block process for much longer time than writing to non-full
0240              * filesystem, so we skip writing to a log for one second
0241              */
0242 
0243             continue;
0244         }
0245 
0246         ngx_stream_script_flush_no_cacheable_variables(s,
0247                                                        log[l].format->flushes);
0248 
0249         len = 0;
0250         op = log[l].format->ops->elts;
0251         for (i = 0; i < log[l].format->ops->nelts; i++) {
0252             if (op[i].len == 0) {
0253                 len += op[i].getlen(s, op[i].data);
0254 
0255             } else {
0256                 len += op[i].len;
0257             }
0258         }
0259 
0260         if (log[l].syslog_peer) {
0261 
0262             /* length of syslog's PRI and HEADER message parts */
0263             len += sizeof("<255>Jan 01 00:00:00 ") - 1
0264                    + ngx_cycle->hostname.len + 1
0265                    + log[l].syslog_peer->tag.len + 2;
0266 
0267             goto alloc_line;
0268         }
0269 
0270         len += NGX_LINEFEED_SIZE;
0271 
0272         buffer = log[l].file ? log[l].file->data : NULL;
0273 
0274         if (buffer) {
0275 
0276             if (len > (size_t) (buffer->last - buffer->pos)) {
0277 
0278                 ngx_stream_log_write(s, &log[l], buffer->start,
0279                                      buffer->pos - buffer->start);
0280 
0281                 buffer->pos = buffer->start;
0282             }
0283 
0284             if (len <= (size_t) (buffer->last - buffer->pos)) {
0285 
0286                 p = buffer->pos;
0287 
0288                 if (buffer->event && p == buffer->start) {
0289                     ngx_add_timer(buffer->event, buffer->flush);
0290                 }
0291 
0292                 for (i = 0; i < log[l].format->ops->nelts; i++) {
0293                     p = op[i].run(s, p, &op[i]);
0294                 }
0295 
0296                 ngx_linefeed(p);
0297 
0298                 buffer->pos = p;
0299 
0300                 continue;
0301             }
0302 
0303             if (buffer->event && buffer->event->timer_set) {
0304                 ngx_del_timer(buffer->event);
0305             }
0306         }
0307 
0308     alloc_line:
0309 
0310         line = ngx_pnalloc(s->connection->pool, len);
0311         if (line == NULL) {
0312             return NGX_ERROR;
0313         }
0314 
0315         p = line;
0316 
0317         if (log[l].syslog_peer) {
0318             p = ngx_syslog_add_header(log[l].syslog_peer, line);
0319         }
0320 
0321         for (i = 0; i < log[l].format->ops->nelts; i++) {
0322             p = op[i].run(s, p, &op[i]);
0323         }
0324 
0325         if (log[l].syslog_peer) {
0326 
0327             size = p - line;
0328 
0329             n = ngx_syslog_send(log[l].syslog_peer, line, size);
0330 
0331             if (n < 0) {
0332                 ngx_log_error(NGX_LOG_WARN, s->connection->log, 0,
0333                               "send() to syslog failed");
0334 
0335             } else if ((size_t) n != size) {
0336                 ngx_log_error(NGX_LOG_WARN, s->connection->log, 0,
0337                               "send() to syslog has written only %z of %uz",
0338                               n, size);
0339             }
0340 
0341             continue;
0342         }
0343 
0344         ngx_linefeed(p);
0345 
0346         ngx_stream_log_write(s, &log[l], line, p - line);
0347     }
0348 
0349     return NGX_OK;
0350 }
0351 
0352 
0353 static void
0354 ngx_stream_log_write(ngx_stream_session_t *s, ngx_stream_log_t *log,
0355     u_char *buf, size_t len)
0356 {
0357     u_char                *name;
0358     time_t                 now;
0359     ssize_t                n;
0360     ngx_err_t              err;
0361 #if (NGX_ZLIB)
0362     ngx_stream_log_buf_t  *buffer;
0363 #endif
0364 
0365     if (log->script == NULL) {
0366         name = log->file->name.data;
0367 
0368 #if (NGX_ZLIB)
0369         buffer = log->file->data;
0370 
0371         if (buffer && buffer->gzip) {
0372             n = ngx_stream_log_gzip(log->file->fd, buf, len, buffer->gzip,
0373                                     s->connection->log);
0374         } else {
0375             n = ngx_write_fd(log->file->fd, buf, len);
0376         }
0377 #else
0378         n = ngx_write_fd(log->file->fd, buf, len);
0379 #endif
0380 
0381     } else {
0382         name = NULL;
0383         n = ngx_stream_log_script_write(s, log->script, &name, buf, len);
0384     }
0385 
0386     if (n == (ssize_t) len) {
0387         return;
0388     }
0389 
0390     now = ngx_time();
0391 
0392     if (n == -1) {
0393         err = ngx_errno;
0394 
0395         if (err == NGX_ENOSPC) {
0396             log->disk_full_time = now;
0397         }
0398 
0399         if (now - log->error_log_time > 59) {
0400             ngx_log_error(NGX_LOG_ALERT, s->connection->log, err,
0401                           ngx_write_fd_n " to \"%s\" failed", name);
0402 
0403             log->error_log_time = now;
0404         }
0405 
0406         return;
0407     }
0408 
0409     if (now - log->error_log_time > 59) {
0410         ngx_log_error(NGX_LOG_ALERT, s->connection->log, 0,
0411                       ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz",
0412                       name, n, len);
0413 
0414         log->error_log_time = now;
0415     }
0416 }
0417 
0418 
0419 static ssize_t
0420 ngx_stream_log_script_write(ngx_stream_session_t *s,
0421     ngx_stream_log_script_t *script, u_char **name, u_char *buf, size_t len)
0422 {
0423     ssize_t                     n;
0424     ngx_str_t                   log;
0425     ngx_open_file_info_t        of;
0426     ngx_stream_log_srv_conf_t  *lscf;
0427 
0428     if (ngx_stream_script_run(s, &log, script->lengths->elts, 1,
0429                               script->values->elts)
0430         == NULL)
0431     {
0432         /* simulate successful logging */
0433         return len;
0434     }
0435 
0436     log.data[log.len - 1] = '\0';
0437     *name = log.data;
0438 
0439     ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
0440                    "stream log \"%s\"", log.data);
0441 
0442     lscf = ngx_stream_get_module_srv_conf(s, ngx_stream_log_module);
0443 
0444     ngx_memzero(&of, sizeof(ngx_open_file_info_t));
0445 
0446     of.log = 1;
0447     of.valid = lscf->open_file_cache_valid;
0448     of.min_uses = lscf->open_file_cache_min_uses;
0449     of.directio = NGX_OPEN_FILE_DIRECTIO_OFF;
0450 
0451     if (ngx_open_cached_file(lscf->open_file_cache, &log, &of,
0452                              s->connection->pool)
0453         != NGX_OK)
0454     {
0455         if (of.err == 0) {
0456             /* simulate successful logging */
0457             return len;
0458         }
0459 
0460         ngx_log_error(NGX_LOG_CRIT, s->connection->log, ngx_errno,
0461                       "%s \"%s\" failed", of.failed, log.data);
0462         /* simulate successful logging */
0463         return len;
0464     }
0465 
0466     ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
0467                    "stream log #%d", of.fd);
0468 
0469     n = ngx_write_fd(of.fd, buf, len);
0470 
0471     return n;
0472 }
0473 
0474 
0475 #if (NGX_ZLIB)
0476 
0477 static ssize_t
0478 ngx_stream_log_gzip(ngx_fd_t fd, u_char *buf, size_t len, ngx_int_t level,
0479     ngx_log_t *log)
0480 {
0481     int          rc, wbits, memlevel;
0482     u_char      *out;
0483     size_t       size;
0484     ssize_t      n;
0485     z_stream     zstream;
0486     ngx_err_t    err;
0487     ngx_pool_t  *pool;
0488 
0489     wbits = MAX_WBITS;
0490     memlevel = MAX_MEM_LEVEL - 1;
0491 
0492     while ((ssize_t) len < ((1 << (wbits - 1)) - 262)) {
0493         wbits--;
0494         memlevel--;
0495     }
0496 
0497     /*
0498      * This is a formula from deflateBound() for conservative upper bound of
0499      * compressed data plus 18 bytes of gzip wrapper.
0500      */
0501 
0502     size = len + ((len + 7) >> 3) + ((len + 63) >> 6) + 5 + 18;
0503 
0504     ngx_memzero(&zstream, sizeof(z_stream));
0505 
0506     pool = ngx_create_pool(256, log);
0507     if (pool == NULL) {
0508         /* simulate successful logging */
0509         return len;
0510     }
0511 
0512     pool->log = log;
0513 
0514     zstream.zalloc = ngx_stream_log_gzip_alloc;
0515     zstream.zfree = ngx_stream_log_gzip_free;
0516     zstream.opaque = pool;
0517 
0518     out = ngx_pnalloc(pool, size);
0519     if (out == NULL) {
0520         goto done;
0521     }
0522 
0523     zstream.next_in = buf;
0524     zstream.avail_in = len;
0525     zstream.next_out = out;
0526     zstream.avail_out = size;
0527 
0528     rc = deflateInit2(&zstream, (int) level, Z_DEFLATED, wbits + 16, memlevel,
0529                       Z_DEFAULT_STRATEGY);
0530 
0531     if (rc != Z_OK) {
0532         ngx_log_error(NGX_LOG_ALERT, log, 0, "deflateInit2() failed: %d", rc);
0533         goto done;
0534     }
0535 
0536     ngx_log_debug4(NGX_LOG_DEBUG_STREAM, log, 0,
0537                    "deflate in: ni:%p no:%p ai:%ud ao:%ud",
0538                    zstream.next_in, zstream.next_out,
0539                    zstream.avail_in, zstream.avail_out);
0540 
0541     rc = deflate(&zstream, Z_FINISH);
0542 
0543     if (rc != Z_STREAM_END) {
0544         ngx_log_error(NGX_LOG_ALERT, log, 0,
0545                       "deflate(Z_FINISH) failed: %d", rc);
0546         goto done;
0547     }
0548 
0549     ngx_log_debug5(NGX_LOG_DEBUG_STREAM, log, 0,
0550                    "deflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d",
0551                    zstream.next_in, zstream.next_out,
0552                    zstream.avail_in, zstream.avail_out,
0553                    rc);
0554 
0555     size -= zstream.avail_out;
0556 
0557     rc = deflateEnd(&zstream);
0558 
0559     if (rc != Z_OK) {
0560         ngx_log_error(NGX_LOG_ALERT, log, 0, "deflateEnd() failed: %d", rc);
0561         goto done;
0562     }
0563 
0564     n = ngx_write_fd(fd, out, size);
0565 
0566     if (n != (ssize_t) size) {
0567         err = (n == -1) ? ngx_errno : 0;
0568 
0569         ngx_destroy_pool(pool);
0570 
0571         ngx_set_errno(err);
0572         return -1;
0573     }
0574 
0575 done:
0576 
0577     ngx_destroy_pool(pool);
0578 
0579     /* simulate successful logging */
0580     return len;
0581 }
0582 
0583 
0584 static void *
0585 ngx_stream_log_gzip_alloc(void *opaque, u_int items, u_int size)
0586 {
0587     ngx_pool_t *pool = opaque;
0588 
0589     ngx_log_debug2(NGX_LOG_DEBUG_STREAM, pool->log, 0,
0590                    "gzip alloc: n:%ud s:%ud", items, size);
0591 
0592     return ngx_palloc(pool, items * size);
0593 }
0594 
0595 
0596 static void
0597 ngx_stream_log_gzip_free(void *opaque, void *address)
0598 {
0599 #if 0
0600     ngx_pool_t *pool = opaque;
0601 
0602     ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pool->log, 0,
0603                    "gzip free: %p", address);
0604 #endif
0605 }
0606 
0607 #endif
0608 
0609 
0610 static void
0611 ngx_stream_log_flush(ngx_open_file_t *file, ngx_log_t *log)
0612 {
0613     size_t                 len;
0614     ssize_t                n;
0615     ngx_stream_log_buf_t  *buffer;
0616 
0617     buffer = file->data;
0618 
0619     len = buffer->pos - buffer->start;
0620 
0621     if (len == 0) {
0622         return;
0623     }
0624 
0625 #if (NGX_ZLIB)
0626     if (buffer->gzip) {
0627         n = ngx_stream_log_gzip(file->fd, buffer->start, len, buffer->gzip,
0628                                 log);
0629     } else {
0630         n = ngx_write_fd(file->fd, buffer->start, len);
0631     }
0632 #else
0633     n = ngx_write_fd(file->fd, buffer->start, len);
0634 #endif
0635 
0636     if (n == -1) {
0637         ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
0638                       ngx_write_fd_n " to \"%s\" failed",
0639                       file->name.data);
0640 
0641     } else if ((size_t) n != len) {
0642         ngx_log_error(NGX_LOG_ALERT, log, 0,
0643                       ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz",
0644                       file->name.data, n, len);
0645     }
0646 
0647     buffer->pos = buffer->start;
0648 
0649     if (buffer->event && buffer->event->timer_set) {
0650         ngx_del_timer(buffer->event);
0651     }
0652 }
0653 
0654 
0655 static void
0656 ngx_stream_log_flush_handler(ngx_event_t *ev)
0657 {
0658     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0,
0659                    "stream log buffer flush handler");
0660 
0661     ngx_stream_log_flush(ev->data, ev->log);
0662 }
0663 
0664 
0665 static u_char *
0666 ngx_stream_log_copy_short(ngx_stream_session_t *s, u_char *buf,
0667     ngx_stream_log_op_t *op)
0668 {
0669     size_t     len;
0670     uintptr_t  data;
0671 
0672     len = op->len;
0673     data = op->data;
0674 
0675     while (len--) {
0676         *buf++ = (u_char) (data & 0xff);
0677         data >>= 8;
0678     }
0679 
0680     return buf;
0681 }
0682 
0683 
0684 static u_char *
0685 ngx_stream_log_copy_long(ngx_stream_session_t *s, u_char *buf,
0686     ngx_stream_log_op_t *op)
0687 {
0688     return ngx_cpymem(buf, (u_char *) op->data, op->len);
0689 }
0690 
0691 
0692 static ngx_int_t
0693 ngx_stream_log_variable_compile(ngx_conf_t *cf, ngx_stream_log_op_t *op,
0694     ngx_str_t *value, ngx_uint_t escape)
0695 {
0696     ngx_int_t  index;
0697 
0698     index = ngx_stream_get_variable_index(cf, value);
0699     if (index == NGX_ERROR) {
0700         return NGX_ERROR;
0701     }
0702 
0703     op->len = 0;
0704 
0705     switch (escape) {
0706     case NGX_STREAM_LOG_ESCAPE_JSON:
0707         op->getlen = ngx_stream_log_json_variable_getlen;
0708         op->run = ngx_stream_log_json_variable;
0709         break;
0710 
0711     case NGX_STREAM_LOG_ESCAPE_NONE:
0712         op->getlen = ngx_stream_log_unescaped_variable_getlen;
0713         op->run = ngx_stream_log_unescaped_variable;
0714         break;
0715 
0716     default: /* NGX_STREAM_LOG_ESCAPE_DEFAULT */
0717         op->getlen = ngx_stream_log_variable_getlen;
0718         op->run = ngx_stream_log_variable;
0719     }
0720 
0721     op->data = index;
0722 
0723     return NGX_OK;
0724 }
0725 
0726 
0727 static size_t
0728 ngx_stream_log_variable_getlen(ngx_stream_session_t *s, uintptr_t data)
0729 {
0730     uintptr_t                     len;
0731     ngx_stream_variable_value_t  *value;
0732 
0733     value = ngx_stream_get_indexed_variable(s, data);
0734 
0735     if (value == NULL || value->not_found) {
0736         return 1;
0737     }
0738 
0739     len = ngx_stream_log_escape(NULL, value->data, value->len);
0740 
0741     value->escape = len ? 1 : 0;
0742 
0743     return value->len + len * 3;
0744 }
0745 
0746 
0747 static u_char *
0748 ngx_stream_log_variable(ngx_stream_session_t *s, u_char *buf,
0749     ngx_stream_log_op_t *op)
0750 {
0751     ngx_stream_variable_value_t  *value;
0752 
0753     value = ngx_stream_get_indexed_variable(s, op->data);
0754 
0755     if (value == NULL || value->not_found) {
0756         *buf = '-';
0757         return buf + 1;
0758     }
0759 
0760     if (value->escape == 0) {
0761         return ngx_cpymem(buf, value->data, value->len);
0762 
0763     } else {
0764         return (u_char *) ngx_stream_log_escape(buf, value->data, value->len);
0765     }
0766 }
0767 
0768 
0769 static uintptr_t
0770 ngx_stream_log_escape(u_char *dst, u_char *src, size_t size)
0771 {
0772     ngx_uint_t      n;
0773     static u_char   hex[] = "0123456789ABCDEF";
0774 
0775     static uint32_t   escape[] = {
0776         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
0777 
0778                     /* ?>=< ;:98 7654 3210  /.-, +*)( '&%$ #"!  */
0779         0x00000004, /* 0000 0000 0000 0000  0000 0000 0000 0100 */
0780 
0781                     /* _^]\ [ZYX WVUT SRQP  ONML KJIH GFED CBA@ */
0782         0x10000000, /* 0001 0000 0000 0000  0000 0000 0000 0000 */
0783 
0784                     /*  ~}| {zyx wvut srqp  onml kjih gfed cba` */
0785         0x80000000, /* 1000 0000 0000 0000  0000 0000 0000 0000 */
0786 
0787         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
0788         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
0789         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
0790         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
0791     };
0792 
0793 
0794     if (dst == NULL) {
0795 
0796         /* find the number of the characters to be escaped */
0797 
0798         n = 0;
0799 
0800         while (size) {
0801             if (escape[*src >> 5] & (1U << (*src & 0x1f))) {
0802                 n++;
0803             }
0804             src++;
0805             size--;
0806         }
0807 
0808         return (uintptr_t) n;
0809     }
0810 
0811     while (size) {
0812         if (escape[*src >> 5] & (1U << (*src & 0x1f))) {
0813             *dst++ = '\\';
0814             *dst++ = 'x';
0815             *dst++ = hex[*src >> 4];
0816             *dst++ = hex[*src & 0xf];
0817             src++;
0818 
0819         } else {
0820             *dst++ = *src++;
0821         }
0822         size--;
0823     }
0824 
0825     return (uintptr_t) dst;
0826 }
0827 
0828 
0829 static size_t
0830 ngx_stream_log_json_variable_getlen(ngx_stream_session_t *s, uintptr_t data)
0831 {
0832     uintptr_t                     len;
0833     ngx_stream_variable_value_t  *value;
0834 
0835     value = ngx_stream_get_indexed_variable(s, data);
0836 
0837     if (value == NULL || value->not_found) {
0838         return 0;
0839     }
0840 
0841     len = ngx_escape_json(NULL, value->data, value->len);
0842 
0843     value->escape = len ? 1 : 0;
0844 
0845     return value->len + len;
0846 }
0847 
0848 
0849 static u_char *
0850 ngx_stream_log_json_variable(ngx_stream_session_t *s, u_char *buf,
0851     ngx_stream_log_op_t *op)
0852 {
0853     ngx_stream_variable_value_t  *value;
0854 
0855     value = ngx_stream_get_indexed_variable(s, op->data);
0856 
0857     if (value == NULL || value->not_found) {
0858         return buf;
0859     }
0860 
0861     if (value->escape == 0) {
0862         return ngx_cpymem(buf, value->data, value->len);
0863 
0864     } else {
0865         return (u_char *) ngx_escape_json(buf, value->data, value->len);
0866     }
0867 }
0868 
0869 
0870 static size_t
0871 ngx_stream_log_unescaped_variable_getlen(ngx_stream_session_t *s,
0872     uintptr_t data)
0873 {
0874     ngx_stream_variable_value_t  *value;
0875 
0876     value = ngx_stream_get_indexed_variable(s, data);
0877 
0878     if (value == NULL || value->not_found) {
0879         return 0;
0880     }
0881 
0882     value->escape = 0;
0883 
0884     return value->len;
0885 }
0886 
0887 
0888 static u_char *
0889 ngx_stream_log_unescaped_variable(ngx_stream_session_t *s, u_char *buf,
0890                                   ngx_stream_log_op_t *op)
0891 {
0892     ngx_stream_variable_value_t  *value;
0893 
0894     value = ngx_stream_get_indexed_variable(s, op->data);
0895 
0896     if (value == NULL || value->not_found) {
0897         return buf;
0898     }
0899 
0900     return ngx_cpymem(buf, value->data, value->len);
0901 }
0902 
0903 
0904 static void *
0905 ngx_stream_log_create_main_conf(ngx_conf_t *cf)
0906 {
0907     ngx_stream_log_main_conf_t  *conf;
0908 
0909     conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_log_main_conf_t));
0910     if (conf == NULL) {
0911         return NULL;
0912     }
0913 
0914     if (ngx_array_init(&conf->formats, cf->pool, 4,
0915                        sizeof(ngx_stream_log_fmt_t))
0916         != NGX_OK)
0917     {
0918         return NULL;
0919     }
0920 
0921     return conf;
0922 }
0923 
0924 
0925 static void *
0926 ngx_stream_log_create_srv_conf(ngx_conf_t *cf)
0927 {
0928     ngx_stream_log_srv_conf_t  *conf;
0929 
0930     conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_log_srv_conf_t));
0931     if (conf == NULL) {
0932         return NULL;
0933     }
0934 
0935     conf->open_file_cache = NGX_CONF_UNSET_PTR;
0936 
0937     return conf;
0938 }
0939 
0940 
0941 static char *
0942 ngx_stream_log_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
0943 {
0944     ngx_stream_log_srv_conf_t *prev = parent;
0945     ngx_stream_log_srv_conf_t *conf = child;
0946 
0947     if (conf->open_file_cache == NGX_CONF_UNSET_PTR) {
0948 
0949         conf->open_file_cache = prev->open_file_cache;
0950         conf->open_file_cache_valid = prev->open_file_cache_valid;
0951         conf->open_file_cache_min_uses = prev->open_file_cache_min_uses;
0952 
0953         if (conf->open_file_cache == NGX_CONF_UNSET_PTR) {
0954             conf->open_file_cache = NULL;
0955         }
0956     }
0957 
0958     if (conf->logs || conf->off) {
0959         return NGX_CONF_OK;
0960     }
0961 
0962     conf->logs = prev->logs;
0963     conf->off = prev->off;
0964 
0965     return NGX_CONF_OK;
0966 }
0967 
0968 
0969 static char *
0970 ngx_stream_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0971 {
0972     ngx_stream_log_srv_conf_t *lscf = conf;
0973 
0974     ssize_t                              size;
0975     ngx_int_t                            gzip;
0976     ngx_uint_t                           i, n;
0977     ngx_msec_t                           flush;
0978     ngx_str_t                           *value, name, s;
0979     ngx_stream_log_t                    *log;
0980     ngx_syslog_peer_t                   *peer;
0981     ngx_stream_log_buf_t                *buffer;
0982     ngx_stream_log_fmt_t                *fmt;
0983     ngx_stream_script_compile_t          sc;
0984     ngx_stream_log_main_conf_t          *lmcf;
0985     ngx_stream_compile_complex_value_t   ccv;
0986 
0987     value = cf->args->elts;
0988 
0989     if (ngx_strcmp(value[1].data, "off") == 0) {
0990         lscf->off = 1;
0991         if (cf->args->nelts == 2) {
0992             return NGX_CONF_OK;
0993         }
0994 
0995         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0996                            "invalid parameter \"%V\"", &value[2]);
0997         return NGX_CONF_ERROR;
0998     }
0999 
1000     if (lscf->logs == NULL) {
1001         lscf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_stream_log_t));
1002         if (lscf->logs == NULL) {
1003             return NGX_CONF_ERROR;
1004         }
1005     }
1006 
1007     lmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_log_module);
1008 
1009     log = ngx_array_push(lscf->logs);
1010     if (log == NULL) {
1011         return NGX_CONF_ERROR;
1012     }
1013 
1014     ngx_memzero(log, sizeof(ngx_stream_log_t));
1015 
1016 
1017     if (ngx_strncmp(value[1].data, "syslog:", 7) == 0) {
1018 
1019         peer = ngx_pcalloc(cf->pool, sizeof(ngx_syslog_peer_t));
1020         if (peer == NULL) {
1021             return NGX_CONF_ERROR;
1022         }
1023 
1024         if (ngx_syslog_process_conf(cf, peer) != NGX_CONF_OK) {
1025             return NGX_CONF_ERROR;
1026         }
1027 
1028         log->syslog_peer = peer;
1029 
1030         goto process_formats;
1031     }
1032 
1033     n = ngx_stream_script_variables_count(&value[1]);
1034 
1035     if (n == 0) {
1036         log->file = ngx_conf_open_file(cf->cycle, &value[1]);
1037         if (log->file == NULL) {
1038             return NGX_CONF_ERROR;
1039         }
1040 
1041     } else {
1042         if (ngx_conf_full_name(cf->cycle, &value[1], 0) != NGX_OK) {
1043             return NGX_CONF_ERROR;
1044         }
1045 
1046         log->script = ngx_pcalloc(cf->pool, sizeof(ngx_stream_log_script_t));
1047         if (log->script == NULL) {
1048             return NGX_CONF_ERROR;
1049         }
1050 
1051         ngx_memzero(&sc, sizeof(ngx_stream_script_compile_t));
1052 
1053         sc.cf = cf;
1054         sc.source = &value[1];
1055         sc.lengths = &log->script->lengths;
1056         sc.values = &log->script->values;
1057         sc.variables = n;
1058         sc.complete_lengths = 1;
1059         sc.complete_values = 1;
1060 
1061         if (ngx_stream_script_compile(&sc) != NGX_OK) {
1062             return NGX_CONF_ERROR;
1063         }
1064     }
1065 
1066 process_formats:
1067 
1068     if (cf->args->nelts >= 3) {
1069         name = value[2];
1070 
1071     } else {
1072         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1073                            "log format is not specified");
1074         return NGX_CONF_ERROR;
1075     }
1076 
1077     fmt = lmcf->formats.elts;
1078     for (i = 0; i < lmcf->formats.nelts; i++) {
1079         if (fmt[i].name.len == name.len
1080             && ngx_strcasecmp(fmt[i].name.data, name.data) == 0)
1081         {
1082             log->format = &fmt[i];
1083             break;
1084         }
1085     }
1086 
1087     if (log->format == NULL) {
1088         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1089                            "unknown log format \"%V\"", &name);
1090         return NGX_CONF_ERROR;
1091     }
1092 
1093     size = 0;
1094     flush = 0;
1095     gzip = 0;
1096 
1097     for (i = 3; i < cf->args->nelts; i++) {
1098 
1099         if (ngx_strncmp(value[i].data, "buffer=", 7) == 0) {
1100             s.len = value[i].len - 7;
1101             s.data = value[i].data + 7;
1102 
1103             size = ngx_parse_size(&s);
1104 
1105             if (size == NGX_ERROR || size == 0) {
1106                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1107                                    "invalid buffer size \"%V\"", &s);
1108                 return NGX_CONF_ERROR;
1109             }
1110 
1111             continue;
1112         }
1113 
1114         if (ngx_strncmp(value[i].data, "flush=", 6) == 0) {
1115             s.len = value[i].len - 6;
1116             s.data = value[i].data + 6;
1117 
1118             flush = ngx_parse_time(&s, 0);
1119 
1120             if (flush == (ngx_msec_t) NGX_ERROR || flush == 0) {
1121                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1122                                    "invalid flush time \"%V\"", &s);
1123                 return NGX_CONF_ERROR;
1124             }
1125 
1126             continue;
1127         }
1128 
1129         if (ngx_strncmp(value[i].data, "gzip", 4) == 0
1130             && (value[i].len == 4 || value[i].data[4] == '='))
1131         {
1132 #if (NGX_ZLIB)
1133             if (size == 0) {
1134                 size = 64 * 1024;
1135             }
1136 
1137             if (value[i].len == 4) {
1138                 gzip = Z_BEST_SPEED;
1139                 continue;
1140             }
1141 
1142             s.len = value[i].len - 5;
1143             s.data = value[i].data + 5;
1144 
1145             gzip = ngx_atoi(s.data, s.len);
1146 
1147             if (gzip < 1 || gzip > 9) {
1148                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1149                                    "invalid compression level \"%V\"", &s);
1150                 return NGX_CONF_ERROR;
1151             }
1152 
1153             continue;
1154 
1155 #else
1156             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1157                                "nginx was built without zlib support");
1158             return NGX_CONF_ERROR;
1159 #endif
1160         }
1161 
1162         if (ngx_strncmp(value[i].data, "if=", 3) == 0) {
1163             s.len = value[i].len - 3;
1164             s.data = value[i].data + 3;
1165 
1166             ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t));
1167 
1168             ccv.cf = cf;
1169             ccv.value = &s;
1170             ccv.complex_value = ngx_palloc(cf->pool,
1171                                            sizeof(ngx_stream_complex_value_t));
1172             if (ccv.complex_value == NULL) {
1173                 return NGX_CONF_ERROR;
1174             }
1175 
1176             if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) {
1177                 return NGX_CONF_ERROR;
1178             }
1179 
1180             log->filter = ccv.complex_value;
1181 
1182             continue;
1183         }
1184 
1185         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1186                            "invalid parameter \"%V\"", &value[i]);
1187         return NGX_CONF_ERROR;
1188     }
1189 
1190     if (flush && size == 0) {
1191         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1192                            "no buffer is defined for access_log \"%V\"",
1193                            &value[1]);
1194         return NGX_CONF_ERROR;
1195     }
1196 
1197     if (size) {
1198 
1199         if (log->script) {
1200             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1201                                "buffered logs cannot have variables in name");
1202             return NGX_CONF_ERROR;
1203         }
1204 
1205         if (log->syslog_peer) {
1206             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1207                                "logs to syslog cannot be buffered");
1208             return NGX_CONF_ERROR;
1209         }
1210 
1211         if (log->file->data) {
1212             buffer = log->file->data;
1213 
1214             if (buffer->last - buffer->start != size
1215                 || buffer->flush != flush
1216                 || buffer->gzip != gzip)
1217             {
1218                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1219                                    "access_log \"%V\" already defined "
1220                                    "with conflicting parameters",
1221                                    &value[1]);
1222                 return NGX_CONF_ERROR;
1223             }
1224 
1225             return NGX_CONF_OK;
1226         }
1227 
1228         buffer = ngx_pcalloc(cf->pool, sizeof(ngx_stream_log_buf_t));
1229         if (buffer == NULL) {
1230             return NGX_CONF_ERROR;
1231         }
1232 
1233         buffer->start = ngx_pnalloc(cf->pool, size);
1234         if (buffer->start == NULL) {
1235             return NGX_CONF_ERROR;
1236         }
1237 
1238         buffer->pos = buffer->start;
1239         buffer->last = buffer->start + size;
1240 
1241         if (flush) {
1242             buffer->event = ngx_pcalloc(cf->pool, sizeof(ngx_event_t));
1243             if (buffer->event == NULL) {
1244                 return NGX_CONF_ERROR;
1245             }
1246 
1247             buffer->event->data = log->file;
1248             buffer->event->handler = ngx_stream_log_flush_handler;
1249             buffer->event->log = &cf->cycle->new_log;
1250             buffer->event->cancelable = 1;
1251 
1252             buffer->flush = flush;
1253         }
1254 
1255         buffer->gzip = gzip;
1256 
1257         log->file->flush = ngx_stream_log_flush;
1258         log->file->data = buffer;
1259     }
1260 
1261     return NGX_CONF_OK;
1262 }
1263 
1264 
1265 static char *
1266 ngx_stream_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1267 {
1268     ngx_stream_log_main_conf_t *lmcf = conf;
1269 
1270     ngx_str_t             *value;
1271     ngx_uint_t             i;
1272     ngx_stream_log_fmt_t  *fmt;
1273 
1274     value = cf->args->elts;
1275 
1276     fmt = lmcf->formats.elts;
1277     for (i = 0; i < lmcf->formats.nelts; i++) {
1278         if (fmt[i].name.len == value[1].len
1279             && ngx_strcmp(fmt[i].name.data, value[1].data) == 0)
1280         {
1281             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1282                                "duplicate \"log_format\" name \"%V\"",
1283                                &value[1]);
1284             return NGX_CONF_ERROR;
1285         }
1286     }
1287 
1288     fmt = ngx_array_push(&lmcf->formats);
1289     if (fmt == NULL) {
1290         return NGX_CONF_ERROR;
1291     }
1292 
1293     fmt->name = value[1];
1294 
1295     fmt->flushes = ngx_array_create(cf->pool, 4, sizeof(ngx_int_t));
1296     if (fmt->flushes == NULL) {
1297         return NGX_CONF_ERROR;
1298     }
1299 
1300     fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_stream_log_op_t));
1301     if (fmt->ops == NULL) {
1302         return NGX_CONF_ERROR;
1303     }
1304 
1305     return ngx_stream_log_compile_format(cf, fmt->flushes, fmt->ops,
1306                                          cf->args, 2);
1307 }
1308 
1309 
1310 static char *
1311 ngx_stream_log_compile_format(ngx_conf_t *cf, ngx_array_t *flushes,
1312     ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s)
1313 {
1314     u_char                *data, *p, ch;
1315     size_t                 i, len;
1316     ngx_str_t             *value, var;
1317     ngx_int_t             *flush;
1318     ngx_uint_t             bracket, escape;
1319     ngx_stream_log_op_t   *op;
1320 
1321     escape = NGX_STREAM_LOG_ESCAPE_DEFAULT;
1322     value = args->elts;
1323 
1324     if (s < args->nelts && ngx_strncmp(value[s].data, "escape=", 7) == 0) {
1325         data = value[s].data + 7;
1326 
1327         if (ngx_strcmp(data, "json") == 0) {
1328             escape = NGX_STREAM_LOG_ESCAPE_JSON;
1329 
1330         } else if (ngx_strcmp(data, "none") == 0) {
1331             escape = NGX_STREAM_LOG_ESCAPE_NONE;
1332 
1333         } else if (ngx_strcmp(data, "default") != 0) {
1334             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1335                                "unknown log format escaping \"%s\"", data);
1336             return NGX_CONF_ERROR;
1337         }
1338 
1339         s++;
1340     }
1341 
1342     for ( /* void */ ; s < args->nelts; s++) {
1343 
1344         i = 0;
1345 
1346         while (i < value[s].len) {
1347 
1348             op = ngx_array_push(ops);
1349             if (op == NULL) {
1350                 return NGX_CONF_ERROR;
1351             }
1352 
1353             data = &value[s].data[i];
1354 
1355             if (value[s].data[i] == '$') {
1356 
1357                 if (++i == value[s].len) {
1358                     goto invalid;
1359                 }
1360 
1361                 if (value[s].data[i] == '{') {
1362                     bracket = 1;
1363 
1364                     if (++i == value[s].len) {
1365                         goto invalid;
1366                     }
1367 
1368                     var.data = &value[s].data[i];
1369 
1370                 } else {
1371                     bracket = 0;
1372                     var.data = &value[s].data[i];
1373                 }
1374 
1375                 for (var.len = 0; i < value[s].len; i++, var.len++) {
1376                     ch = value[s].data[i];
1377 
1378                     if (ch == '}' && bracket) {
1379                         i++;
1380                         bracket = 0;
1381                         break;
1382                     }
1383 
1384                     if ((ch >= 'A' && ch <= 'Z')
1385                         || (ch >= 'a' && ch <= 'z')
1386                         || (ch >= '0' && ch <= '9')
1387                         || ch == '_')
1388                     {
1389                         continue;
1390                     }
1391 
1392                     break;
1393                 }
1394 
1395                 if (bracket) {
1396                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1397                                        "the closing bracket in \"%V\" "
1398                                        "variable is missing", &var);
1399                     return NGX_CONF_ERROR;
1400                 }
1401 
1402                 if (var.len == 0) {
1403                     goto invalid;
1404                 }
1405 
1406                 if (ngx_stream_log_variable_compile(cf, op, &var, escape)
1407                     != NGX_OK)
1408                 {
1409                     return NGX_CONF_ERROR;
1410                 }
1411 
1412                 if (flushes) {
1413 
1414                     flush = ngx_array_push(flushes);
1415                     if (flush == NULL) {
1416                         return NGX_CONF_ERROR;
1417                     }
1418 
1419                     *flush = op->data; /* variable index */
1420                 }
1421 
1422                 continue;
1423             }
1424 
1425             i++;
1426 
1427             while (i < value[s].len && value[s].data[i] != '$') {
1428                 i++;
1429             }
1430 
1431             len = &value[s].data[i] - data;
1432 
1433             if (len) {
1434 
1435                 op->len = len;
1436                 op->getlen = NULL;
1437 
1438                 if (len <= sizeof(uintptr_t)) {
1439                     op->run = ngx_stream_log_copy_short;
1440                     op->data = 0;
1441 
1442                     while (len--) {
1443                         op->data <<= 8;
1444                         op->data |= data[len];
1445                     }
1446 
1447                 } else {
1448                     op->run = ngx_stream_log_copy_long;
1449 
1450                     p = ngx_pnalloc(cf->pool, len);
1451                     if (p == NULL) {
1452                         return NGX_CONF_ERROR;
1453                     }
1454 
1455                     ngx_memcpy(p, data, len);
1456                     op->data = (uintptr_t) p;
1457                 }
1458             }
1459         }
1460     }
1461 
1462     return NGX_CONF_OK;
1463 
1464 invalid:
1465 
1466     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%s\"", data);
1467 
1468     return NGX_CONF_ERROR;
1469 }
1470 
1471 
1472 static char *
1473 ngx_stream_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1474 {
1475     ngx_stream_log_srv_conf_t *lscf = conf;
1476 
1477     time_t       inactive, valid;
1478     ngx_str_t   *value, s;
1479     ngx_int_t    max, min_uses;
1480     ngx_uint_t   i;
1481 
1482     if (lscf->open_file_cache != NGX_CONF_UNSET_PTR) {
1483         return "is duplicate";
1484     }
1485 
1486     value = cf->args->elts;
1487 
1488     max = 0;
1489     inactive = 10;
1490     valid = 60;
1491     min_uses = 1;
1492 
1493     for (i = 1; i < cf->args->nelts; i++) {
1494 
1495         if (ngx_strncmp(value[i].data, "max=", 4) == 0) {
1496 
1497             max = ngx_atoi(value[i].data + 4, value[i].len - 4);
1498             if (max == NGX_ERROR) {
1499                 goto failed;
1500             }
1501 
1502             continue;
1503         }
1504 
1505         if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) {
1506 
1507             s.len = value[i].len - 9;
1508             s.data = value[i].data + 9;
1509 
1510             inactive = ngx_parse_time(&s, 1);
1511             if (inactive == (time_t) NGX_ERROR) {
1512                 goto failed;
1513             }
1514 
1515             continue;
1516         }
1517 
1518         if (ngx_strncmp(value[i].data, "min_uses=", 9) == 0) {
1519 
1520             min_uses = ngx_atoi(value[i].data + 9, value[i].len - 9);
1521             if (min_uses == NGX_ERROR) {
1522                 goto failed;
1523             }
1524 
1525             continue;
1526         }
1527 
1528         if (ngx_strncmp(value[i].data, "valid=", 6) == 0) {
1529 
1530             s.len = value[i].len - 6;
1531             s.data = value[i].data + 6;
1532 
1533             valid = ngx_parse_time(&s, 1);
1534             if (valid == (time_t) NGX_ERROR) {
1535                 goto failed;
1536             }
1537 
1538             continue;
1539         }
1540 
1541         if (ngx_strcmp(value[i].data, "off") == 0) {
1542 
1543             lscf->open_file_cache = NULL;
1544 
1545             continue;
1546         }
1547 
1548     failed:
1549 
1550         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1551                            "invalid \"open_log_file_cache\" parameter \"%V\"",
1552                            &value[i]);
1553         return NGX_CONF_ERROR;
1554     }
1555 
1556     if (lscf->open_file_cache == NULL) {
1557         return NGX_CONF_OK;
1558     }
1559 
1560     if (max == 0) {
1561         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1562                         "\"open_log_file_cache\" must have \"max\" parameter");
1563         return NGX_CONF_ERROR;
1564     }
1565 
1566     lscf->open_file_cache = ngx_open_file_cache_init(cf->pool, max, inactive);
1567 
1568     if (lscf->open_file_cache) {
1569 
1570         lscf->open_file_cache_valid = valid;
1571         lscf->open_file_cache_min_uses = min_uses;
1572 
1573         return NGX_CONF_OK;
1574     }
1575 
1576     return NGX_CONF_ERROR;
1577 }
1578 
1579 
1580 static ngx_int_t
1581 ngx_stream_log_init(ngx_conf_t *cf)
1582 {
1583     ngx_stream_handler_pt        *h;
1584     ngx_stream_core_main_conf_t  *cmcf;
1585 
1586     cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);
1587 
1588     h = ngx_array_push(&cmcf->phases[NGX_STREAM_LOG_PHASE].handlers);
1589     if (h == NULL) {
1590         return NGX_ERROR;
1591     }
1592 
1593     *h = ngx_stream_log_handler;
1594 
1595     return NGX_OK;
1596 }