Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.15.11 ]​[ nginx-1.14.2 ]​

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