Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.13.12 ]​[ nginx-1.12.2 ]​

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