src/stream/ngx_stream_variables.c - nginx source code

Global variables defined

Functions 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. #include <nginx.h>

  9. static ngx_stream_variable_t *ngx_stream_add_prefix_variable(ngx_conf_t *cf,
  10.     ngx_str_t *name, ngx_uint_t flags);

  11. static ngx_int_t ngx_stream_variable_binary_remote_addr(
  12.     ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data);
  13. static ngx_int_t ngx_stream_variable_remote_addr(ngx_stream_session_t *s,
  14.     ngx_stream_variable_value_t *v, uintptr_t data);
  15. static ngx_int_t ngx_stream_variable_remote_port(ngx_stream_session_t *s,
  16.     ngx_stream_variable_value_t *v, uintptr_t data);
  17. static ngx_int_t ngx_stream_variable_proxy_protocol_addr(
  18.     ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data);
  19. static ngx_int_t ngx_stream_variable_proxy_protocol_port(
  20.     ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data);
  21. static ngx_int_t ngx_stream_variable_proxy_protocol_tlv(
  22.     ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data);
  23. static ngx_int_t ngx_stream_variable_server_addr(ngx_stream_session_t *s,
  24.     ngx_stream_variable_value_t *v, uintptr_t data);
  25. static ngx_int_t ngx_stream_variable_server_port(ngx_stream_session_t *s,
  26.     ngx_stream_variable_value_t *v, uintptr_t data);
  27. static ngx_int_t ngx_stream_variable_server_name(ngx_stream_session_t *s,
  28.     ngx_stream_variable_value_t *v, uintptr_t data);
  29. static ngx_int_t ngx_stream_variable_bytes(ngx_stream_session_t *s,
  30.     ngx_stream_variable_value_t *v, uintptr_t data);
  31. static ngx_int_t ngx_stream_variable_session_time(ngx_stream_session_t *s,
  32.     ngx_stream_variable_value_t *v, uintptr_t data);
  33. static ngx_int_t ngx_stream_variable_status(ngx_stream_session_t *s,
  34.     ngx_stream_variable_value_t *v, uintptr_t data);
  35. static ngx_int_t ngx_stream_variable_connection(ngx_stream_session_t *s,
  36.     ngx_stream_variable_value_t *v, uintptr_t data);

  37. static ngx_int_t ngx_stream_variable_nginx_version(ngx_stream_session_t *s,
  38.     ngx_stream_variable_value_t *v, uintptr_t data);
  39. static ngx_int_t ngx_stream_variable_hostname(ngx_stream_session_t *s,
  40.     ngx_stream_variable_value_t *v, uintptr_t data);
  41. static ngx_int_t ngx_stream_variable_pid(ngx_stream_session_t *s,
  42.     ngx_stream_variable_value_t *v, uintptr_t data);
  43. static ngx_int_t ngx_stream_variable_msec(ngx_stream_session_t *s,
  44.     ngx_stream_variable_value_t *v, uintptr_t data);
  45. static ngx_int_t ngx_stream_variable_time_iso8601(ngx_stream_session_t *s,
  46.     ngx_stream_variable_value_t *v, uintptr_t data);
  47. static ngx_int_t ngx_stream_variable_time_local(ngx_stream_session_t *s,
  48.     ngx_stream_variable_value_t *v, uintptr_t data);
  49. static ngx_int_t ngx_stream_variable_protocol(ngx_stream_session_t *s,
  50.     ngx_stream_variable_value_t *v, uintptr_t data);


  51. static ngx_stream_variable_t  ngx_stream_core_variables[] = {

  52.     { ngx_string("binary_remote_addr"), NULL,
  53.       ngx_stream_variable_binary_remote_addr, 0, 0, 0 },

  54.     { ngx_string("remote_addr"), NULL,
  55.       ngx_stream_variable_remote_addr, 0, 0, 0 },

  56.     { ngx_string("remote_port"), NULL,
  57.       ngx_stream_variable_remote_port, 0, 0, 0 },

  58.     { ngx_string("proxy_protocol_addr"), NULL,
  59.       ngx_stream_variable_proxy_protocol_addr,
  60.       offsetof(ngx_proxy_protocol_t, src_addr), 0, 0 },

  61.     { ngx_string("proxy_protocol_port"), NULL,
  62.       ngx_stream_variable_proxy_protocol_port,
  63.       offsetof(ngx_proxy_protocol_t, src_port), 0, 0 },

  64.     { ngx_string("proxy_protocol_server_addr"), NULL,
  65.       ngx_stream_variable_proxy_protocol_addr,
  66.       offsetof(ngx_proxy_protocol_t, dst_addr), 0, 0 },

  67.     { ngx_string("proxy_protocol_server_port"), NULL,
  68.       ngx_stream_variable_proxy_protocol_port,
  69.       offsetof(ngx_proxy_protocol_t, dst_port), 0, 0 },

  70.     { ngx_string("proxy_protocol_tlv_"), NULL,
  71.       ngx_stream_variable_proxy_protocol_tlv,
  72.       0, NGX_STREAM_VAR_PREFIX, 0 },

  73.     { ngx_string("server_addr"), NULL,
  74.       ngx_stream_variable_server_addr, 0, 0, 0 },

  75.     { ngx_string("server_port"), NULL,
  76.       ngx_stream_variable_server_port, 0, 0, 0 },

  77.     { ngx_string("server_name"), NULL, ngx_stream_variable_server_name,
  78.       0, 0, 0 },

  79.     { ngx_string("bytes_sent"), NULL, ngx_stream_variable_bytes,
  80.       0, 0, 0 },

  81.     { ngx_string("bytes_received"), NULL, ngx_stream_variable_bytes,
  82.       1, 0, 0 },

  83.     { ngx_string("session_time"), NULL, ngx_stream_variable_session_time,
  84.       0, NGX_STREAM_VAR_NOCACHEABLE, 0 },

  85.     { ngx_string("status"), NULL, ngx_stream_variable_status,
  86.       0, NGX_STREAM_VAR_NOCACHEABLE, 0 },

  87.     { ngx_string("connection"), NULL,
  88.       ngx_stream_variable_connection, 0, 0, 0 },

  89.     { ngx_string("nginx_version"), NULL, ngx_stream_variable_nginx_version,
  90.       0, 0, 0 },

  91.     { ngx_string("hostname"), NULL, ngx_stream_variable_hostname,
  92.       0, 0, 0 },

  93.     { ngx_string("pid"), NULL, ngx_stream_variable_pid,
  94.       0, 0, 0 },

  95.     { ngx_string("msec"), NULL, ngx_stream_variable_msec,
  96.       0, NGX_STREAM_VAR_NOCACHEABLE, 0 },

  97.     { ngx_string("time_iso8601"), NULL, ngx_stream_variable_time_iso8601,
  98.       0, NGX_STREAM_VAR_NOCACHEABLE, 0 },

  99.     { ngx_string("time_local"), NULL, ngx_stream_variable_time_local,
  100.       0, NGX_STREAM_VAR_NOCACHEABLE, 0 },

  101.     { ngx_string("protocol"), NULL,
  102.       ngx_stream_variable_protocol, 0, 0, 0 },

  103.       ngx_stream_null_variable
  104. };


  105. ngx_stream_variable_value_t  ngx_stream_variable_null_value =
  106.     ngx_stream_variable("");
  107. ngx_stream_variable_value_t  ngx_stream_variable_true_value =
  108.     ngx_stream_variable("1");


  109. static ngx_uint_t  ngx_stream_variable_depth = 100;


  110. ngx_stream_variable_t *
  111. ngx_stream_add_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t flags)
  112. {
  113.     ngx_int_t                     rc;
  114.     ngx_uint_t                    i;
  115.     ngx_hash_key_t               *key;
  116.     ngx_stream_variable_t        *v;
  117.     ngx_stream_core_main_conf_t  *cmcf;

  118.     if (name->len == 0) {
  119.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  120.                            "invalid variable name \"$\"");
  121.         return NULL;
  122.     }

  123.     if (flags & NGX_STREAM_VAR_PREFIX) {
  124.         return ngx_stream_add_prefix_variable(cf, name, flags);
  125.     }

  126.     cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);

  127.     key = cmcf->variables_keys->keys.elts;
  128.     for (i = 0; i < cmcf->variables_keys->keys.nelts; i++) {
  129.         if (name->len != key[i].key.len
  130.             || ngx_strncasecmp(name->data, key[i].key.data, name->len) != 0)
  131.         {
  132.             continue;
  133.         }

  134.         v = key[i].value;

  135.         if (!(v->flags & NGX_STREAM_VAR_CHANGEABLE)) {
  136.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  137.                                "the duplicate \"%V\" variable", name);
  138.             return NULL;
  139.         }

  140.         if (!(flags & NGX_STREAM_VAR_WEAK)) {
  141.             v->flags &= ~NGX_STREAM_VAR_WEAK;
  142.         }

  143.         return v;
  144.     }

  145.     v = ngx_palloc(cf->pool, sizeof(ngx_stream_variable_t));
  146.     if (v == NULL) {
  147.         return NULL;
  148.     }

  149.     v->name.len = name->len;
  150.     v->name.data = ngx_pnalloc(cf->pool, name->len);
  151.     if (v->name.data == NULL) {
  152.         return NULL;
  153.     }

  154.     ngx_strlow(v->name.data, name->data, name->len);

  155.     v->set_handler = NULL;
  156.     v->get_handler = NULL;
  157.     v->data = 0;
  158.     v->flags = flags;
  159.     v->index = 0;

  160.     rc = ngx_hash_add_key(cmcf->variables_keys, &v->name, v, 0);

  161.     if (rc == NGX_ERROR) {
  162.         return NULL;
  163.     }

  164.     if (rc == NGX_BUSY) {
  165.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  166.                            "conflicting variable name \"%V\"", name);
  167.         return NULL;
  168.     }

  169.     return v;
  170. }


  171. static ngx_stream_variable_t *
  172. ngx_stream_add_prefix_variable(ngx_conf_t *cf, ngx_str_t *name,
  173.     ngx_uint_t flags)
  174. {
  175.     ngx_uint_t                    i;
  176.     ngx_stream_variable_t        *v;
  177.     ngx_stream_core_main_conf_t  *cmcf;

  178.     cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);

  179.     v = cmcf->prefix_variables.elts;
  180.     for (i = 0; i < cmcf->prefix_variables.nelts; i++) {
  181.         if (name->len != v[i].name.len
  182.             || ngx_strncasecmp(name->data, v[i].name.data, name->len) != 0)
  183.         {
  184.             continue;
  185.         }

  186.         v = &v[i];

  187.         if (!(v->flags & NGX_STREAM_VAR_CHANGEABLE)) {
  188.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  189.                                "the duplicate \"%V\" variable", name);
  190.             return NULL;
  191.         }

  192.         if (!(flags & NGX_STREAM_VAR_WEAK)) {
  193.             v->flags &= ~NGX_STREAM_VAR_WEAK;
  194.         }

  195.         return v;
  196.     }

  197.     v = ngx_array_push(&cmcf->prefix_variables);
  198.     if (v == NULL) {
  199.         return NULL;
  200.     }

  201.     v->name.len = name->len;
  202.     v->name.data = ngx_pnalloc(cf->pool, name->len);
  203.     if (v->name.data == NULL) {
  204.         return NULL;
  205.     }

  206.     ngx_strlow(v->name.data, name->data, name->len);

  207.     v->set_handler = NULL;
  208.     v->get_handler = NULL;
  209.     v->data = 0;
  210.     v->flags = flags;
  211.     v->index = 0;

  212.     return v;
  213. }


  214. ngx_int_t
  215. ngx_stream_get_variable_index(ngx_conf_t *cf, ngx_str_t *name)
  216. {
  217.     ngx_uint_t                    i;
  218.     ngx_stream_variable_t        *v;
  219.     ngx_stream_core_main_conf_t  *cmcf;

  220.     if (name->len == 0) {
  221.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  222.                            "invalid variable name \"$\"");
  223.         return NGX_ERROR;
  224.     }

  225.     cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);

  226.     v = cmcf->variables.elts;

  227.     if (v == NULL) {
  228.         if (ngx_array_init(&cmcf->variables, cf->pool, 4,
  229.                            sizeof(ngx_stream_variable_t))
  230.             != NGX_OK)
  231.         {
  232.             return NGX_ERROR;
  233.         }

  234.     } else {
  235.         for (i = 0; i < cmcf->variables.nelts; i++) {
  236.             if (name->len != v[i].name.len
  237.                 || ngx_strncasecmp(name->data, v[i].name.data, name->len) != 0)
  238.             {
  239.                 continue;
  240.             }

  241.             return i;
  242.         }
  243.     }

  244.     v = ngx_array_push(&cmcf->variables);
  245.     if (v == NULL) {
  246.         return NGX_ERROR;
  247.     }

  248.     v->name.len = name->len;
  249.     v->name.data = ngx_pnalloc(cf->pool, name->len);
  250.     if (v->name.data == NULL) {
  251.         return NGX_ERROR;
  252.     }

  253.     ngx_strlow(v->name.data, name->data, name->len);

  254.     v->set_handler = NULL;
  255.     v->get_handler = NULL;
  256.     v->data = 0;
  257.     v->flags = 0;
  258.     v->index = cmcf->variables.nelts - 1;

  259.     return v->index;
  260. }


  261. ngx_stream_variable_value_t *
  262. ngx_stream_get_indexed_variable(ngx_stream_session_t *s, ngx_uint_t index)
  263. {
  264.     ngx_stream_variable_t        *v;
  265.     ngx_stream_core_main_conf_t  *cmcf;

  266.     cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module);

  267.     if (cmcf->variables.nelts <= index) {
  268.         ngx_log_error(NGX_LOG_ALERT, s->connection->log, 0,
  269.                       "unknown variable index: %ui", index);
  270.         return NULL;
  271.     }

  272.     if (s->variables[index].not_found || s->variables[index].valid) {
  273.         return &s->variables[index];
  274.     }

  275.     v = cmcf->variables.elts;

  276.     if (ngx_stream_variable_depth == 0) {
  277.         ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
  278.                       "cycle while evaluating variable \"%V\"",
  279.                       &v[index].name);
  280.         return NULL;
  281.     }

  282.     ngx_stream_variable_depth--;

  283.     if (v[index].get_handler(s, &s->variables[index], v[index].data)
  284.         == NGX_OK)
  285.     {
  286.         ngx_stream_variable_depth++;

  287.         if (v[index].flags & NGX_STREAM_VAR_NOCACHEABLE) {
  288.             s->variables[index].no_cacheable = 1;
  289.         }

  290.         return &s->variables[index];
  291.     }

  292.     ngx_stream_variable_depth++;

  293.     s->variables[index].valid = 0;
  294.     s->variables[index].not_found = 1;

  295.     return NULL;
  296. }


  297. ngx_stream_variable_value_t *
  298. ngx_stream_get_flushed_variable(ngx_stream_session_t *s, ngx_uint_t index)
  299. {
  300.     ngx_stream_variable_value_t  *v;

  301.     v = &s->variables[index];

  302.     if (v->valid || v->not_found) {
  303.         if (!v->no_cacheable) {
  304.             return v;
  305.         }

  306.         v->valid = 0;
  307.         v->not_found = 0;
  308.     }

  309.     return ngx_stream_get_indexed_variable(s, index);
  310. }


  311. ngx_stream_variable_value_t *
  312. ngx_stream_get_variable(ngx_stream_session_t *s, ngx_str_t *name,
  313.     ngx_uint_t key)
  314. {
  315.     size_t                        len;
  316.     ngx_uint_t                    i, n;
  317.     ngx_stream_variable_t        *v;
  318.     ngx_stream_variable_value_t  *vv;
  319.     ngx_stream_core_main_conf_t  *cmcf;

  320.     cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module);

  321.     v = ngx_hash_find(&cmcf->variables_hash, key, name->data, name->len);

  322.     if (v) {
  323.         if (v->flags & NGX_STREAM_VAR_INDEXED) {
  324.             return ngx_stream_get_flushed_variable(s, v->index);
  325.         }

  326.         if (ngx_stream_variable_depth == 0) {
  327.             ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
  328.                           "cycle while evaluating variable \"%V\"", name);
  329.             return NULL;
  330.         }

  331.         ngx_stream_variable_depth--;

  332.         vv = ngx_palloc(s->connection->pool,
  333.                         sizeof(ngx_stream_variable_value_t));

  334.         if (vv && v->get_handler(s, vv, v->data) == NGX_OK) {
  335.             ngx_stream_variable_depth++;
  336.             return vv;
  337.         }

  338.         ngx_stream_variable_depth++;
  339.         return NULL;
  340.     }

  341.     vv = ngx_palloc(s->connection->pool, sizeof(ngx_stream_variable_value_t));
  342.     if (vv == NULL) {
  343.         return NULL;
  344.     }

  345.     len = 0;

  346.     v = cmcf->prefix_variables.elts;
  347.     n = cmcf->prefix_variables.nelts;

  348.     for (i = 0; i < cmcf->prefix_variables.nelts; i++) {
  349.         if (name->len >= v[i].name.len && name->len > len
  350.             && ngx_strncmp(name->data, v[i].name.data, v[i].name.len) == 0)
  351.         {
  352.             len = v[i].name.len;
  353.             n = i;
  354.         }
  355.     }

  356.     if (n != cmcf->prefix_variables.nelts) {
  357.         if (v[n].get_handler(s, vv, (uintptr_t) name) == NGX_OK) {
  358.             return vv;
  359.         }

  360.         return NULL;
  361.     }

  362.     vv->not_found = 1;

  363.     return vv;
  364. }


  365. static ngx_int_t
  366. ngx_stream_variable_binary_remote_addr(ngx_stream_session_t *s,
  367.      ngx_stream_variable_value_t *v, uintptr_t data)
  368. {
  369.     struct sockaddr_in   *sin;
  370. #if (NGX_HAVE_INET6)
  371.     struct sockaddr_in6  *sin6;
  372. #endif

  373.     switch (s->connection->sockaddr->sa_family) {

  374. #if (NGX_HAVE_INET6)
  375.     case AF_INET6:
  376.         sin6 = (struct sockaddr_in6 *) s->connection->sockaddr;

  377.         v->len = sizeof(struct in6_addr);
  378.         v->valid = 1;
  379.         v->no_cacheable = 0;
  380.         v->not_found = 0;
  381.         v->data = sin6->sin6_addr.s6_addr;

  382.         break;
  383. #endif

  384. #if (NGX_HAVE_UNIX_DOMAIN)
  385.     case AF_UNIX:

  386.         v->len = s->connection->addr_text.len;
  387.         v->valid = 1;
  388.         v->no_cacheable = 0;
  389.         v->not_found = 0;
  390.         v->data = s->connection->addr_text.data;

  391.         break;
  392. #endif

  393.     default: /* AF_INET */
  394.         sin = (struct sockaddr_in *) s->connection->sockaddr;

  395.         v->len = sizeof(in_addr_t);
  396.         v->valid = 1;
  397.         v->no_cacheable = 0;
  398.         v->not_found = 0;
  399.         v->data = (u_char *) &sin->sin_addr;

  400.         break;
  401.     }

  402.     return NGX_OK;
  403. }


  404. static ngx_int_t
  405. ngx_stream_variable_remote_addr(ngx_stream_session_t *s,
  406.     ngx_stream_variable_value_t *v, uintptr_t data)
  407. {
  408.     v->len = s->connection->addr_text.len;
  409.     v->valid = 1;
  410.     v->no_cacheable = 0;
  411.     v->not_found = 0;
  412.     v->data = s->connection->addr_text.data;

  413.     return NGX_OK;
  414. }


  415. static ngx_int_t
  416. ngx_stream_variable_remote_port(ngx_stream_session_t *s,
  417.     ngx_stream_variable_value_t *v, uintptr_t data)
  418. {
  419.     ngx_uint_t  port;

  420.     v->len = 0;
  421.     v->valid = 1;
  422.     v->no_cacheable = 0;
  423.     v->not_found = 0;

  424.     v->data = ngx_pnalloc(s->connection->pool, sizeof("65535") - 1);
  425.     if (v->data == NULL) {
  426.         return NGX_ERROR;
  427.     }

  428.     port = ngx_inet_get_port(s->connection->sockaddr);

  429.     if (port > 0 && port < 65536) {
  430.         v->len = ngx_sprintf(v->data, "%ui", port) - v->data;
  431.     }

  432.     return NGX_OK;
  433. }


  434. static ngx_int_t
  435. ngx_stream_variable_proxy_protocol_addr(ngx_stream_session_t *s,
  436.     ngx_stream_variable_value_t *v, uintptr_t data)
  437. {
  438.     ngx_str_t             *addr;
  439.     ngx_proxy_protocol_t  *pp;

  440.     pp = s->connection->proxy_protocol;
  441.     if (pp == NULL) {
  442.         v->not_found = 1;
  443.         return NGX_OK;
  444.     }

  445.     addr = (ngx_str_t *) ((char *) pp + data);

  446.     v->len = addr->len;
  447.     v->valid = 1;
  448.     v->no_cacheable = 0;
  449.     v->not_found = 0;
  450.     v->data = addr->data;

  451.     return NGX_OK;
  452. }


  453. static ngx_int_t
  454. ngx_stream_variable_proxy_protocol_port(ngx_stream_session_t *s,
  455.     ngx_stream_variable_value_t *v, uintptr_t data)
  456. {
  457.     ngx_uint_t             port;
  458.     ngx_proxy_protocol_t  *pp;

  459.     pp = s->connection->proxy_protocol;
  460.     if (pp == NULL) {
  461.         v->not_found = 1;
  462.         return NGX_OK;
  463.     }

  464.     v->len = 0;
  465.     v->valid = 1;
  466.     v->no_cacheable = 0;
  467.     v->not_found = 0;

  468.     v->data = ngx_pnalloc(s->connection->pool, sizeof("65535") - 1);
  469.     if (v->data == NULL) {
  470.         return NGX_ERROR;
  471.     }

  472.     port = *(in_port_t *) ((char *) pp + data);

  473.     if (port > 0 && port < 65536) {
  474.         v->len = ngx_sprintf(v->data, "%ui", port) - v->data;
  475.     }

  476.     return NGX_OK;
  477. }


  478. static ngx_int_t
  479. ngx_stream_variable_proxy_protocol_tlv(ngx_stream_session_t *s,
  480.     ngx_stream_variable_value_t *v, uintptr_t data)
  481. {
  482.     ngx_str_t *name = (ngx_str_t *) data;

  483.     ngx_int_t  rc;
  484.     ngx_str_t  tlv, value;

  485.     tlv.len = name->len - (sizeof("proxy_protocol_tlv_") - 1);
  486.     tlv.data = name->data + sizeof("proxy_protocol_tlv_") - 1;

  487.     rc = ngx_proxy_protocol_get_tlv(s->connection, &tlv, &value);

  488.     if (rc == NGX_ERROR) {
  489.         return NGX_ERROR;
  490.     }

  491.     if (rc == NGX_DECLINED) {
  492.         v->not_found = 1;
  493.         return NGX_OK;
  494.     }

  495.     v->len = value.len;
  496.     v->valid = 1;
  497.     v->no_cacheable = 0;
  498.     v->not_found = 0;
  499.     v->data = value.data;

  500.     return NGX_OK;
  501. }


  502. static ngx_int_t
  503. ngx_stream_variable_server_addr(ngx_stream_session_t *s,
  504.     ngx_stream_variable_value_t *v, uintptr_t data)
  505. {
  506.     ngx_str_t  str;
  507.     u_char     addr[NGX_SOCKADDR_STRLEN];

  508.     str.len = NGX_SOCKADDR_STRLEN;
  509.     str.data = addr;

  510.     if (ngx_connection_local_sockaddr(s->connection, &str, 0) != NGX_OK) {
  511.         return NGX_ERROR;
  512.     }

  513.     str.data = ngx_pnalloc(s->connection->pool, str.len);
  514.     if (str.data == NULL) {
  515.         return NGX_ERROR;
  516.     }

  517.     ngx_memcpy(str.data, addr, str.len);

  518.     v->len = str.len;
  519.     v->valid = 1;
  520.     v->no_cacheable = 0;
  521.     v->not_found = 0;
  522.     v->data = str.data;

  523.     return NGX_OK;
  524. }


  525. static ngx_int_t
  526. ngx_stream_variable_server_port(ngx_stream_session_t *s,
  527.     ngx_stream_variable_value_t *v, uintptr_t data)
  528. {
  529.     ngx_uint_t  port;

  530.     v->len = 0;
  531.     v->valid = 1;
  532.     v->no_cacheable = 0;
  533.     v->not_found = 0;

  534.     if (ngx_connection_local_sockaddr(s->connection, NULL, 0) != NGX_OK) {
  535.         return NGX_ERROR;
  536.     }

  537.     v->data = ngx_pnalloc(s->connection->pool, sizeof("65535") - 1);
  538.     if (v->data == NULL) {
  539.         return NGX_ERROR;
  540.     }

  541.     port = ngx_inet_get_port(s->connection->local_sockaddr);

  542.     if (port > 0 && port < 65536) {
  543.         v->len = ngx_sprintf(v->data, "%ui", port) - v->data;
  544.     }

  545.     return NGX_OK;
  546. }


  547. static ngx_int_t
  548. ngx_stream_variable_server_name(ngx_stream_session_t *s,
  549.     ngx_stream_variable_value_t *v, uintptr_t data)
  550. {
  551.     ngx_stream_core_srv_conf_t  *cscf;

  552.     cscf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module);

  553.     v->len = cscf->server_name.len;
  554.     v->valid = 1;
  555.     v->no_cacheable = 0;
  556.     v->not_found = 0;
  557.     v->data = cscf->server_name.data;

  558.     return NGX_OK;
  559. }


  560. static ngx_int_t
  561. ngx_stream_variable_bytes(ngx_stream_session_t *s,
  562.     ngx_stream_variable_value_t *v, uintptr_t data)
  563. {
  564.     u_char  *p;

  565.     p = ngx_pnalloc(s->connection->pool, NGX_OFF_T_LEN);
  566.     if (p == NULL) {
  567.         return NGX_ERROR;
  568.     }

  569.     if (data == 1) {
  570.         v->len = ngx_sprintf(p, "%O", s->received) - p;

  571.     } else {
  572.         v->len = ngx_sprintf(p, "%O", s->connection->sent) - p;
  573.     }

  574.     v->valid = 1;
  575.     v->no_cacheable = 0;
  576.     v->not_found = 0;
  577.     v->data = p;

  578.     return NGX_OK;
  579. }


  580. static ngx_int_t
  581. ngx_stream_variable_session_time(ngx_stream_session_t *s,
  582.     ngx_stream_variable_value_t *v, uintptr_t data)
  583. {
  584.     u_char          *p;
  585.     ngx_time_t      *tp;
  586.     ngx_msec_int_t   ms;

  587.     p = ngx_pnalloc(s->connection->pool, NGX_TIME_T_LEN + 4);
  588.     if (p == NULL) {
  589.         return NGX_ERROR;
  590.     }

  591.     tp = ngx_timeofday();

  592.     ms = (ngx_msec_int_t)
  593.              ((tp->sec - s->start_sec) * 1000 + (tp->msec - s->start_msec));
  594.     ms = ngx_max(ms, 0);

  595.     v->len = ngx_sprintf(p, "%T.%03M", (time_t) ms / 1000, ms % 1000) - p;
  596.     v->valid = 1;
  597.     v->no_cacheable = 0;
  598.     v->not_found = 0;
  599.     v->data = p;

  600.     return NGX_OK;
  601. }


  602. static ngx_int_t
  603. ngx_stream_variable_status(ngx_stream_session_t *s,
  604.     ngx_stream_variable_value_t *v, uintptr_t data)
  605. {
  606.     v->data = ngx_pnalloc(s->connection->pool, NGX_INT_T_LEN);
  607.     if (v->data == NULL) {
  608.         return NGX_ERROR;
  609.     }

  610.     v->len = ngx_sprintf(v->data, "%03ui", s->status) - v->data;
  611.     v->valid = 1;
  612.     v->no_cacheable = 0;
  613.     v->not_found = 0;

  614.     return NGX_OK;
  615. }


  616. static ngx_int_t
  617. ngx_stream_variable_connection(ngx_stream_session_t *s,
  618.     ngx_stream_variable_value_t *v, uintptr_t data)
  619. {
  620.     u_char  *p;

  621.     p = ngx_pnalloc(s->connection->pool, NGX_ATOMIC_T_LEN);
  622.     if (p == NULL) {
  623.         return NGX_ERROR;
  624.     }

  625.     v->len = ngx_sprintf(p, "%uA", s->connection->number) - p;
  626.     v->valid = 1;
  627.     v->no_cacheable = 0;
  628.     v->not_found = 0;
  629.     v->data = p;

  630.     return NGX_OK;
  631. }


  632. static ngx_int_t
  633. ngx_stream_variable_nginx_version(ngx_stream_session_t *s,
  634.     ngx_stream_variable_value_t *v, uintptr_t data)
  635. {
  636.     v->len = sizeof(NGINX_VERSION) - 1;
  637.     v->valid = 1;
  638.     v->no_cacheable = 0;
  639.     v->not_found = 0;
  640.     v->data = (u_char *) NGINX_VERSION;

  641.     return NGX_OK;
  642. }


  643. static ngx_int_t
  644. ngx_stream_variable_hostname(ngx_stream_session_t *s,
  645.     ngx_stream_variable_value_t *v, uintptr_t data)
  646. {
  647.     v->len = ngx_cycle->hostname.len;
  648.     v->valid = 1;
  649.     v->no_cacheable = 0;
  650.     v->not_found = 0;
  651.     v->data = ngx_cycle->hostname.data;

  652.     return NGX_OK;
  653. }


  654. static ngx_int_t
  655. ngx_stream_variable_pid(ngx_stream_session_t *s,
  656.     ngx_stream_variable_value_t *v, uintptr_t data)
  657. {
  658.     u_char  *p;

  659.     p = ngx_pnalloc(s->connection->pool, NGX_INT64_LEN);
  660.     if (p == NULL) {
  661.         return NGX_ERROR;
  662.     }

  663.     v->len = ngx_sprintf(p, "%P", ngx_pid) - p;
  664.     v->valid = 1;
  665.     v->no_cacheable = 0;
  666.     v->not_found = 0;
  667.     v->data = p;

  668.     return NGX_OK;
  669. }


  670. static ngx_int_t
  671. ngx_stream_variable_msec(ngx_stream_session_t *s,
  672.     ngx_stream_variable_value_t *v, uintptr_t data)
  673. {
  674.     u_char      *p;
  675.     ngx_time_t  *tp;

  676.     p = ngx_pnalloc(s->connection->pool, NGX_TIME_T_LEN + 4);
  677.     if (p == NULL) {
  678.         return NGX_ERROR;
  679.     }

  680.     tp = ngx_timeofday();

  681.     v->len = ngx_sprintf(p, "%T.%03M", tp->sec, tp->msec) - p;
  682.     v->valid = 1;
  683.     v->no_cacheable = 0;
  684.     v->not_found = 0;
  685.     v->data = p;

  686.     return NGX_OK;
  687. }


  688. static ngx_int_t
  689. ngx_stream_variable_time_iso8601(ngx_stream_session_t *s,
  690.     ngx_stream_variable_value_t *v, uintptr_t data)
  691. {
  692.     u_char  *p;

  693.     p = ngx_pnalloc(s->connection->pool, ngx_cached_http_log_iso8601.len);
  694.     if (p == NULL) {
  695.         return NGX_ERROR;
  696.     }

  697.     ngx_memcpy(p, ngx_cached_http_log_iso8601.data,
  698.                ngx_cached_http_log_iso8601.len);

  699.     v->len = ngx_cached_http_log_iso8601.len;
  700.     v->valid = 1;
  701.     v->no_cacheable = 0;
  702.     v->not_found = 0;
  703.     v->data = p;

  704.     return NGX_OK;
  705. }


  706. static ngx_int_t
  707. ngx_stream_variable_time_local(ngx_stream_session_t *s,
  708.     ngx_stream_variable_value_t *v, uintptr_t data)
  709. {
  710.     u_char  *p;

  711.     p = ngx_pnalloc(s->connection->pool, ngx_cached_http_log_time.len);
  712.     if (p == NULL) {
  713.         return NGX_ERROR;
  714.     }

  715.     ngx_memcpy(p, ngx_cached_http_log_time.data, ngx_cached_http_log_time.len);

  716.     v->len = ngx_cached_http_log_time.len;
  717.     v->valid = 1;
  718.     v->no_cacheable = 0;
  719.     v->not_found = 0;
  720.     v->data = p;

  721.     return NGX_OK;
  722. }


  723. static ngx_int_t
  724. ngx_stream_variable_protocol(ngx_stream_session_t *s,
  725.     ngx_stream_variable_value_t *v, uintptr_t data)
  726. {
  727.     v->len = 3;
  728.     v->valid = 1;
  729.     v->no_cacheable = 0;
  730.     v->not_found = 0;
  731.     v->data = (u_char *) (s->connection->type == SOCK_DGRAM ? "UDP" : "TCP");

  732.     return NGX_OK;
  733. }


  734. void *
  735. ngx_stream_map_find(ngx_stream_session_t *s, ngx_stream_map_t *map,
  736.     ngx_str_t *match)
  737. {
  738.     void        *value;
  739.     u_char      *low;
  740.     size_t       len;
  741.     ngx_uint_t   key;

  742.     len = match->len;

  743.     if (len) {
  744.         low = ngx_pnalloc(s->connection->pool, len);
  745.         if (low == NULL) {
  746.             return NULL;
  747.         }

  748.     } else {
  749.         low = NULL;
  750.     }

  751.     key = ngx_hash_strlow(low, match->data, len);

  752.     value = ngx_hash_find_combined(&map->hash, key, low, len);
  753.     if (value) {
  754.         return value;
  755.     }

  756. #if (NGX_PCRE)

  757.     if (len && map->nregex) {
  758.         ngx_int_t                n;
  759.         ngx_uint_t               i;
  760.         ngx_stream_map_regex_t  *reg;

  761.         reg = map->regex;

  762.         for (i = 0; i < map->nregex; i++) {

  763.             n = ngx_stream_regex_exec(s, reg[i].regex, match);

  764.             if (n == NGX_OK) {
  765.                 return reg[i].value;
  766.             }

  767.             if (n == NGX_DECLINED) {
  768.                 continue;
  769.             }

  770.             /* NGX_ERROR */

  771.             return NULL;
  772.         }
  773.     }

  774. #endif

  775.     return NULL;
  776. }


  777. #if (NGX_PCRE)

  778. static ngx_int_t
  779. ngx_stream_variable_not_found(ngx_stream_session_t *s,
  780.     ngx_stream_variable_value_t *v, uintptr_t data)
  781. {
  782.     v->not_found = 1;
  783.     return NGX_OK;
  784. }


  785. ngx_stream_regex_t *
  786. ngx_stream_regex_compile(ngx_conf_t *cf, ngx_regex_compile_t *rc)
  787. {
  788.     u_char                       *p;
  789.     size_t                        size;
  790.     ngx_str_t                     name;
  791.     ngx_uint_t                    i, n;
  792.     ngx_stream_variable_t        *v;
  793.     ngx_stream_regex_t           *re;
  794.     ngx_stream_regex_variable_t  *rv;
  795.     ngx_stream_core_main_conf_t  *cmcf;

  796.     rc->pool = cf->pool;

  797.     if (ngx_regex_compile(rc) != NGX_OK) {
  798.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc->err);
  799.         return NULL;
  800.     }

  801.     re = ngx_pcalloc(cf->pool, sizeof(ngx_stream_regex_t));
  802.     if (re == NULL) {
  803.         return NULL;
  804.     }

  805.     re->regex = rc->regex;
  806.     re->ncaptures = rc->captures;
  807.     re->name = rc->pattern;

  808.     cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);
  809.     cmcf->ncaptures = ngx_max(cmcf->ncaptures, re->ncaptures);

  810.     n = (ngx_uint_t) rc->named_captures;

  811.     if (n == 0) {
  812.         return re;
  813.     }

  814.     rv = ngx_palloc(rc->pool, n * sizeof(ngx_stream_regex_variable_t));
  815.     if (rv == NULL) {
  816.         return NULL;
  817.     }

  818.     re->variables = rv;
  819.     re->nvariables = n;

  820.     size = rc->name_size;
  821.     p = rc->names;

  822.     for (i = 0; i < n; i++) {
  823.         rv[i].capture = 2 * ((p[0] << 8) + p[1]);

  824.         name.data = &p[2];
  825.         name.len = ngx_strlen(name.data);

  826.         v = ngx_stream_add_variable(cf, &name, NGX_STREAM_VAR_CHANGEABLE);
  827.         if (v == NULL) {
  828.             return NULL;
  829.         }

  830.         rv[i].index = ngx_stream_get_variable_index(cf, &name);
  831.         if (rv[i].index == NGX_ERROR) {
  832.             return NULL;
  833.         }

  834.         v->get_handler = ngx_stream_variable_not_found;

  835.         p += size;
  836.     }

  837.     return re;
  838. }


  839. ngx_int_t
  840. ngx_stream_regex_exec(ngx_stream_session_t *s, ngx_stream_regex_t *re,
  841.     ngx_str_t *str)
  842. {
  843.     ngx_int_t                     rc, index;
  844.     ngx_uint_t                    i, n, len;
  845.     ngx_stream_variable_value_t  *vv;
  846.     ngx_stream_core_main_conf_t  *cmcf;

  847.     cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module);

  848.     if (re->ncaptures) {
  849.         len = cmcf->ncaptures;

  850.         if (s->captures == NULL) {
  851.             s->captures = ngx_palloc(s->connection->pool, len * sizeof(int));
  852.             if (s->captures == NULL) {
  853.                 return NGX_ERROR;
  854.             }
  855.         }

  856.     } else {
  857.         len = 0;
  858.     }

  859.     rc = ngx_regex_exec(re->regex, str, s->captures, len);

  860.     if (rc == NGX_REGEX_NO_MATCHED) {
  861.         return NGX_DECLINED;
  862.     }

  863.     if (rc < 0) {
  864.         ngx_log_error(NGX_LOG_ALERT, s->connection->log, 0,
  865.                       ngx_regex_exec_n " failed: %i on \"%V\" using \"%V\"",
  866.                       rc, str, &re->name);
  867.         return NGX_ERROR;
  868.     }

  869.     for (i = 0; i < re->nvariables; i++) {

  870.         n = re->variables[i].capture;
  871.         index = re->variables[i].index;
  872.         vv = &s->variables[index];

  873.         vv->len = s->captures[n + 1] - s->captures[n];
  874.         vv->valid = 1;
  875.         vv->no_cacheable = 0;
  876.         vv->not_found = 0;
  877.         vv->data = &str->data[s->captures[n]];

  878. #if (NGX_DEBUG)
  879.         {
  880.         ngx_stream_variable_t  *v;

  881.         v = cmcf->variables.elts;

  882.         ngx_log_debug2(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
  883.                        "stream regex set $%V to \"%v\"", &v[index].name, vv);
  884.         }
  885. #endif
  886.     }

  887.     s->ncaptures = rc * 2;
  888.     s->captures_data = str->data;

  889.     return NGX_OK;
  890. }

  891. #endif


  892. ngx_int_t
  893. ngx_stream_variables_add_core_vars(ngx_conf_t *cf)
  894. {
  895.     ngx_stream_variable_t        *cv, *v;
  896.     ngx_stream_core_main_conf_t  *cmcf;

  897.     cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);

  898.     cmcf->variables_keys = ngx_pcalloc(cf->temp_pool,
  899.                                        sizeof(ngx_hash_keys_arrays_t));
  900.     if (cmcf->variables_keys == NULL) {
  901.         return NGX_ERROR;
  902.     }

  903.     cmcf->variables_keys->pool = cf->pool;
  904.     cmcf->variables_keys->temp_pool = cf->pool;

  905.     if (ngx_hash_keys_array_init(cmcf->variables_keys, NGX_HASH_SMALL)
  906.         != NGX_OK)
  907.     {
  908.         return NGX_ERROR;
  909.     }

  910.     if (ngx_array_init(&cmcf->prefix_variables, cf->pool, 8,
  911.                        sizeof(ngx_stream_variable_t))
  912.         != NGX_OK)
  913.     {
  914.         return NGX_ERROR;
  915.     }

  916.     for (cv = ngx_stream_core_variables; cv->name.len; cv++) {
  917.         v = ngx_stream_add_variable(cf, &cv->name, cv->flags);
  918.         if (v == NULL) {
  919.             return NGX_ERROR;
  920.         }

  921.         *v = *cv;
  922.     }

  923.     return NGX_OK;
  924. }


  925. ngx_int_t
  926. ngx_stream_variables_init_vars(ngx_conf_t *cf)
  927. {
  928.     size_t                        len;
  929.     ngx_uint_t                    i, n;
  930.     ngx_hash_key_t               *key;
  931.     ngx_hash_init_t               hash;
  932.     ngx_stream_variable_t        *v, *av, *pv;
  933.     ngx_stream_core_main_conf_t  *cmcf;

  934.     /* set the handlers for the indexed stream variables */

  935.     cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);

  936.     v = cmcf->variables.elts;
  937.     pv = cmcf->prefix_variables.elts;
  938.     key = cmcf->variables_keys->keys.elts;

  939.     for (i = 0; i < cmcf->variables.nelts; i++) {

  940.         for (n = 0; n < cmcf->variables_keys->keys.nelts; n++) {

  941.             av = key[n].value;

  942.             if (v[i].name.len == key[n].key.len
  943.                 && ngx_strncmp(v[i].name.data, key[n].key.data, v[i].name.len)
  944.                    == 0)
  945.             {
  946.                 v[i].get_handler = av->get_handler;
  947.                 v[i].data = av->data;

  948.                 av->flags |= NGX_STREAM_VAR_INDEXED;
  949.                 v[i].flags = av->flags;

  950.                 av->index = i;

  951.                 if (av->get_handler == NULL
  952.                     || (av->flags & NGX_STREAM_VAR_WEAK))
  953.                 {
  954.                     break;
  955.                 }

  956.                 goto next;
  957.             }
  958.         }

  959.         len = 0;
  960.         av = NULL;

  961.         for (n = 0; n < cmcf->prefix_variables.nelts; n++) {
  962.             if (v[i].name.len >= pv[n].name.len && v[i].name.len > len
  963.                 && ngx_strncmp(v[i].name.data, pv[n].name.data, pv[n].name.len)
  964.                    == 0)
  965.             {
  966.                 av = &pv[n];
  967.                 len = pv[n].name.len;
  968.             }
  969.         }

  970.         if (av) {
  971.             v[i].get_handler = av->get_handler;
  972.             v[i].data = (uintptr_t) &v[i].name;
  973.             v[i].flags = av->flags;

  974.             goto next;
  975.          }

  976.         if (v[i].get_handler == NULL) {
  977.             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
  978.                           "unknown \"%V\" variable", &v[i].name);
  979.             return NGX_ERROR;
  980.         }

  981.     next:
  982.         continue;
  983.     }


  984.     for (n = 0; n < cmcf->variables_keys->keys.nelts; n++) {
  985.         av = key[n].value;

  986.         if (av->flags & NGX_STREAM_VAR_NOHASH) {
  987.             key[n].key.data = NULL;
  988.         }
  989.     }


  990.     hash.hash = &cmcf->variables_hash;
  991.     hash.key = ngx_hash_key;
  992.     hash.max_size = cmcf->variables_hash_max_size;
  993.     hash.bucket_size = cmcf->variables_hash_bucket_size;
  994.     hash.name = "variables_hash";
  995.     hash.pool = cf->pool;
  996.     hash.temp_pool = NULL;

  997.     if (ngx_hash_init(&hash, cmcf->variables_keys->keys.elts,
  998.                       cmcf->variables_keys->keys.nelts)
  999.         != NGX_OK)
  1000.     {
  1001.         return NGX_ERROR;
  1002.     }

  1003.     cmcf->variables_keys = NULL;

  1004.     return NGX_OK;
  1005. }