Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.19.2 ]​[ nginx-1.18.0 ]​

0001 
0002 /*
0003  * Copyright (C) Igor Sysoev
0004  * Copyright (C) Nginx, Inc.
0005  */
0006 
0007 
0008 #include <ngx_config.h>
0009 #include <ngx_core.h>
0010 #include <ngx_stream.h>
0011 #include <nginx.h>
0012 
0013 static ngx_stream_variable_t *ngx_stream_add_prefix_variable(ngx_conf_t *cf,
0014     ngx_str_t *name, ngx_uint_t flags);
0015 
0016 static ngx_int_t ngx_stream_variable_binary_remote_addr(
0017     ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data);
0018 static ngx_int_t ngx_stream_variable_remote_addr(ngx_stream_session_t *s,
0019     ngx_stream_variable_value_t *v, uintptr_t data);
0020 static ngx_int_t ngx_stream_variable_remote_port(ngx_stream_session_t *s,
0021     ngx_stream_variable_value_t *v, uintptr_t data);
0022 static ngx_int_t ngx_stream_variable_proxy_protocol_addr(
0023     ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data);
0024 static ngx_int_t ngx_stream_variable_proxy_protocol_port(
0025     ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data);
0026 static ngx_int_t ngx_stream_variable_server_addr(ngx_stream_session_t *s,
0027     ngx_stream_variable_value_t *v, uintptr_t data);
0028 static ngx_int_t ngx_stream_variable_server_port(ngx_stream_session_t *s,
0029     ngx_stream_variable_value_t *v, uintptr_t data);
0030 static ngx_int_t ngx_stream_variable_bytes(ngx_stream_session_t *s,
0031     ngx_stream_variable_value_t *v, uintptr_t data);
0032 static ngx_int_t ngx_stream_variable_session_time(ngx_stream_session_t *s,
0033     ngx_stream_variable_value_t *v, uintptr_t data);
0034 static ngx_int_t ngx_stream_variable_status(ngx_stream_session_t *s,
0035     ngx_stream_variable_value_t *v, uintptr_t data);
0036 static ngx_int_t ngx_stream_variable_connection(ngx_stream_session_t *s,
0037     ngx_stream_variable_value_t *v, uintptr_t data);
0038 
0039 static ngx_int_t ngx_stream_variable_nginx_version(ngx_stream_session_t *s,
0040     ngx_stream_variable_value_t *v, uintptr_t data);
0041 static ngx_int_t ngx_stream_variable_hostname(ngx_stream_session_t *s,
0042     ngx_stream_variable_value_t *v, uintptr_t data);
0043 static ngx_int_t ngx_stream_variable_pid(ngx_stream_session_t *s,
0044     ngx_stream_variable_value_t *v, uintptr_t data);
0045 static ngx_int_t ngx_stream_variable_msec(ngx_stream_session_t *s,
0046     ngx_stream_variable_value_t *v, uintptr_t data);
0047 static ngx_int_t ngx_stream_variable_time_iso8601(ngx_stream_session_t *s,
0048     ngx_stream_variable_value_t *v, uintptr_t data);
0049 static ngx_int_t ngx_stream_variable_time_local(ngx_stream_session_t *s,
0050     ngx_stream_variable_value_t *v, uintptr_t data);
0051 static ngx_int_t ngx_stream_variable_protocol(ngx_stream_session_t *s,
0052     ngx_stream_variable_value_t *v, uintptr_t data);
0053 
0054 
0055 static ngx_stream_variable_t  ngx_stream_core_variables[] = {
0056 
0057     { ngx_string("binary_remote_addr"), NULL,
0058       ngx_stream_variable_binary_remote_addr, 0, 0, 0 },
0059 
0060     { ngx_string("remote_addr"), NULL,
0061       ngx_stream_variable_remote_addr, 0, 0, 0 },
0062 
0063     { ngx_string("remote_port"), NULL,
0064       ngx_stream_variable_remote_port, 0, 0, 0 },
0065 
0066     { ngx_string("proxy_protocol_addr"), NULL,
0067       ngx_stream_variable_proxy_protocol_addr,
0068       offsetof(ngx_proxy_protocol_t, src_addr), 0, 0 },
0069 
0070     { ngx_string("proxy_protocol_port"), NULL,
0071       ngx_stream_variable_proxy_protocol_port,
0072       offsetof(ngx_proxy_protocol_t, src_port), 0, 0 },
0073 
0074     { ngx_string("proxy_protocol_server_addr"), NULL,
0075       ngx_stream_variable_proxy_protocol_addr,
0076       offsetof(ngx_proxy_protocol_t, dst_addr), 0, 0 },
0077 
0078     { ngx_string("proxy_protocol_server_port"), NULL,
0079       ngx_stream_variable_proxy_protocol_port,
0080       offsetof(ngx_proxy_protocol_t, dst_port), 0, 0 },
0081 
0082     { ngx_string("server_addr"), NULL,
0083       ngx_stream_variable_server_addr, 0, 0, 0 },
0084 
0085     { ngx_string("server_port"), NULL,
0086       ngx_stream_variable_server_port, 0, 0, 0 },
0087 
0088     { ngx_string("bytes_sent"), NULL, ngx_stream_variable_bytes,
0089       0, 0, 0 },
0090 
0091     { ngx_string("bytes_received"), NULL, ngx_stream_variable_bytes,
0092       1, 0, 0 },
0093 
0094     { ngx_string("session_time"), NULL, ngx_stream_variable_session_time,
0095       0, NGX_STREAM_VAR_NOCACHEABLE, 0 },
0096 
0097     { ngx_string("status"), NULL, ngx_stream_variable_status,
0098       0, NGX_STREAM_VAR_NOCACHEABLE, 0 },
0099 
0100     { ngx_string("connection"), NULL,
0101       ngx_stream_variable_connection, 0, 0, 0 },
0102 
0103     { ngx_string("nginx_version"), NULL, ngx_stream_variable_nginx_version,
0104       0, 0, 0 },
0105 
0106     { ngx_string("hostname"), NULL, ngx_stream_variable_hostname,
0107       0, 0, 0 },
0108 
0109     { ngx_string("pid"), NULL, ngx_stream_variable_pid,
0110       0, 0, 0 },
0111 
0112     { ngx_string("msec"), NULL, ngx_stream_variable_msec,
0113       0, NGX_STREAM_VAR_NOCACHEABLE, 0 },
0114 
0115     { ngx_string("time_iso8601"), NULL, ngx_stream_variable_time_iso8601,
0116       0, NGX_STREAM_VAR_NOCACHEABLE, 0 },
0117 
0118     { ngx_string("time_local"), NULL, ngx_stream_variable_time_local,
0119       0, NGX_STREAM_VAR_NOCACHEABLE, 0 },
0120 
0121     { ngx_string("protocol"), NULL,
0122       ngx_stream_variable_protocol, 0, 0, 0 },
0123 
0124       ngx_stream_null_variable
0125 };
0126 
0127 
0128 ngx_stream_variable_value_t  ngx_stream_variable_null_value =
0129     ngx_stream_variable("");
0130 ngx_stream_variable_value_t  ngx_stream_variable_true_value =
0131     ngx_stream_variable("1");
0132 
0133 
0134 static ngx_uint_t  ngx_stream_variable_depth = 100;
0135 
0136 
0137 ngx_stream_variable_t *
0138 ngx_stream_add_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t flags)
0139 {
0140     ngx_int_t                     rc;
0141     ngx_uint_t                    i;
0142     ngx_hash_key_t               *key;
0143     ngx_stream_variable_t        *v;
0144     ngx_stream_core_main_conf_t  *cmcf;
0145 
0146     if (name->len == 0) {
0147         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0148                            "invalid variable name \"$\"");
0149         return NULL;
0150     }
0151 
0152     if (flags & NGX_STREAM_VAR_PREFIX) {
0153         return ngx_stream_add_prefix_variable(cf, name, flags);
0154     }
0155 
0156     cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);
0157 
0158     key = cmcf->variables_keys->keys.elts;
0159     for (i = 0; i < cmcf->variables_keys->keys.nelts; i++) {
0160         if (name->len != key[i].key.len
0161             || ngx_strncasecmp(name->data, key[i].key.data, name->len) != 0)
0162         {
0163             continue;
0164         }
0165 
0166         v = key[i].value;
0167 
0168         if (!(v->flags & NGX_STREAM_VAR_CHANGEABLE)) {
0169             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0170                                "the duplicate \"%V\" variable", name);
0171             return NULL;
0172         }
0173 
0174         if (!(flags & NGX_STREAM_VAR_WEAK)) {
0175             v->flags &= ~NGX_STREAM_VAR_WEAK;
0176         }
0177 
0178         return v;
0179     }
0180 
0181     v = ngx_palloc(cf->pool, sizeof(ngx_stream_variable_t));
0182     if (v == NULL) {
0183         return NULL;
0184     }
0185 
0186     v->name.len = name->len;
0187     v->name.data = ngx_pnalloc(cf->pool, name->len);
0188     if (v->name.data == NULL) {
0189         return NULL;
0190     }
0191 
0192     ngx_strlow(v->name.data, name->data, name->len);
0193 
0194     v->set_handler = NULL;
0195     v->get_handler = NULL;
0196     v->data = 0;
0197     v->flags = flags;
0198     v->index = 0;
0199 
0200     rc = ngx_hash_add_key(cmcf->variables_keys, &v->name, v, 0);
0201 
0202     if (rc == NGX_ERROR) {
0203         return NULL;
0204     }
0205 
0206     if (rc == NGX_BUSY) {
0207         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0208                            "conflicting variable name \"%V\"", name);
0209         return NULL;
0210     }
0211 
0212     return v;
0213 }
0214 
0215 
0216 static ngx_stream_variable_t *
0217 ngx_stream_add_prefix_variable(ngx_conf_t *cf, ngx_str_t *name,
0218     ngx_uint_t flags)
0219 {
0220     ngx_uint_t                    i;
0221     ngx_stream_variable_t        *v;
0222     ngx_stream_core_main_conf_t  *cmcf;
0223 
0224     cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);
0225 
0226     v = cmcf->prefix_variables.elts;
0227     for (i = 0; i < cmcf->prefix_variables.nelts; i++) {
0228         if (name->len != v[i].name.len
0229             || ngx_strncasecmp(name->data, v[i].name.data, name->len) != 0)
0230         {
0231             continue;
0232         }
0233 
0234         v = &v[i];
0235 
0236         if (!(v->flags & NGX_STREAM_VAR_CHANGEABLE)) {
0237             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0238                                "the duplicate \"%V\" variable", name);
0239             return NULL;
0240         }
0241 
0242         if (!(flags & NGX_STREAM_VAR_WEAK)) {
0243             v->flags &= ~NGX_STREAM_VAR_WEAK;
0244         }
0245 
0246         return v;
0247     }
0248 
0249     v = ngx_array_push(&cmcf->prefix_variables);
0250     if (v == NULL) {
0251         return NULL;
0252     }
0253 
0254     v->name.len = name->len;
0255     v->name.data = ngx_pnalloc(cf->pool, name->len);
0256     if (v->name.data == NULL) {
0257         return NULL;
0258     }
0259 
0260     ngx_strlow(v->name.data, name->data, name->len);
0261 
0262     v->set_handler = NULL;
0263     v->get_handler = NULL;
0264     v->data = 0;
0265     v->flags = flags;
0266     v->index = 0;
0267 
0268     return v;
0269 }
0270 
0271 
0272 ngx_int_t
0273 ngx_stream_get_variable_index(ngx_conf_t *cf, ngx_str_t *name)
0274 {
0275     ngx_uint_t                    i;
0276     ngx_stream_variable_t        *v;
0277     ngx_stream_core_main_conf_t  *cmcf;
0278 
0279     if (name->len == 0) {
0280         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0281                            "invalid variable name \"$\"");
0282         return NGX_ERROR;
0283     }
0284 
0285     cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);
0286 
0287     v = cmcf->variables.elts;
0288 
0289     if (v == NULL) {
0290         if (ngx_array_init(&cmcf->variables, cf->pool, 4,
0291                            sizeof(ngx_stream_variable_t))
0292             != NGX_OK)
0293         {
0294             return NGX_ERROR;
0295         }
0296 
0297     } else {
0298         for (i = 0; i < cmcf->variables.nelts; i++) {
0299             if (name->len != v[i].name.len
0300                 || ngx_strncasecmp(name->data, v[i].name.data, name->len) != 0)
0301             {
0302                 continue;
0303             }
0304 
0305             return i;
0306         }
0307     }
0308 
0309     v = ngx_array_push(&cmcf->variables);
0310     if (v == NULL) {
0311         return NGX_ERROR;
0312     }
0313 
0314     v->name.len = name->len;
0315     v->name.data = ngx_pnalloc(cf->pool, name->len);
0316     if (v->name.data == NULL) {
0317         return NGX_ERROR;
0318     }
0319 
0320     ngx_strlow(v->name.data, name->data, name->len);
0321 
0322     v->set_handler = NULL;
0323     v->get_handler = NULL;
0324     v->data = 0;
0325     v->flags = 0;
0326     v->index = cmcf->variables.nelts - 1;
0327 
0328     return v->index;
0329 }
0330 
0331 
0332 ngx_stream_variable_value_t *
0333 ngx_stream_get_indexed_variable(ngx_stream_session_t *s, ngx_uint_t index)
0334 {
0335     ngx_stream_variable_t        *v;
0336     ngx_stream_core_main_conf_t  *cmcf;
0337 
0338     cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module);
0339 
0340     if (cmcf->variables.nelts <= index) {
0341         ngx_log_error(NGX_LOG_ALERT, s->connection->log, 0,
0342                       "unknown variable index: %ui", index);
0343         return NULL;
0344     }
0345 
0346     if (s->variables[index].not_found || s->variables[index].valid) {
0347         return &s->variables[index];
0348     }
0349 
0350     v = cmcf->variables.elts;
0351 
0352     if (ngx_stream_variable_depth == 0) {
0353         ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
0354                       "cycle while evaluating variable \"%V\"",
0355                       &v[index].name);
0356         return NULL;
0357     }
0358 
0359     ngx_stream_variable_depth--;
0360 
0361     if (v[index].get_handler(s, &s->variables[index], v[index].data)
0362         == NGX_OK)
0363     {
0364         ngx_stream_variable_depth++;
0365 
0366         if (v[index].flags & NGX_STREAM_VAR_NOCACHEABLE) {
0367             s->variables[index].no_cacheable = 1;
0368         }
0369 
0370         return &s->variables[index];
0371     }
0372 
0373     ngx_stream_variable_depth++;
0374 
0375     s->variables[index].valid = 0;
0376     s->variables[index].not_found = 1;
0377 
0378     return NULL;
0379 }
0380 
0381 
0382 ngx_stream_variable_value_t *
0383 ngx_stream_get_flushed_variable(ngx_stream_session_t *s, ngx_uint_t index)
0384 {
0385     ngx_stream_variable_value_t  *v;
0386 
0387     v = &s->variables[index];
0388 
0389     if (v->valid || v->not_found) {
0390         if (!v->no_cacheable) {
0391             return v;
0392         }
0393 
0394         v->valid = 0;
0395         v->not_found = 0;
0396     }
0397 
0398     return ngx_stream_get_indexed_variable(s, index);
0399 }
0400 
0401 
0402 ngx_stream_variable_value_t *
0403 ngx_stream_get_variable(ngx_stream_session_t *s, ngx_str_t *name,
0404     ngx_uint_t key)
0405 {
0406     size_t                        len;
0407     ngx_uint_t                    i, n;
0408     ngx_stream_variable_t        *v;
0409     ngx_stream_variable_value_t  *vv;
0410     ngx_stream_core_main_conf_t  *cmcf;
0411 
0412     cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module);
0413 
0414     v = ngx_hash_find(&cmcf->variables_hash, key, name->data, name->len);
0415 
0416     if (v) {
0417         if (v->flags & NGX_STREAM_VAR_INDEXED) {
0418             return ngx_stream_get_flushed_variable(s, v->index);
0419         }
0420 
0421         if (ngx_stream_variable_depth == 0) {
0422             ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
0423                           "cycle while evaluating variable \"%V\"", name);
0424             return NULL;
0425         }
0426 
0427         ngx_stream_variable_depth--;
0428 
0429         vv = ngx_palloc(s->connection->pool,
0430                         sizeof(ngx_stream_variable_value_t));
0431 
0432         if (vv && v->get_handler(s, vv, v->data) == NGX_OK) {
0433             ngx_stream_variable_depth++;
0434             return vv;
0435         }
0436 
0437         ngx_stream_variable_depth++;
0438         return NULL;
0439     }
0440 
0441     vv = ngx_palloc(s->connection->pool, sizeof(ngx_stream_variable_value_t));
0442     if (vv == NULL) {
0443         return NULL;
0444     }
0445 
0446     len = 0;
0447 
0448     v = cmcf->prefix_variables.elts;
0449     n = cmcf->prefix_variables.nelts;
0450 
0451     for (i = 0; i < cmcf->prefix_variables.nelts; i++) {
0452         if (name->len >= v[i].name.len && name->len > len
0453             && ngx_strncmp(name->data, v[i].name.data, v[i].name.len) == 0)
0454         {
0455             len = v[i].name.len;
0456             n = i;
0457         }
0458     }
0459 
0460     if (n != cmcf->prefix_variables.nelts) {
0461         if (v[n].get_handler(s, vv, (uintptr_t) name) == NGX_OK) {
0462             return vv;
0463         }
0464 
0465         return NULL;
0466     }
0467 
0468     vv->not_found = 1;
0469 
0470     return vv;
0471 }
0472 
0473 
0474 static ngx_int_t
0475 ngx_stream_variable_binary_remote_addr(ngx_stream_session_t *s,
0476      ngx_stream_variable_value_t *v, uintptr_t data)
0477 {
0478     struct sockaddr_in   *sin;
0479 #if (NGX_HAVE_INET6)
0480     struct sockaddr_in6  *sin6;
0481 #endif
0482 
0483     switch (s->connection->sockaddr->sa_family) {
0484 
0485 #if (NGX_HAVE_INET6)
0486     case AF_INET6:
0487         sin6 = (struct sockaddr_in6 *) s->connection->sockaddr;
0488 
0489         v->len = sizeof(struct in6_addr);
0490         v->valid = 1;
0491         v->no_cacheable = 0;
0492         v->not_found = 0;
0493         v->data = sin6->sin6_addr.s6_addr;
0494 
0495         break;
0496 #endif
0497 
0498 #if (NGX_HAVE_UNIX_DOMAIN)
0499     case AF_UNIX:
0500 
0501         v->len = s->connection->addr_text.len;
0502         v->valid = 1;
0503         v->no_cacheable = 0;
0504         v->not_found = 0;
0505         v->data = s->connection->addr_text.data;
0506 
0507         break;
0508 #endif
0509 
0510     default: /* AF_INET */
0511         sin = (struct sockaddr_in *) s->connection->sockaddr;
0512 
0513         v->len = sizeof(in_addr_t);
0514         v->valid = 1;
0515         v->no_cacheable = 0;
0516         v->not_found = 0;
0517         v->data = (u_char *) &sin->sin_addr;
0518 
0519         break;
0520     }
0521 
0522     return NGX_OK;
0523 }
0524 
0525 
0526 static ngx_int_t
0527 ngx_stream_variable_remote_addr(ngx_stream_session_t *s,
0528     ngx_stream_variable_value_t *v, uintptr_t data)
0529 {
0530     v->len = s->connection->addr_text.len;
0531     v->valid = 1;
0532     v->no_cacheable = 0;
0533     v->not_found = 0;
0534     v->data = s->connection->addr_text.data;
0535 
0536     return NGX_OK;
0537 }
0538 
0539 
0540 static ngx_int_t
0541 ngx_stream_variable_remote_port(ngx_stream_session_t *s,
0542     ngx_stream_variable_value_t *v, uintptr_t data)
0543 {
0544     ngx_uint_t  port;
0545 
0546     v->len = 0;
0547     v->valid = 1;
0548     v->no_cacheable = 0;
0549     v->not_found = 0;
0550 
0551     v->data = ngx_pnalloc(s->connection->pool, sizeof("65535") - 1);
0552     if (v->data == NULL) {
0553         return NGX_ERROR;
0554     }
0555 
0556     port = ngx_inet_get_port(s->connection->sockaddr);
0557 
0558     if (port > 0 && port < 65536) {
0559         v->len = ngx_sprintf(v->data, "%ui", port) - v->data;
0560     }
0561 
0562     return NGX_OK;
0563 }
0564 
0565 
0566 static ngx_int_t
0567 ngx_stream_variable_proxy_protocol_addr(ngx_stream_session_t *s,
0568     ngx_stream_variable_value_t *v, uintptr_t data)
0569 {
0570     ngx_str_t             *addr;
0571     ngx_proxy_protocol_t  *pp;
0572 
0573     pp = s->connection->proxy_protocol;
0574     if (pp == NULL) {
0575         v->not_found = 1;
0576         return NGX_OK;
0577     }
0578 
0579     addr = (ngx_str_t *) ((char *) pp + data);
0580 
0581     v->len = addr->len;
0582     v->valid = 1;
0583     v->no_cacheable = 0;
0584     v->not_found = 0;
0585     v->data = addr->data;
0586 
0587     return NGX_OK;
0588 }
0589 
0590 
0591 static ngx_int_t
0592 ngx_stream_variable_proxy_protocol_port(ngx_stream_session_t *s,
0593     ngx_stream_variable_value_t *v, uintptr_t data)
0594 {
0595     ngx_uint_t             port;
0596     ngx_proxy_protocol_t  *pp;
0597 
0598     pp = s->connection->proxy_protocol;
0599     if (pp == NULL) {
0600         v->not_found = 1;
0601         return NGX_OK;
0602     }
0603 
0604     v->len = 0;
0605     v->valid = 1;
0606     v->no_cacheable = 0;
0607     v->not_found = 0;
0608 
0609     v->data = ngx_pnalloc(s->connection->pool, sizeof("65535") - 1);
0610     if (v->data == NULL) {
0611         return NGX_ERROR;
0612     }
0613 
0614     port = *(in_port_t *) ((char *) pp + data);
0615 
0616     if (port > 0 && port < 65536) {
0617         v->len = ngx_sprintf(v->data, "%ui", port) - v->data;
0618     }
0619 
0620     return NGX_OK;
0621 }
0622 
0623 
0624 static ngx_int_t
0625 ngx_stream_variable_server_addr(ngx_stream_session_t *s,
0626     ngx_stream_variable_value_t *v, uintptr_t data)
0627 {
0628     ngx_str_t  str;
0629     u_char     addr[NGX_SOCKADDR_STRLEN];
0630 
0631     str.len = NGX_SOCKADDR_STRLEN;
0632     str.data = addr;
0633 
0634     if (ngx_connection_local_sockaddr(s->connection, &str, 0) != NGX_OK) {
0635         return NGX_ERROR;
0636     }
0637 
0638     str.data = ngx_pnalloc(s->connection->pool, str.len);
0639     if (str.data == NULL) {
0640         return NGX_ERROR;
0641     }
0642 
0643     ngx_memcpy(str.data, addr, str.len);
0644 
0645     v->len = str.len;
0646     v->valid = 1;
0647     v->no_cacheable = 0;
0648     v->not_found = 0;
0649     v->data = str.data;
0650 
0651     return NGX_OK;
0652 }
0653 
0654 
0655 static ngx_int_t
0656 ngx_stream_variable_server_port(ngx_stream_session_t *s,
0657     ngx_stream_variable_value_t *v, uintptr_t data)
0658 {
0659     ngx_uint_t  port;
0660 
0661     v->len = 0;
0662     v->valid = 1;
0663     v->no_cacheable = 0;
0664     v->not_found = 0;
0665 
0666     if (ngx_connection_local_sockaddr(s->connection, NULL, 0) != NGX_OK) {
0667         return NGX_ERROR;
0668     }
0669 
0670     v->data = ngx_pnalloc(s->connection->pool, sizeof("65535") - 1);
0671     if (v->data == NULL) {
0672         return NGX_ERROR;
0673     }
0674 
0675     port = ngx_inet_get_port(s->connection->local_sockaddr);
0676 
0677     if (port > 0 && port < 65536) {
0678         v->len = ngx_sprintf(v->data, "%ui", port) - v->data;
0679     }
0680 
0681     return NGX_OK;
0682 }
0683 
0684 
0685 static ngx_int_t
0686 ngx_stream_variable_bytes(ngx_stream_session_t *s,
0687     ngx_stream_variable_value_t *v, uintptr_t data)
0688 {
0689     u_char  *p;
0690 
0691     p = ngx_pnalloc(s->connection->pool, NGX_OFF_T_LEN);
0692     if (p == NULL) {
0693         return NGX_ERROR;
0694     }
0695 
0696     if (data == 1) {
0697         v->len = ngx_sprintf(p, "%O", s->received) - p;
0698 
0699     } else {
0700         v->len = ngx_sprintf(p, "%O", s->connection->sent) - p;
0701     }
0702 
0703     v->valid = 1;
0704     v->no_cacheable = 0;
0705     v->not_found = 0;
0706     v->data = p;
0707 
0708     return NGX_OK;
0709 }
0710 
0711 
0712 static ngx_int_t
0713 ngx_stream_variable_session_time(ngx_stream_session_t *s,
0714     ngx_stream_variable_value_t *v, uintptr_t data)
0715 {
0716     u_char          *p;
0717     ngx_time_t      *tp;
0718     ngx_msec_int_t   ms;
0719 
0720     p = ngx_pnalloc(s->connection->pool, NGX_TIME_T_LEN + 4);
0721     if (p == NULL) {
0722         return NGX_ERROR;
0723     }
0724 
0725     tp = ngx_timeofday();
0726 
0727     ms = (ngx_msec_int_t)
0728              ((tp->sec - s->start_sec) * 1000 + (tp->msec - s->start_msec));
0729     ms = ngx_max(ms, 0);
0730 
0731     v->len = ngx_sprintf(p, "%T.%03M", (time_t) ms / 1000, ms % 1000) - p;
0732     v->valid = 1;
0733     v->no_cacheable = 0;
0734     v->not_found = 0;
0735     v->data = p;
0736 
0737     return NGX_OK;
0738 }
0739 
0740 
0741 static ngx_int_t
0742 ngx_stream_variable_status(ngx_stream_session_t *s,
0743     ngx_stream_variable_value_t *v, uintptr_t data)
0744 {
0745     v->data = ngx_pnalloc(s->connection->pool, NGX_INT_T_LEN);
0746     if (v->data == NULL) {
0747         return NGX_ERROR;
0748     }
0749 
0750     v->len = ngx_sprintf(v->data, "%03ui", s->status) - v->data;
0751     v->valid = 1;
0752     v->no_cacheable = 0;
0753     v->not_found = 0;
0754 
0755     return NGX_OK;
0756 }
0757 
0758 
0759 static ngx_int_t
0760 ngx_stream_variable_connection(ngx_stream_session_t *s,
0761     ngx_stream_variable_value_t *v, uintptr_t data)
0762 {
0763     u_char  *p;
0764 
0765     p = ngx_pnalloc(s->connection->pool, NGX_ATOMIC_T_LEN);
0766     if (p == NULL) {
0767         return NGX_ERROR;
0768     }
0769 
0770     v->len = ngx_sprintf(p, "%uA", s->connection->number) - p;
0771     v->valid = 1;
0772     v->no_cacheable = 0;
0773     v->not_found = 0;
0774     v->data = p;
0775 
0776     return NGX_OK;
0777 }
0778 
0779 
0780 static ngx_int_t
0781 ngx_stream_variable_nginx_version(ngx_stream_session_t *s,
0782     ngx_stream_variable_value_t *v, uintptr_t data)
0783 {
0784     v->len = sizeof(NGINX_VERSION) - 1;
0785     v->valid = 1;
0786     v->no_cacheable = 0;
0787     v->not_found = 0;
0788     v->data = (u_char *) NGINX_VERSION;
0789 
0790     return NGX_OK;
0791 }
0792 
0793 
0794 static ngx_int_t
0795 ngx_stream_variable_hostname(ngx_stream_session_t *s,
0796     ngx_stream_variable_value_t *v, uintptr_t data)
0797 {
0798     v->len = ngx_cycle->hostname.len;
0799     v->valid = 1;
0800     v->no_cacheable = 0;
0801     v->not_found = 0;
0802     v->data = ngx_cycle->hostname.data;
0803 
0804     return NGX_OK;
0805 }
0806 
0807 
0808 static ngx_int_t
0809 ngx_stream_variable_pid(ngx_stream_session_t *s,
0810     ngx_stream_variable_value_t *v, uintptr_t data)
0811 {
0812     u_char  *p;
0813 
0814     p = ngx_pnalloc(s->connection->pool, NGX_INT64_LEN);
0815     if (p == NULL) {
0816         return NGX_ERROR;
0817     }
0818 
0819     v->len = ngx_sprintf(p, "%P", ngx_pid) - p;
0820     v->valid = 1;
0821     v->no_cacheable = 0;
0822     v->not_found = 0;
0823     v->data = p;
0824 
0825     return NGX_OK;
0826 }
0827 
0828 
0829 static ngx_int_t
0830 ngx_stream_variable_msec(ngx_stream_session_t *s,
0831     ngx_stream_variable_value_t *v, uintptr_t data)
0832 {
0833     u_char      *p;
0834     ngx_time_t  *tp;
0835 
0836     p = ngx_pnalloc(s->connection->pool, NGX_TIME_T_LEN + 4);
0837     if (p == NULL) {
0838         return NGX_ERROR;
0839     }
0840 
0841     tp = ngx_timeofday();
0842 
0843     v->len = ngx_sprintf(p, "%T.%03M", tp->sec, tp->msec) - p;
0844     v->valid = 1;
0845     v->no_cacheable = 0;
0846     v->not_found = 0;
0847     v->data = p;
0848 
0849     return NGX_OK;
0850 }
0851 
0852 
0853 static ngx_int_t
0854 ngx_stream_variable_time_iso8601(ngx_stream_session_t *s,
0855     ngx_stream_variable_value_t *v, uintptr_t data)
0856 {
0857     u_char  *p;
0858 
0859     p = ngx_pnalloc(s->connection->pool, ngx_cached_http_log_iso8601.len);
0860     if (p == NULL) {
0861         return NGX_ERROR;
0862     }
0863 
0864     ngx_memcpy(p, ngx_cached_http_log_iso8601.data,
0865                ngx_cached_http_log_iso8601.len);
0866 
0867     v->len = ngx_cached_http_log_iso8601.len;
0868     v->valid = 1;
0869     v->no_cacheable = 0;
0870     v->not_found = 0;
0871     v->data = p;
0872 
0873     return NGX_OK;
0874 }
0875 
0876 
0877 static ngx_int_t
0878 ngx_stream_variable_time_local(ngx_stream_session_t *s,
0879     ngx_stream_variable_value_t *v, uintptr_t data)
0880 {
0881     u_char  *p;
0882 
0883     p = ngx_pnalloc(s->connection->pool, ngx_cached_http_log_time.len);
0884     if (p == NULL) {
0885         return NGX_ERROR;
0886     }
0887 
0888     ngx_memcpy(p, ngx_cached_http_log_time.data, ngx_cached_http_log_time.len);
0889 
0890     v->len = ngx_cached_http_log_time.len;
0891     v->valid = 1;
0892     v->no_cacheable = 0;
0893     v->not_found = 0;
0894     v->data = p;
0895 
0896     return NGX_OK;
0897 }
0898 
0899 
0900 static ngx_int_t
0901 ngx_stream_variable_protocol(ngx_stream_session_t *s,
0902     ngx_stream_variable_value_t *v, uintptr_t data)
0903 {
0904     v->len = 3;
0905     v->valid = 1;
0906     v->no_cacheable = 0;
0907     v->not_found = 0;
0908     v->data = (u_char *) (s->connection->type == SOCK_DGRAM ? "UDP" : "TCP");
0909 
0910     return NGX_OK;
0911 }
0912 
0913 
0914 void *
0915 ngx_stream_map_find(ngx_stream_session_t *s, ngx_stream_map_t *map,
0916     ngx_str_t *match)
0917 {
0918     void        *value;
0919     u_char      *low;
0920     size_t       len;
0921     ngx_uint_t   key;
0922 
0923     len = match->len;
0924 
0925     if (len) {
0926         low = ngx_pnalloc(s->connection->pool, len);
0927         if (low == NULL) {
0928             return NULL;
0929         }
0930 
0931     } else {
0932         low = NULL;
0933     }
0934 
0935     key = ngx_hash_strlow(low, match->data, len);
0936 
0937     value = ngx_hash_find_combined(&map->hash, key, low, len);
0938     if (value) {
0939         return value;
0940     }
0941 
0942 #if (NGX_PCRE)
0943 
0944     if (len && map->nregex) {
0945         ngx_int_t                n;
0946         ngx_uint_t               i;
0947         ngx_stream_map_regex_t  *reg;
0948 
0949         reg = map->regex;
0950 
0951         for (i = 0; i < map->nregex; i++) {
0952 
0953             n = ngx_stream_regex_exec(s, reg[i].regex, match);
0954 
0955             if (n == NGX_OK) {
0956                 return reg[i].value;
0957             }
0958 
0959             if (n == NGX_DECLINED) {
0960                 continue;
0961             }
0962 
0963             /* NGX_ERROR */
0964 
0965             return NULL;
0966         }
0967     }
0968 
0969 #endif
0970 
0971     return NULL;
0972 }
0973 
0974 
0975 #if (NGX_PCRE)
0976 
0977 static ngx_int_t
0978 ngx_stream_variable_not_found(ngx_stream_session_t *s,
0979     ngx_stream_variable_value_t *v, uintptr_t data)
0980 {
0981     v->not_found = 1;
0982     return NGX_OK;
0983 }
0984 
0985 
0986 ngx_stream_regex_t *
0987 ngx_stream_regex_compile(ngx_conf_t *cf, ngx_regex_compile_t *rc)
0988 {
0989     u_char                       *p;
0990     size_t                        size;
0991     ngx_str_t                     name;
0992     ngx_uint_t                    i, n;
0993     ngx_stream_variable_t        *v;
0994     ngx_stream_regex_t           *re;
0995     ngx_stream_regex_variable_t  *rv;
0996     ngx_stream_core_main_conf_t  *cmcf;
0997 
0998     rc->pool = cf->pool;
0999 
1000     if (ngx_regex_compile(rc) != NGX_OK) {
1001         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc->err);
1002         return NULL;
1003     }
1004 
1005     re = ngx_pcalloc(cf->pool, sizeof(ngx_stream_regex_t));
1006     if (re == NULL) {
1007         return NULL;
1008     }
1009 
1010     re->regex = rc->regex;
1011     re->ncaptures = rc->captures;
1012     re->name = rc->pattern;
1013 
1014     cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);
1015     cmcf->ncaptures = ngx_max(cmcf->ncaptures, re->ncaptures);
1016 
1017     n = (ngx_uint_t) rc->named_captures;
1018 
1019     if (n == 0) {
1020         return re;
1021     }
1022 
1023     rv = ngx_palloc(rc->pool, n * sizeof(ngx_stream_regex_variable_t));
1024     if (rv == NULL) {
1025         return NULL;
1026     }
1027 
1028     re->variables = rv;
1029     re->nvariables = n;
1030 
1031     size = rc->name_size;
1032     p = rc->names;
1033 
1034     for (i = 0; i < n; i++) {
1035         rv[i].capture = 2 * ((p[0] << 8) + p[1]);
1036 
1037         name.data = &p[2];
1038         name.len = ngx_strlen(name.data);
1039 
1040         v = ngx_stream_add_variable(cf, &name, NGX_STREAM_VAR_CHANGEABLE);
1041         if (v == NULL) {
1042             return NULL;
1043         }
1044 
1045         rv[i].index = ngx_stream_get_variable_index(cf, &name);
1046         if (rv[i].index == NGX_ERROR) {
1047             return NULL;
1048         }
1049 
1050         v->get_handler = ngx_stream_variable_not_found;
1051 
1052         p += size;
1053     }
1054 
1055     return re;
1056 }
1057 
1058 
1059 ngx_int_t
1060 ngx_stream_regex_exec(ngx_stream_session_t *s, ngx_stream_regex_t *re,
1061     ngx_str_t *str)
1062 {
1063     ngx_int_t                     rc, index;
1064     ngx_uint_t                    i, n, len;
1065     ngx_stream_variable_value_t  *vv;
1066     ngx_stream_core_main_conf_t  *cmcf;
1067 
1068     cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module);
1069 
1070     if (re->ncaptures) {
1071         len = cmcf->ncaptures;
1072 
1073         if (s->captures == NULL) {
1074             s->captures = ngx_palloc(s->connection->pool, len * sizeof(int));
1075             if (s->captures == NULL) {
1076                 return NGX_ERROR;
1077             }
1078         }
1079 
1080     } else {
1081         len = 0;
1082     }
1083 
1084     rc = ngx_regex_exec(re->regex, str, s->captures, len);
1085 
1086     if (rc == NGX_REGEX_NO_MATCHED) {
1087         return NGX_DECLINED;
1088     }
1089 
1090     if (rc < 0) {
1091         ngx_log_error(NGX_LOG_ALERT, s->connection->log, 0,
1092                       ngx_regex_exec_n " failed: %i on \"%V\" using \"%V\"",
1093                       rc, str, &re->name);
1094         return NGX_ERROR;
1095     }
1096 
1097     for (i = 0; i < re->nvariables; i++) {
1098 
1099         n = re->variables[i].capture;
1100         index = re->variables[i].index;
1101         vv = &s->variables[index];
1102 
1103         vv->len = s->captures[n + 1] - s->captures[n];
1104         vv->valid = 1;
1105         vv->no_cacheable = 0;
1106         vv->not_found = 0;
1107         vv->data = &str->data[s->captures[n]];
1108 
1109 #if (NGX_DEBUG)
1110         {
1111         ngx_stream_variable_t  *v;
1112 
1113         v = cmcf->variables.elts;
1114 
1115         ngx_log_debug2(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
1116                        "stream regex set $%V to \"%v\"", &v[index].name, vv);
1117         }
1118 #endif
1119     }
1120 
1121     s->ncaptures = rc * 2;
1122     s->captures_data = str->data;
1123 
1124     return NGX_OK;
1125 }
1126 
1127 #endif
1128 
1129 
1130 ngx_int_t
1131 ngx_stream_variables_add_core_vars(ngx_conf_t *cf)
1132 {
1133     ngx_stream_variable_t        *cv, *v;
1134     ngx_stream_core_main_conf_t  *cmcf;
1135 
1136     cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);
1137 
1138     cmcf->variables_keys = ngx_pcalloc(cf->temp_pool,
1139                                        sizeof(ngx_hash_keys_arrays_t));
1140     if (cmcf->variables_keys == NULL) {
1141         return NGX_ERROR;
1142     }
1143 
1144     cmcf->variables_keys->pool = cf->pool;
1145     cmcf->variables_keys->temp_pool = cf->pool;
1146 
1147     if (ngx_hash_keys_array_init(cmcf->variables_keys, NGX_HASH_SMALL)
1148         != NGX_OK)
1149     {
1150         return NGX_ERROR;
1151     }
1152 
1153     if (ngx_array_init(&cmcf->prefix_variables, cf->pool, 8,
1154                        sizeof(ngx_stream_variable_t))
1155         != NGX_OK)
1156     {
1157         return NGX_ERROR;
1158     }
1159 
1160     for (cv = ngx_stream_core_variables; cv->name.len; cv++) {
1161         v = ngx_stream_add_variable(cf, &cv->name, cv->flags);
1162         if (v == NULL) {
1163             return NGX_ERROR;
1164         }
1165 
1166         *v = *cv;
1167     }
1168 
1169     return NGX_OK;
1170 }
1171 
1172 
1173 ngx_int_t
1174 ngx_stream_variables_init_vars(ngx_conf_t *cf)
1175 {
1176     size_t                        len;
1177     ngx_uint_t                    i, n;
1178     ngx_hash_key_t               *key;
1179     ngx_hash_init_t               hash;
1180     ngx_stream_variable_t        *v, *av, *pv;
1181     ngx_stream_core_main_conf_t  *cmcf;
1182 
1183     /* set the handlers for the indexed stream variables */
1184 
1185     cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);
1186 
1187     v = cmcf->variables.elts;
1188     pv = cmcf->prefix_variables.elts;
1189     key = cmcf->variables_keys->keys.elts;
1190 
1191     for (i = 0; i < cmcf->variables.nelts; i++) {
1192 
1193         for (n = 0; n < cmcf->variables_keys->keys.nelts; n++) {
1194 
1195             av = key[n].value;
1196 
1197             if (v[i].name.len == key[n].key.len
1198                 && ngx_strncmp(v[i].name.data, key[n].key.data, v[i].name.len)
1199                    == 0)
1200             {
1201                 v[i].get_handler = av->get_handler;
1202                 v[i].data = av->data;
1203 
1204                 av->flags |= NGX_STREAM_VAR_INDEXED;
1205                 v[i].flags = av->flags;
1206 
1207                 av->index = i;
1208 
1209                 if (av->get_handler == NULL
1210                     || (av->flags & NGX_STREAM_VAR_WEAK))
1211                 {
1212                     break;
1213                 }
1214 
1215                 goto next;
1216             }
1217         }
1218 
1219         len = 0;
1220         av = NULL;
1221 
1222         for (n = 0; n < cmcf->prefix_variables.nelts; n++) {
1223             if (v[i].name.len >= pv[n].name.len && v[i].name.len > len
1224                 && ngx_strncmp(v[i].name.data, pv[n].name.data, pv[n].name.len)
1225                    == 0)
1226             {
1227                 av = &pv[n];
1228                 len = pv[n].name.len;
1229             }
1230         }
1231 
1232         if (av) {
1233             v[i].get_handler = av->get_handler;
1234             v[i].data = (uintptr_t) &v[i].name;
1235             v[i].flags = av->flags;
1236 
1237             goto next;
1238          }
1239 
1240         if (v[i].get_handler == NULL) {
1241             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
1242                           "unknown \"%V\" variable", &v[i].name);
1243             return NGX_ERROR;
1244         }
1245 
1246     next:
1247         continue;
1248     }
1249 
1250 
1251     for (n = 0; n < cmcf->variables_keys->keys.nelts; n++) {
1252         av = key[n].value;
1253 
1254         if (av->flags & NGX_STREAM_VAR_NOHASH) {
1255             key[n].key.data = NULL;
1256         }
1257     }
1258 
1259 
1260     hash.hash = &cmcf->variables_hash;
1261     hash.key = ngx_hash_key;
1262     hash.max_size = cmcf->variables_hash_max_size;
1263     hash.bucket_size = cmcf->variables_hash_bucket_size;
1264     hash.name = "variables_hash";
1265     hash.pool = cf->pool;
1266     hash.temp_pool = NULL;
1267 
1268     if (ngx_hash_init(&hash, cmcf->variables_keys->keys.elts,
1269                       cmcf->variables_keys->keys.nelts)
1270         != NGX_OK)
1271     {
1272         return NGX_ERROR;
1273     }
1274 
1275     cmcf->variables_keys = NULL;
1276 
1277     return NGX_OK;
1278 }