src/stream/ngx_stream_log_module.c - nginx-1.31.4 nginx/ @ 8d9666701

Global variables defined

Data types defined

Functions defined

Macros defined

Source code


  1. /*
  2. * Copyright (C) Igor Sysoev
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>
  7. #include <ngx_stream.h>

  8. #if (NGX_ZLIB)
  9. #include <zlib.h>
  10. #endif


  11. typedef struct ngx_stream_log_op_s  ngx_stream_log_op_t;

  12. typedef u_char *(*ngx_stream_log_op_run_pt) (ngx_stream_session_t *s,
  13.     u_char *buf, u_char *end, ngx_stream_log_op_t *op);

  14. typedef size_t (*ngx_stream_log_op_getlen_pt) (ngx_stream_session_t *s,
  15.     uintptr_t data);


  16. struct ngx_stream_log_op_s {
  17.     size_t                       len;
  18.     ngx_stream_log_op_getlen_pt  getlen;
  19.     ngx_stream_log_op_run_pt     run;
  20.     uintptr_t                    data;
  21. };


  22. typedef struct {
  23.     ngx_str_t                    name;
  24.     ngx_array_t                 *flushes;
  25.     ngx_array_t                 *ops;        /* array of ngx_stream_log_op_t */
  26. } ngx_stream_log_fmt_t;


  27. typedef struct {
  28.     ngx_array_t                  formats;    /* array of ngx_stream_log_fmt_t */
  29. } ngx_stream_log_main_conf_t;


  30. typedef struct {
  31.     u_char                      *start;
  32.     u_char                      *pos;
  33.     u_char                      *last;

  34.     ngx_event_t                 *event;
  35.     ngx_msec_t                   flush;
  36.     ngx_int_t                    gzip;
  37. } ngx_stream_log_buf_t;


  38. typedef struct {
  39.     ngx_array_t                 *lengths;
  40.     ngx_array_t                 *values;
  41. } ngx_stream_log_script_t;


  42. typedef struct {
  43.     ngx_open_file_t             *file;
  44.     ngx_stream_log_script_t     *script;
  45.     time_t                       disk_full_time;
  46.     time_t                       error_log_time;
  47.     ngx_syslog_peer_t           *syslog_peer;
  48.     ngx_stream_log_fmt_t        *format;
  49.     ngx_stream_complex_value_t  *filter;
  50. } ngx_stream_log_t;


  51. typedef struct {
  52.     ngx_array_t                 *logs;       /* array of ngx_stream_log_t */

  53.     ngx_open_file_cache_t       *open_file_cache;
  54.     time_t                       open_file_cache_valid;
  55.     ngx_uint_t                   open_file_cache_min_uses;

  56.     ngx_uint_t                   off;        /* unsigned  off:1 */
  57. } ngx_stream_log_srv_conf_t;


  58. typedef struct {
  59.     ngx_str_t                    name;
  60.     size_t                       len;
  61.     ngx_stream_log_op_run_pt     run;
  62. } ngx_stream_log_var_t;


  63. #define NGX_STREAM_LOG_ESCAPE_DEFAULT  0
  64. #define NGX_STREAM_LOG_ESCAPE_JSON     1
  65. #define NGX_STREAM_LOG_ESCAPE_NONE     2


  66. static void ngx_stream_log_write(ngx_stream_session_t *s, ngx_stream_log_t *log,
  67.     u_char *buf, size_t len);
  68. static ssize_t ngx_stream_log_script_write(ngx_stream_session_t *s,
  69.     ngx_stream_log_script_t *script, u_char **name, u_char *buf, size_t len);

  70. #if (NGX_ZLIB)
  71. static ssize_t ngx_stream_log_gzip(ngx_fd_t fd, u_char *buf, size_t len,
  72.     ngx_int_t level, ngx_log_t *log);

  73. static void *ngx_stream_log_gzip_alloc(void *opaque, u_int items, u_int size);
  74. static void ngx_stream_log_gzip_free(void *opaque, void *address);
  75. #endif

  76. static void ngx_stream_log_flush(ngx_open_file_t *file, ngx_log_t *log);
  77. static void ngx_stream_log_flush_handler(ngx_event_t *ev);

  78. static ngx_int_t ngx_stream_log_variable_compile(ngx_conf_t *cf,
  79.     ngx_stream_log_op_t *op, ngx_str_t *value, ngx_uint_t escape);
  80. static size_t ngx_stream_log_variable_getlen(ngx_stream_session_t *s,
  81.     uintptr_t data);
  82. static u_char *ngx_stream_log_variable(ngx_stream_session_t *s, u_char *buf,
  83.     u_char *end, ngx_stream_log_op_t *op);
  84. static uintptr_t ngx_stream_log_escape(u_char *dst, u_char *src, size_t size);
  85. static size_t ngx_stream_log_json_variable_getlen(ngx_stream_session_t *s,
  86.     uintptr_t data);
  87. static u_char *ngx_stream_log_json_variable(ngx_stream_session_t *s,
  88.     u_char *buf, u_char *end, ngx_stream_log_op_t *op);
  89. static size_t ngx_stream_log_unescaped_variable_getlen(ngx_stream_session_t *s,
  90.     uintptr_t data);
  91. static u_char *ngx_stream_log_unescaped_variable(ngx_stream_session_t *s,
  92.     u_char *buf, u_char *end, ngx_stream_log_op_t *op);

  93. static ngx_int_t ngx_stream_log_check_length(ngx_stream_session_t *s,
  94.     u_char *buf, u_char *end, size_t len);


  95. static void *ngx_stream_log_create_main_conf(ngx_conf_t *cf);
  96. static void *ngx_stream_log_create_srv_conf(ngx_conf_t *cf);
  97. static char *ngx_stream_log_merge_srv_conf(ngx_conf_t *cf, void *parent,
  98.     void *child);
  99. static char *ngx_stream_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd,
  100.     void *conf);
  101. static char *ngx_stream_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd,
  102.     void *conf);
  103. static char *ngx_stream_log_compile_format(ngx_conf_t *cf,
  104.     ngx_array_t *flushes, ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s);
  105. static char *ngx_stream_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd,
  106.     void *conf);
  107. static ngx_int_t ngx_stream_log_init(ngx_conf_t *cf);


  108. static ngx_command_t  ngx_stream_log_commands[] = {

  109.     { ngx_string("log_format"),
  110.       NGX_STREAM_MAIN_CONF|NGX_CONF_2MORE,
  111.       ngx_stream_log_set_format,
  112.       NGX_STREAM_MAIN_CONF_OFFSET,
  113.       0,
  114.       NULL },

  115.     { ngx_string("access_log"),
  116.       NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_1MORE,
  117.       ngx_stream_log_set_log,
  118.       NGX_STREAM_SRV_CONF_OFFSET,
  119.       0,
  120.       NULL },

  121.     { ngx_string("open_log_file_cache"),
  122.       NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1234,
  123.       ngx_stream_log_open_file_cache,
  124.       NGX_STREAM_SRV_CONF_OFFSET,
  125.       0,
  126.       NULL },

  127.       ngx_null_command
  128. };


  129. static ngx_stream_module_t  ngx_stream_log_module_ctx = {
  130.     NULL,                                  /* preconfiguration */
  131.     ngx_stream_log_init,                   /* postconfiguration */

  132.     ngx_stream_log_create_main_conf,       /* create main configuration */
  133.     NULL,                                  /* init main configuration */

  134.     ngx_stream_log_create_srv_conf,        /* create server configuration */
  135.     ngx_stream_log_merge_srv_conf          /* merge server configuration */
  136. };


  137. ngx_module_t  ngx_stream_log_module = {
  138.     NGX_MODULE_V1,
  139.     &ngx_stream_log_module_ctx,            /* module context */
  140.     ngx_stream_log_commands,               /* module directives */
  141.     NGX_STREAM_MODULE,                     /* module type */
  142.     NULL,                                  /* init master */
  143.     NULL,                                  /* init module */
  144.     NULL,                                  /* init process */
  145.     NULL,                                  /* init thread */
  146.     NULL,                                  /* exit thread */
  147.     NULL,                                  /* exit process */
  148.     NULL,                                  /* exit master */
  149.     NGX_MODULE_V1_PADDING
  150. };


  151. static ngx_int_t
  152. ngx_stream_log_handler(ngx_stream_session_t *s)
  153. {
  154.     u_char                     *line, *p, *end;
  155.     size_t                      len, size;
  156.     ssize_t                     n;
  157.     ngx_str_t                   val;
  158.     ngx_uint_t                  i, l;
  159.     ngx_stream_log_t           *log;
  160.     ngx_stream_log_op_t        *op;
  161.     ngx_stream_log_buf_t       *buffer;
  162.     ngx_stream_log_srv_conf_t  *lscf;

  163.     ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
  164.                    "stream log handler");

  165.     lscf = ngx_stream_get_module_srv_conf(s, ngx_stream_log_module);

  166.     if (lscf->off || lscf->logs == NULL) {
  167.         return NGX_OK;
  168.     }

  169.     log = lscf->logs->elts;
  170.     for (l = 0; l < lscf->logs->nelts; l++) {

  171.         if (log[l].filter) {
  172.             if (ngx_stream_complex_value(s, log[l].filter, &val) != NGX_OK) {
  173.                 return NGX_ERROR;
  174.             }

  175.             if (val.len == 0 || (val.len == 1 && val.data[0] == '0')) {
  176.                 continue;
  177.             }
  178.         }

  179.         if (ngx_time() == log[l].disk_full_time) {

  180.             /*
  181.              * on FreeBSD writing to a full filesystem with enabled softupdates
  182.              * may block process for much longer time than writing to non-full
  183.              * filesystem, so we skip writing to a log for one second
  184.              */

  185.             continue;
  186.         }

  187.         ngx_stream_script_flush_no_cacheable_variables(s,
  188.                                                        log[l].format->flushes);

  189.         len = 0;
  190.         op = log[l].format->ops->elts;
  191.         for (i = 0; i < log[l].format->ops->nelts; i++) {
  192.             if (op[i].len == 0) {
  193.                 len += op[i].getlen(s, op[i].data);

  194.             } else {
  195.                 len += op[i].len;
  196.             }
  197.         }

  198.         len += NGX_LINEFEED_SIZE;

  199.         if (log[l].syslog_peer) {

  200.             /* length of syslog's PRI and HEADER message parts */
  201.             len += sizeof("<255>Jan 01 00:00:00 ") - 1
  202.                    + ngx_cycle->hostname.len + 1
  203.                    + log[l].syslog_peer->tag.len + 2;

  204.             goto alloc_line;
  205.         }

  206.         buffer = log[l].file ? log[l].file->data : NULL;

  207.         if (buffer) {

  208.             if (len > (size_t) (buffer->last - buffer->pos)) {

  209.                 ngx_stream_log_write(s, &log[l], buffer->start,
  210.                                      buffer->pos - buffer->start);

  211.                 buffer->pos = buffer->start;
  212.             }

  213.             if (len <= (size_t) (buffer->last - buffer->pos)) {

  214.                 p = buffer->pos;
  215.                 end = p + len - NGX_LINEFEED_SIZE;

  216.                 if (buffer->event && p == buffer->start) {
  217.                     ngx_add_timer(buffer->event, buffer->flush);
  218.                 }

  219.                 for (i = 0; i < log[l].format->ops->nelts && p; i++) {
  220.                     p = op[i].run(s, p, end, &op[i]);
  221.                 }

  222.                 if (p == NULL) {
  223.                     return NGX_ERROR;
  224.                 }

  225.                 ngx_linefeed(p);

  226.                 buffer->pos = p;

  227.                 continue;
  228.             }

  229.             if (buffer->event && buffer->event->timer_set) {
  230.                 ngx_del_timer(buffer->event);
  231.             }
  232.         }

  233.     alloc_line:

  234.         line = ngx_pnalloc(s->connection->pool, len);
  235.         if (line == NULL) {
  236.             return NGX_ERROR;
  237.         }

  238.         p = line;
  239.         end = p + len - NGX_LINEFEED_SIZE;

  240.         if (log[l].syslog_peer) {
  241.             p = ngx_syslog_add_header(log[l].syslog_peer, line);
  242.         }

  243.         for (i = 0; i < log[l].format->ops->nelts && p; i++) {
  244.             p = op[i].run(s, p, end, &op[i]);
  245.         }

  246.         if (p == NULL) {
  247.             return NGX_ERROR;
  248.         }

  249.         if (log[l].syslog_peer) {

  250.             size = p - line;

  251.             n = ngx_syslog_send(log[l].syslog_peer, line, size);

  252.             if (n < 0) {
  253.                 ngx_log_error(NGX_LOG_WARN, s->connection->log, 0,
  254.                               "send() to syslog failed");

  255.             } else if ((size_t) n != size) {
  256.                 ngx_log_error(NGX_LOG_WARN, s->connection->log, 0,
  257.                               "send() to syslog has written only %z of %uz",
  258.                               n, size);
  259.             }

  260.             continue;
  261.         }

  262.         ngx_linefeed(p);

  263.         ngx_stream_log_write(s, &log[l], line, p - line);
  264.     }

  265.     return NGX_OK;
  266. }


  267. static void
  268. ngx_stream_log_write(ngx_stream_session_t *s, ngx_stream_log_t *log,
  269.     u_char *buf, size_t len)
  270. {
  271.     u_char                *name;
  272.     time_t                 now;
  273.     ssize_t                n;
  274.     ngx_err_t              err;
  275. #if (NGX_ZLIB)
  276.     ngx_stream_log_buf_t  *buffer;
  277. #endif

  278.     if (log->script == NULL) {
  279.         name = log->file->name.data;

  280. #if (NGX_ZLIB)
  281.         buffer = log->file->data;

  282.         if (buffer && buffer->gzip) {
  283.             n = ngx_stream_log_gzip(log->file->fd, buf, len, buffer->gzip,
  284.                                     s->connection->log);
  285.         } else {
  286.             n = ngx_write_fd(log->file->fd, buf, len);
  287.         }
  288. #else
  289.         n = ngx_write_fd(log->file->fd, buf, len);
  290. #endif

  291.     } else {
  292.         name = NULL;
  293.         n = ngx_stream_log_script_write(s, log->script, &name, buf, len);
  294.     }

  295.     if (n == (ssize_t) len) {
  296.         return;
  297.     }

  298.     now = ngx_time();

  299.     if (n == -1) {
  300.         err = ngx_errno;

  301.         if (err == NGX_ENOSPC) {
  302.             log->disk_full_time = now;
  303.         }

  304.         if (now - log->error_log_time > 59) {
  305.             ngx_log_error(NGX_LOG_ALERT, s->connection->log, err,
  306.                           ngx_write_fd_n " to \"%s\" failed", name);

  307.             log->error_log_time = now;
  308.         }

  309.         return;
  310.     }

  311.     if (now - log->error_log_time > 59) {
  312.         ngx_log_error(NGX_LOG_ALERT, s->connection->log, 0,
  313.                       ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz",
  314.                       name, n, len);

  315.         log->error_log_time = now;
  316.     }
  317. }


  318. static ssize_t
  319. ngx_stream_log_script_write(ngx_stream_session_t *s,
  320.     ngx_stream_log_script_t *script, u_char **name, u_char *buf, size_t len)
  321. {
  322.     ssize_t                     n;
  323.     ngx_str_t                   log;
  324.     ngx_open_file_info_t        of;
  325.     ngx_stream_log_srv_conf_t  *lscf;

  326.     if (ngx_stream_script_run(s, &log, script->lengths->elts, 1,
  327.                               script->values->elts)
  328.         == NULL)
  329.     {
  330.         /* simulate successful logging */
  331.         return len;
  332.     }

  333.     log.data[log.len - 1] = '\0';
  334.     *name = log.data;

  335.     ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
  336.                    "stream log \"%s\"", log.data);

  337.     lscf = ngx_stream_get_module_srv_conf(s, ngx_stream_log_module);

  338.     ngx_memzero(&of, sizeof(ngx_open_file_info_t));

  339.     of.log = 1;
  340.     of.valid = lscf->open_file_cache_valid;
  341.     of.min_uses = lscf->open_file_cache_min_uses;
  342.     of.directio = NGX_OPEN_FILE_DIRECTIO_OFF;

  343.     if (ngx_open_cached_file(lscf->open_file_cache, &log, &of,
  344.                              s->connection->pool)
  345.         != NGX_OK)
  346.     {
  347.         if (of.err == 0) {
  348.             /* simulate successful logging */
  349.             return len;
  350.         }

  351.         ngx_log_error(NGX_LOG_CRIT, s->connection->log, ngx_errno,
  352.                       "%s \"%s\" failed", of.failed, log.data);
  353.         /* simulate successful logging */
  354.         return len;
  355.     }

  356.     ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
  357.                    "stream log #%d", of.fd);

  358.     n = ngx_write_fd(of.fd, buf, len);

  359.     return n;
  360. }


  361. #if (NGX_ZLIB)

  362. static ssize_t
  363. ngx_stream_log_gzip(ngx_fd_t fd, u_char *buf, size_t len, ngx_int_t level,
  364.     ngx_log_t *log)
  365. {
  366.     int          rc, wbits, memlevel;
  367.     u_char      *out;
  368.     size_t       size;
  369.     ssize_t      n;
  370.     z_stream     zstream;
  371.     ngx_err_t    err;
  372.     ngx_pool_t  *pool;

  373.     wbits = MAX_WBITS;
  374.     memlevel = MAX_MEM_LEVEL - 1;

  375.     while ((ssize_t) len < ((1 << (wbits - 1)) - 262)) {
  376.         wbits--;
  377.         memlevel--;
  378.     }

  379.     /*
  380.      * This is a formula from deflateBound() for conservative upper bound of
  381.      * compressed data plus 18 bytes of gzip wrapper.
  382.      */

  383.     size = len + ((len + 7) >> 3) + ((len + 63) >> 6) + 5 + 18;

  384.     ngx_memzero(&zstream, sizeof(z_stream));

  385.     pool = ngx_create_pool(256, log);
  386.     if (pool == NULL) {
  387.         /* simulate successful logging */
  388.         return len;
  389.     }

  390.     pool->log = log;

  391.     zstream.zalloc = ngx_stream_log_gzip_alloc;
  392.     zstream.zfree = ngx_stream_log_gzip_free;
  393.     zstream.opaque = pool;

  394.     out = ngx_pnalloc(pool, size);
  395.     if (out == NULL) {
  396.         goto done;
  397.     }

  398.     zstream.next_in = buf;
  399.     zstream.avail_in = len;
  400.     zstream.next_out = out;
  401.     zstream.avail_out = size;

  402.     rc = deflateInit2(&zstream, (int) level, Z_DEFLATED, wbits + 16, memlevel,
  403.                       Z_DEFAULT_STRATEGY);

  404.     if (rc != Z_OK) {
  405.         ngx_log_error(NGX_LOG_ALERT, log, 0, "deflateInit2() failed: %d", rc);
  406.         goto done;
  407.     }

  408.     ngx_log_debug4(NGX_LOG_DEBUG_STREAM, log, 0,
  409.                    "deflate in: ni:%p no:%p ai:%ud ao:%ud",
  410.                    zstream.next_in, zstream.next_out,
  411.                    zstream.avail_in, zstream.avail_out);

  412.     rc = deflate(&zstream, Z_FINISH);

  413.     if (rc != Z_STREAM_END) {
  414.         ngx_log_error(NGX_LOG_ALERT, log, 0,
  415.                       "deflate(Z_FINISH) failed: %d", rc);
  416.         goto done;
  417.     }

  418.     ngx_log_debug5(NGX_LOG_DEBUG_STREAM, log, 0,
  419.                    "deflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d",
  420.                    zstream.next_in, zstream.next_out,
  421.                    zstream.avail_in, zstream.avail_out,
  422.                    rc);

  423.     size -= zstream.avail_out;

  424.     rc = deflateEnd(&zstream);

  425.     if (rc != Z_OK) {
  426.         ngx_log_error(NGX_LOG_ALERT, log, 0, "deflateEnd() failed: %d", rc);
  427.         goto done;
  428.     }

  429.     n = ngx_write_fd(fd, out, size);

  430.     if (n != (ssize_t) size) {
  431.         err = (n == -1) ? ngx_errno : 0;

  432.         ngx_destroy_pool(pool);

  433.         ngx_set_errno(err);
  434.         return -1;
  435.     }

  436. done:

  437.     ngx_destroy_pool(pool);

  438.     /* simulate successful logging */
  439.     return len;
  440. }


  441. static void *
  442. ngx_stream_log_gzip_alloc(void *opaque, u_int items, u_int size)
  443. {
  444.     ngx_pool_t *pool = opaque;

  445.     ngx_log_debug2(NGX_LOG_DEBUG_STREAM, pool->log, 0,
  446.                    "gzip alloc: n:%ud s:%ud", items, size);

  447.     return ngx_palloc(pool, items * size);
  448. }


  449. static void
  450. ngx_stream_log_gzip_free(void *opaque, void *address)
  451. {
  452. #if 0
  453.     ngx_pool_t *pool = opaque;

  454.     ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pool->log, 0,
  455.                    "gzip free: %p", address);
  456. #endif
  457. }

  458. #endif


  459. static void
  460. ngx_stream_log_flush(ngx_open_file_t *file, ngx_log_t *log)
  461. {
  462.     size_t                 len;
  463.     ssize_t                n;
  464.     ngx_stream_log_buf_t  *buffer;

  465.     buffer = file->data;

  466.     len = buffer->pos - buffer->start;

  467.     if (len == 0) {
  468.         return;
  469.     }

  470. #if (NGX_ZLIB)
  471.     if (buffer->gzip) {
  472.         n = ngx_stream_log_gzip(file->fd, buffer->start, len, buffer->gzip,
  473.                                 log);
  474.     } else {
  475.         n = ngx_write_fd(file->fd, buffer->start, len);
  476.     }
  477. #else
  478.     n = ngx_write_fd(file->fd, buffer->start, len);
  479. #endif

  480.     if (n == -1) {
  481.         ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
  482.                       ngx_write_fd_n " to \"%s\" failed",
  483.                       file->name.data);

  484.     } else if ((size_t) n != len) {
  485.         ngx_log_error(NGX_LOG_ALERT, log, 0,
  486.                       ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz",
  487.                       file->name.data, n, len);
  488.     }

  489.     buffer->pos = buffer->start;

  490.     if (buffer->event && buffer->event->timer_set) {
  491.         ngx_del_timer(buffer->event);
  492.     }
  493. }


  494. static void
  495. ngx_stream_log_flush_handler(ngx_event_t *ev)
  496. {
  497.     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0,
  498.                    "stream log buffer flush handler");

  499.     ngx_stream_log_flush(ev->data, ev->log);
  500. }


  501. static u_char *
  502. ngx_stream_log_copy_short(ngx_stream_session_t *s, u_char *buf, u_char *end,
  503.     ngx_stream_log_op_t *op)
  504. {
  505.     size_t     len;
  506.     uintptr_t  data;

  507.     len = op->len;
  508.     data = op->data;

  509.     if (ngx_stream_log_check_length(s, buf, end, len) != NGX_OK) {
  510.         return NULL;
  511.     }

  512.     while (len--) {
  513.         *buf++ = (u_char) (data & 0xff);
  514.         data >>= 8;
  515.     }

  516.     return buf;
  517. }


  518. static u_char *
  519. ngx_stream_log_copy_long(ngx_stream_session_t *s, u_char *buf, u_char *end,
  520.     ngx_stream_log_op_t *op)
  521. {
  522.     if (ngx_stream_log_check_length(s, buf, end, op->len) != NGX_OK) {
  523.         return NULL;
  524.     }

  525.     return ngx_cpymem(buf, (u_char *) op->data, op->len);
  526. }


  527. static ngx_int_t
  528. ngx_stream_log_variable_compile(ngx_conf_t *cf, ngx_stream_log_op_t *op,
  529.     ngx_str_t *value, ngx_uint_t escape)
  530. {
  531.     ngx_int_t  index;

  532.     index = ngx_stream_get_variable_index(cf, value);
  533.     if (index == NGX_ERROR) {
  534.         return NGX_ERROR;
  535.     }

  536.     op->len = 0;

  537.     switch (escape) {
  538.     case NGX_STREAM_LOG_ESCAPE_JSON:
  539.         op->getlen = ngx_stream_log_json_variable_getlen;
  540.         op->run = ngx_stream_log_json_variable;
  541.         break;

  542.     case NGX_STREAM_LOG_ESCAPE_NONE:
  543.         op->getlen = ngx_stream_log_unescaped_variable_getlen;
  544.         op->run = ngx_stream_log_unescaped_variable;
  545.         break;

  546.     default: /* NGX_STREAM_LOG_ESCAPE_DEFAULT */
  547.         op->getlen = ngx_stream_log_variable_getlen;
  548.         op->run = ngx_stream_log_variable;
  549.     }

  550.     op->data = index;

  551.     return NGX_OK;
  552. }


  553. static size_t
  554. ngx_stream_log_variable_getlen(ngx_stream_session_t *s, uintptr_t data)
  555. {
  556.     uintptr_t                     len;
  557.     ngx_stream_variable_value_t  *value;

  558.     value = ngx_stream_get_indexed_variable(s, data);

  559.     if (value == NULL || value->not_found) {
  560.         return 1;
  561.     }

  562.     len = ngx_stream_log_escape(NULL, value->data, value->len);

  563.     value->escape = len ? 1 : 0;

  564.     return value->len + len * 3;
  565. }


  566. static u_char *
  567. ngx_stream_log_variable(ngx_stream_session_t *s, u_char *buf, u_char *end,
  568.     ngx_stream_log_op_t *op)
  569. {
  570.     uintptr_t                     len;
  571.     ngx_stream_variable_value_t  *value;

  572.     value = ngx_stream_get_indexed_variable(s, op->data);

  573.     if (value == NULL || value->not_found) {
  574.         if (ngx_stream_log_check_length(s, buf, end, 1) != NGX_OK) {
  575.             return NULL;
  576.         }

  577.         *buf = '-';
  578.         return buf + 1;
  579.     }

  580.     if (value->escape == 0) {
  581.         if (ngx_stream_log_check_length(s, buf, end, value->len) != NGX_OK) {
  582.             return NULL;
  583.         }

  584.         return ngx_cpymem(buf, value->data, value->len);

  585.     } else {
  586.         len = ngx_stream_log_escape(NULL, value->data, value->len);

  587.         if (ngx_stream_log_check_length(s, buf, end, value->len + len * 3)
  588.             != NGX_OK)
  589.         {
  590.             return NULL;
  591.         }

  592.         return (u_char *) ngx_stream_log_escape(buf, value->data, value->len);
  593.     }
  594. }


  595. static uintptr_t
  596. ngx_stream_log_escape(u_char *dst, u_char *src, size_t size)
  597. {
  598.     ngx_uint_t      n;
  599.     static u_char   hex[] = "0123456789ABCDEF";

  600.     static uint32_t   escape[] = {
  601.         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */

  602.                     /* ?>=< ;:98 7654 3210  /.-, +*)( '&%$ #"!  */
  603.         0x00000004, /* 0000 0000 0000 0000  0000 0000 0000 0100 */

  604.                     /* _^]\ [ZYX WVUT SRQP  ONML KJIH GFED CBA@ */
  605.         0x10000000, /* 0001 0000 0000 0000  0000 0000 0000 0000 */

  606.                     /*  ~}| {zyx wvut srqp  onml kjih gfed cba` */
  607.         0x80000000, /* 1000 0000 0000 0000  0000 0000 0000 0000 */

  608.         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
  609.         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
  610.         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
  611.         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
  612.     };


  613.     if (dst == NULL) {

  614.         /* find the number of the characters to be escaped */

  615.         n = 0;

  616.         while (size) {
  617.             if (escape[*src >> 5] & (1U << (*src & 0x1f))) {
  618.                 n++;
  619.             }
  620.             src++;
  621.             size--;
  622.         }

  623.         return (uintptr_t) n;
  624.     }

  625.     while (size) {
  626.         if (escape[*src >> 5] & (1U << (*src & 0x1f))) {
  627.             *dst++ = '\\';
  628.             *dst++ = 'x';
  629.             *dst++ = hex[*src >> 4];
  630.             *dst++ = hex[*src & 0xf];
  631.             src++;

  632.         } else {
  633.             *dst++ = *src++;
  634.         }
  635.         size--;
  636.     }

  637.     return (uintptr_t) dst;
  638. }


  639. static size_t
  640. ngx_stream_log_json_variable_getlen(ngx_stream_session_t *s, uintptr_t data)
  641. {
  642.     uintptr_t                     len;
  643.     ngx_stream_variable_value_t  *value;

  644.     value = ngx_stream_get_indexed_variable(s, data);

  645.     if (value == NULL || value->not_found) {
  646.         return 0;
  647.     }

  648.     len = ngx_escape_json(NULL, value->data, value->len);

  649.     value->escape = len ? 1 : 0;

  650.     return value->len + len;
  651. }


  652. static u_char *
  653. ngx_stream_log_json_variable(ngx_stream_session_t *s, u_char *buf, u_char *end,
  654.     ngx_stream_log_op_t *op)
  655. {
  656.     uintptr_t                     len;
  657.     ngx_stream_variable_value_t  *value;

  658.     value = ngx_stream_get_indexed_variable(s, op->data);

  659.     if (value == NULL || value->not_found) {
  660.         return buf;
  661.     }

  662.     if (value->escape == 0) {
  663.         if (ngx_stream_log_check_length(s, buf, end, value->len) != NGX_OK) {
  664.             return NULL;
  665.         }

  666.         return ngx_cpymem(buf, value->data, value->len);

  667.     } else {
  668.         len = ngx_escape_json(NULL, value->data, value->len);

  669.         if (ngx_stream_log_check_length(s, buf, end, value->len + len)
  670.             != NGX_OK)
  671.         {
  672.             return NULL;
  673.         }

  674.         return (u_char *) ngx_escape_json(buf, value->data, value->len);
  675.     }
  676. }


  677. static size_t
  678. ngx_stream_log_unescaped_variable_getlen(ngx_stream_session_t *s,
  679.     uintptr_t data)
  680. {
  681.     ngx_stream_variable_value_t  *value;

  682.     value = ngx_stream_get_indexed_variable(s, data);

  683.     if (value == NULL || value->not_found) {
  684.         return 0;
  685.     }

  686.     value->escape = 0;

  687.     return value->len;
  688. }


  689. static u_char *
  690. ngx_stream_log_unescaped_variable(ngx_stream_session_t *s, u_char *buf,
  691.     u_char *end, ngx_stream_log_op_t *op)
  692. {
  693.     ngx_stream_variable_value_t  *value;

  694.     value = ngx_stream_get_indexed_variable(s, op->data);

  695.     if (value == NULL || value->not_found) {
  696.         return buf;
  697.     }

  698.     if (ngx_stream_log_check_length(s, buf, end, value->len) != NGX_OK) {
  699.         return NULL;
  700.     }

  701.     return ngx_cpymem(buf, value->data, value->len);
  702. }


  703. static ngx_int_t
  704. ngx_stream_log_check_length(ngx_stream_session_t *s, u_char *buf, u_char *end,
  705.     size_t len)
  706. {
  707.     if (end - buf < (ssize_t) len) {
  708.         ngx_log_error(NGX_LOG_ALERT, s->connection->log, 0,
  709.                       "no buffer space in log script copy");
  710.         return NGX_ERROR;
  711.     }

  712.     return NGX_OK;
  713. }


  714. static void *
  715. ngx_stream_log_create_main_conf(ngx_conf_t *cf)
  716. {
  717.     ngx_stream_log_main_conf_t  *conf;

  718.     conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_log_main_conf_t));
  719.     if (conf == NULL) {
  720.         return NULL;
  721.     }

  722.     if (ngx_array_init(&conf->formats, cf->pool, 4,
  723.                        sizeof(ngx_stream_log_fmt_t))
  724.         != NGX_OK)
  725.     {
  726.         return NULL;
  727.     }

  728.     return conf;
  729. }


  730. static void *
  731. ngx_stream_log_create_srv_conf(ngx_conf_t *cf)
  732. {
  733.     ngx_stream_log_srv_conf_t  *conf;

  734.     conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_log_srv_conf_t));
  735.     if (conf == NULL) {
  736.         return NULL;
  737.     }

  738.     conf->open_file_cache = NGX_CONF_UNSET_PTR;

  739.     return conf;
  740. }


  741. static char *
  742. ngx_stream_log_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
  743. {
  744.     ngx_stream_log_srv_conf_t *prev = parent;
  745.     ngx_stream_log_srv_conf_t *conf = child;

  746.     if (conf->open_file_cache == NGX_CONF_UNSET_PTR) {

  747.         conf->open_file_cache = prev->open_file_cache;
  748.         conf->open_file_cache_valid = prev->open_file_cache_valid;
  749.         conf->open_file_cache_min_uses = prev->open_file_cache_min_uses;

  750.         if (conf->open_file_cache == NGX_CONF_UNSET_PTR) {
  751.             conf->open_file_cache = NULL;
  752.         }
  753.     }

  754.     if (conf->logs || conf->off) {
  755.         return NGX_CONF_OK;
  756.     }

  757.     conf->logs = prev->logs;
  758.     conf->off = prev->off;

  759.     return NGX_CONF_OK;
  760. }


  761. static char *
  762. ngx_stream_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  763. {
  764.     ngx_stream_log_srv_conf_t *lscf = conf;

  765.     ssize_t                              size;
  766.     ngx_int_t                            gzip;
  767.     ngx_uint_t                           i, n;
  768.     ngx_msec_t                           flush;
  769.     ngx_str_t                           *value, name, s;
  770.     ngx_stream_log_t                    *log;
  771.     ngx_syslog_peer_t                   *peer;
  772.     ngx_stream_log_buf_t                *buffer;
  773.     ngx_stream_log_fmt_t                *fmt;
  774.     ngx_stream_script_compile_t          sc;
  775.     ngx_stream_log_main_conf_t          *lmcf;
  776.     ngx_stream_compile_complex_value_t   ccv;

  777.     value = cf->args->elts;

  778.     if (ngx_strcmp(value[1].data, "off") == 0) {
  779.         lscf->off = 1;
  780.         if (cf->args->nelts == 2) {
  781.             return NGX_CONF_OK;
  782.         }

  783.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  784.                            "invalid parameter \"%V\"", &value[2]);
  785.         return NGX_CONF_ERROR;
  786.     }

  787.     if (lscf->logs == NULL) {
  788.         lscf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_stream_log_t));
  789.         if (lscf->logs == NULL) {
  790.             return NGX_CONF_ERROR;
  791.         }
  792.     }

  793.     lmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_log_module);

  794.     log = ngx_array_push(lscf->logs);
  795.     if (log == NULL) {
  796.         return NGX_CONF_ERROR;
  797.     }

  798.     ngx_memzero(log, sizeof(ngx_stream_log_t));


  799.     if (ngx_strncmp(value[1].data, "syslog:", 7) == 0) {

  800.         peer = ngx_pcalloc(cf->pool, sizeof(ngx_syslog_peer_t));
  801.         if (peer == NULL) {
  802.             return NGX_CONF_ERROR;
  803.         }

  804.         if (ngx_syslog_process_conf(cf, peer) != NGX_CONF_OK) {
  805.             return NGX_CONF_ERROR;
  806.         }

  807.         log->syslog_peer = peer;

  808.         goto process_formats;
  809.     }

  810.     n = ngx_stream_script_variables_count(&value[1]);

  811.     if (n == 0) {
  812.         log->file = ngx_conf_open_file(cf->cycle, &value[1]);
  813.         if (log->file == NULL) {
  814.             return NGX_CONF_ERROR;
  815.         }

  816.     } else {
  817.         if (ngx_conf_full_name(cf->cycle, &value[1], 0) != NGX_OK) {
  818.             return NGX_CONF_ERROR;
  819.         }

  820.         log->script = ngx_pcalloc(cf->pool, sizeof(ngx_stream_log_script_t));
  821.         if (log->script == NULL) {
  822.             return NGX_CONF_ERROR;
  823.         }

  824.         ngx_memzero(&sc, sizeof(ngx_stream_script_compile_t));

  825.         sc.cf = cf;
  826.         sc.source = &value[1];
  827.         sc.lengths = &log->script->lengths;
  828.         sc.values = &log->script->values;
  829.         sc.variables = n;
  830.         sc.complete_lengths = 1;
  831.         sc.complete_values = 1;

  832.         if (ngx_stream_script_compile(&sc) != NGX_OK) {
  833.             return NGX_CONF_ERROR;
  834.         }
  835.     }

  836. process_formats:

  837.     if (cf->args->nelts >= 3) {
  838.         name = value[2];

  839.     } else {
  840.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  841.                            "log format is not specified");
  842.         return NGX_CONF_ERROR;
  843.     }

  844.     fmt = lmcf->formats.elts;
  845.     for (i = 0; i < lmcf->formats.nelts; i++) {
  846.         if (fmt[i].name.len == name.len
  847.             && ngx_strcasecmp(fmt[i].name.data, name.data) == 0)
  848.         {
  849.             log->format = &fmt[i];
  850.             break;
  851.         }
  852.     }

  853.     if (log->format == NULL) {
  854.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  855.                            "unknown log format \"%V\"", &name);
  856.         return NGX_CONF_ERROR;
  857.     }

  858.     size = 0;
  859.     flush = 0;
  860.     gzip = 0;

  861.     for (i = 3; i < cf->args->nelts; i++) {

  862.         if (ngx_strncmp(value[i].data, "buffer=", 7) == 0) {
  863.             s.len = value[i].len - 7;
  864.             s.data = value[i].data + 7;

  865.             size = ngx_parse_size(&s);

  866.             if (size == NGX_ERROR || size == 0) {
  867.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  868.                                    "invalid buffer size \"%V\"", &s);
  869.                 return NGX_CONF_ERROR;
  870.             }

  871.             continue;
  872.         }

  873.         if (ngx_strncmp(value[i].data, "flush=", 6) == 0) {
  874.             s.len = value[i].len - 6;
  875.             s.data = value[i].data + 6;

  876.             flush = ngx_parse_time(&s, 0);

  877.             if (flush == (ngx_msec_t) NGX_ERROR || flush == 0) {
  878.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  879.                                    "invalid flush time \"%V\"", &s);
  880.                 return NGX_CONF_ERROR;
  881.             }

  882.             continue;
  883.         }

  884.         if (ngx_strncmp(value[i].data, "gzip", 4) == 0
  885.             && (value[i].len == 4 || value[i].data[4] == '='))
  886.         {
  887. #if (NGX_ZLIB)
  888.             if (size == 0) {
  889.                 size = 64 * 1024;
  890.             }

  891.             if (value[i].len == 4) {
  892.                 gzip = Z_BEST_SPEED;
  893.                 continue;
  894.             }

  895.             s.len = value[i].len - 5;
  896.             s.data = value[i].data + 5;

  897.             gzip = ngx_atoi(s.data, s.len);

  898.             if (gzip < 1 || gzip > 9) {
  899.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  900.                                    "invalid compression level \"%V\"", &s);
  901.                 return NGX_CONF_ERROR;
  902.             }

  903.             continue;

  904. #else
  905.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  906.                                "nginx was built without zlib support");
  907.             return NGX_CONF_ERROR;
  908. #endif
  909.         }

  910.         if (ngx_strncmp(value[i].data, "if=", 3) == 0) {
  911.             s.len = value[i].len - 3;
  912.             s.data = value[i].data + 3;

  913.             ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t));

  914.             ccv.cf = cf;
  915.             ccv.value = &s;
  916.             ccv.complex_value = ngx_palloc(cf->pool,
  917.                                            sizeof(ngx_stream_complex_value_t));
  918.             if (ccv.complex_value == NULL) {
  919.                 return NGX_CONF_ERROR;
  920.             }

  921.             if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) {
  922.                 return NGX_CONF_ERROR;
  923.             }

  924.             log->filter = ccv.complex_value;

  925.             continue;
  926.         }

  927.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  928.                            "invalid parameter \"%V\"", &value[i]);
  929.         return NGX_CONF_ERROR;
  930.     }

  931.     if (flush && size == 0) {
  932.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  933.                            "no buffer is defined for access_log \"%V\"",
  934.                            &value[1]);
  935.         return NGX_CONF_ERROR;
  936.     }

  937.     if (size) {

  938.         if (log->script) {
  939.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  940.                                "buffered logs cannot have variables in name");
  941.             return NGX_CONF_ERROR;
  942.         }

  943.         if (log->syslog_peer) {
  944.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  945.                                "logs to syslog cannot be buffered");
  946.             return NGX_CONF_ERROR;
  947.         }

  948.         if (log->file->data) {
  949.             buffer = log->file->data;

  950.             if (buffer->last - buffer->start != size
  951.                 || buffer->flush != flush
  952.                 || buffer->gzip != gzip)
  953.             {
  954.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  955.                                    "access_log \"%V\" already defined "
  956.                                    "with conflicting parameters",
  957.                                    &value[1]);
  958.                 return NGX_CONF_ERROR;
  959.             }

  960.             return NGX_CONF_OK;
  961.         }

  962.         buffer = ngx_pcalloc(cf->pool, sizeof(ngx_stream_log_buf_t));
  963.         if (buffer == NULL) {
  964.             return NGX_CONF_ERROR;
  965.         }

  966.         buffer->start = ngx_pnalloc(cf->pool, size);
  967.         if (buffer->start == NULL) {
  968.             return NGX_CONF_ERROR;
  969.         }

  970.         buffer->pos = buffer->start;
  971.         buffer->last = buffer->start + size;

  972.         if (flush) {
  973.             buffer->event = ngx_pcalloc(cf->pool, sizeof(ngx_event_t));
  974.             if (buffer->event == NULL) {
  975.                 return NGX_CONF_ERROR;
  976.             }

  977.             buffer->event->data = log->file;
  978.             buffer->event->handler = ngx_stream_log_flush_handler;
  979.             buffer->event->log = &cf->cycle->new_log;
  980.             buffer->event->cancelable = 1;

  981.             buffer->flush = flush;
  982.         }

  983.         buffer->gzip = gzip;

  984.         log->file->flush = ngx_stream_log_flush;
  985.         log->file->data = buffer;
  986.     }

  987.     return NGX_CONF_OK;
  988. }


  989. static char *
  990. ngx_stream_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  991. {
  992.     ngx_stream_log_main_conf_t *lmcf = conf;

  993.     ngx_str_t             *value;
  994.     ngx_uint_t             i;
  995.     ngx_stream_log_fmt_t  *fmt;

  996.     value = cf->args->elts;

  997.     fmt = lmcf->formats.elts;
  998.     for (i = 0; i < lmcf->formats.nelts; i++) {
  999.         if (fmt[i].name.len == value[1].len
  1000.             && ngx_strcmp(fmt[i].name.data, value[1].data) == 0)
  1001.         {
  1002.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1003.                                "duplicate \"log_format\" name \"%V\"",
  1004.                                &value[1]);
  1005.             return NGX_CONF_ERROR;
  1006.         }
  1007.     }

  1008.     fmt = ngx_array_push(&lmcf->formats);
  1009.     if (fmt == NULL) {
  1010.         return NGX_CONF_ERROR;
  1011.     }

  1012.     fmt->name = value[1];

  1013.     fmt->flushes = ngx_array_create(cf->pool, 4, sizeof(ngx_int_t));
  1014.     if (fmt->flushes == NULL) {
  1015.         return NGX_CONF_ERROR;
  1016.     }

  1017.     fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_stream_log_op_t));
  1018.     if (fmt->ops == NULL) {
  1019.         return NGX_CONF_ERROR;
  1020.     }

  1021.     return ngx_stream_log_compile_format(cf, fmt->flushes, fmt->ops,
  1022.                                          cf->args, 2);
  1023. }


  1024. static char *
  1025. ngx_stream_log_compile_format(ngx_conf_t *cf, ngx_array_t *flushes,
  1026.     ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s)
  1027. {
  1028.     u_char                *data, *p, ch;
  1029.     size_t                 i, len;
  1030.     ngx_str_t             *value, var;
  1031.     ngx_int_t             *flush;
  1032.     ngx_uint_t             bracket, escape;
  1033.     ngx_stream_log_op_t   *op;

  1034.     escape = NGX_STREAM_LOG_ESCAPE_DEFAULT;
  1035.     value = args->elts;

  1036.     if (s < args->nelts && ngx_strncmp(value[s].data, "escape=", 7) == 0) {
  1037.         data = value[s].data + 7;

  1038.         if (ngx_strcmp(data, "json") == 0) {
  1039.             escape = NGX_STREAM_LOG_ESCAPE_JSON;

  1040.         } else if (ngx_strcmp(data, "none") == 0) {
  1041.             escape = NGX_STREAM_LOG_ESCAPE_NONE;

  1042.         } else if (ngx_strcmp(data, "default") != 0) {
  1043.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1044.                                "unknown log format escaping \"%s\"", data);
  1045.             return NGX_CONF_ERROR;
  1046.         }

  1047.         s++;
  1048.     }

  1049.     for ( /* void */ ; s < args->nelts; s++) {

  1050.         i = 0;

  1051.         while (i < value[s].len) {

  1052.             op = ngx_array_push(ops);
  1053.             if (op == NULL) {
  1054.                 return NGX_CONF_ERROR;
  1055.             }

  1056.             data = &value[s].data[i];

  1057.             if (value[s].data[i] == '$') {

  1058.                 if (++i == value[s].len) {
  1059.                     goto invalid;
  1060.                 }

  1061.                 if (value[s].data[i] == '{') {
  1062.                     bracket = 1;

  1063.                     if (++i == value[s].len) {
  1064.                         goto invalid;
  1065.                     }

  1066.                     var.data = &value[s].data[i];

  1067.                 } else {
  1068.                     bracket = 0;
  1069.                     var.data = &value[s].data[i];
  1070.                 }

  1071.                 for (var.len = 0; i < value[s].len; i++, var.len++) {
  1072.                     ch = value[s].data[i];

  1073.                     if (ch == '}' && bracket) {
  1074.                         i++;
  1075.                         bracket = 0;
  1076.                         break;
  1077.                     }

  1078.                     if ((ch >= 'A' && ch <= 'Z')
  1079.                         || (ch >= 'a' && ch <= 'z')
  1080.                         || (ch >= '0' && ch <= '9')
  1081.                         || ch == '_')
  1082.                     {
  1083.                         continue;
  1084.                     }

  1085.                     break;
  1086.                 }

  1087.                 if (bracket) {
  1088.                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1089.                                        "the closing bracket in \"%V\" "
  1090.                                        "variable is missing", &var);
  1091.                     return NGX_CONF_ERROR;
  1092.                 }

  1093.                 if (var.len == 0) {
  1094.                     goto invalid;
  1095.                 }

  1096.                 if (ngx_stream_log_variable_compile(cf, op, &var, escape)
  1097.                     != NGX_OK)
  1098.                 {
  1099.                     return NGX_CONF_ERROR;
  1100.                 }

  1101.                 if (flushes) {

  1102.                     flush = ngx_array_push(flushes);
  1103.                     if (flush == NULL) {
  1104.                         return NGX_CONF_ERROR;
  1105.                     }

  1106.                     *flush = op->data; /* variable index */
  1107.                 }

  1108.                 continue;
  1109.             }

  1110.             i++;

  1111.             while (i < value[s].len && value[s].data[i] != '$') {
  1112.                 i++;
  1113.             }

  1114.             len = &value[s].data[i] - data;

  1115.             if (len) {

  1116.                 op->len = len;
  1117.                 op->getlen = NULL;

  1118.                 if (len <= sizeof(uintptr_t)) {
  1119.                     op->run = ngx_stream_log_copy_short;
  1120.                     op->data = 0;

  1121.                     while (len--) {
  1122.                         op->data <<= 8;
  1123.                         op->data |= data[len];
  1124.                     }

  1125.                 } else {
  1126.                     op->run = ngx_stream_log_copy_long;

  1127.                     p = ngx_pnalloc(cf->pool, len);
  1128.                     if (p == NULL) {
  1129.                         return NGX_CONF_ERROR;
  1130.                     }

  1131.                     ngx_memcpy(p, data, len);
  1132.                     op->data = (uintptr_t) p;
  1133.                 }
  1134.             }
  1135.         }
  1136.     }

  1137.     return NGX_CONF_OK;

  1138. invalid:

  1139.     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%s\"", data);

  1140.     return NGX_CONF_ERROR;
  1141. }


  1142. static char *
  1143. ngx_stream_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  1144. {
  1145.     ngx_stream_log_srv_conf_t *lscf = conf;

  1146.     time_t       inactive, valid;
  1147.     ngx_str_t   *value, s;
  1148.     ngx_int_t    max, min_uses;
  1149.     ngx_uint_t   i;

  1150.     if (lscf->open_file_cache != NGX_CONF_UNSET_PTR) {
  1151.         return "is duplicate";
  1152.     }

  1153.     value = cf->args->elts;

  1154.     max = 0;
  1155.     inactive = 10;
  1156.     valid = 60;
  1157.     min_uses = 1;

  1158.     for (i = 1; i < cf->args->nelts; i++) {

  1159.         if (ngx_strncmp(value[i].data, "max=", 4) == 0) {

  1160.             max = ngx_atoi(value[i].data + 4, value[i].len - 4);
  1161.             if (max == NGX_ERROR) {
  1162.                 goto failed;
  1163.             }

  1164.             continue;
  1165.         }

  1166.         if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) {

  1167.             s.len = value[i].len - 9;
  1168.             s.data = value[i].data + 9;

  1169.             inactive = ngx_parse_time(&s, 1);
  1170.             if (inactive == (time_t) NGX_ERROR) {
  1171.                 goto failed;
  1172.             }

  1173.             continue;
  1174.         }

  1175.         if (ngx_strncmp(value[i].data, "min_uses=", 9) == 0) {

  1176.             min_uses = ngx_atoi(value[i].data + 9, value[i].len - 9);
  1177.             if (min_uses == NGX_ERROR) {
  1178.                 goto failed;
  1179.             }

  1180.             continue;
  1181.         }

  1182.         if (ngx_strncmp(value[i].data, "valid=", 6) == 0) {

  1183.             s.len = value[i].len - 6;
  1184.             s.data = value[i].data + 6;

  1185.             valid = ngx_parse_time(&s, 1);
  1186.             if (valid == (time_t) NGX_ERROR) {
  1187.                 goto failed;
  1188.             }

  1189.             continue;
  1190.         }

  1191.         if (ngx_strcmp(value[i].data, "off") == 0) {

  1192.             lscf->open_file_cache = NULL;

  1193.             continue;
  1194.         }

  1195.     failed:

  1196.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1197.                            "invalid \"open_log_file_cache\" parameter \"%V\"",
  1198.                            &value[i]);
  1199.         return NGX_CONF_ERROR;
  1200.     }

  1201.     if (lscf->open_file_cache == NULL) {
  1202.         return NGX_CONF_OK;
  1203.     }

  1204.     if (max == 0) {
  1205.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1206.                         "\"open_log_file_cache\" must have \"max\" parameter");
  1207.         return NGX_CONF_ERROR;
  1208.     }

  1209.     lscf->open_file_cache = ngx_open_file_cache_init(cf->pool, max, inactive);

  1210.     if (lscf->open_file_cache) {

  1211.         lscf->open_file_cache_valid = valid;
  1212.         lscf->open_file_cache_min_uses = min_uses;

  1213.         return NGX_CONF_OK;
  1214.     }

  1215.     return NGX_CONF_ERROR;
  1216. }


  1217. static ngx_int_t
  1218. ngx_stream_log_init(ngx_conf_t *cf)
  1219. {
  1220.     ngx_stream_handler_pt        *h;
  1221.     ngx_stream_core_main_conf_t  *cmcf;

  1222.     cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);

  1223.     h = ngx_array_push(&cmcf->phases[NGX_STREAM_LOG_PHASE].handlers);
  1224.     if (h == NULL) {
  1225.         return NGX_ERROR;
  1226.     }

  1227.     *h = ngx_stream_log_handler;

  1228.     return NGX_OK;
  1229. }