Annotation of embedaddon/nginx/src/http/ngx_http_variables.c, revision 1.1
1.1 ! misho 1:
! 2: /*
! 3: * Copyright (C) Igor Sysoev
! 4: * Copyright (C) Nginx, Inc.
! 5: */
! 6:
! 7:
! 8: #include <ngx_config.h>
! 9: #include <ngx_core.h>
! 10: #include <ngx_http.h>
! 11: #include <nginx.h>
! 12:
! 13:
! 14: static ngx_int_t ngx_http_variable_request(ngx_http_request_t *r,
! 15: ngx_http_variable_value_t *v, uintptr_t data);
! 16: static void ngx_http_variable_request_set(ngx_http_request_t *r,
! 17: ngx_http_variable_value_t *v, uintptr_t data);
! 18: static ngx_int_t ngx_http_variable_request_get_size(ngx_http_request_t *r,
! 19: ngx_http_variable_value_t *v, uintptr_t data);
! 20: static void ngx_http_variable_request_set_size(ngx_http_request_t *r,
! 21: ngx_http_variable_value_t *v, uintptr_t data);
! 22: static ngx_int_t ngx_http_variable_header(ngx_http_request_t *r,
! 23: ngx_http_variable_value_t *v, uintptr_t data);
! 24:
! 25: static ngx_int_t ngx_http_variable_cookies(ngx_http_request_t *r,
! 26: ngx_http_variable_value_t *v, uintptr_t data);
! 27: static ngx_int_t ngx_http_variable_headers(ngx_http_request_t *r,
! 28: ngx_http_variable_value_t *v, uintptr_t data);
! 29: static ngx_int_t ngx_http_variable_headers_internal(ngx_http_request_t *r,
! 30: ngx_http_variable_value_t *v, uintptr_t data, u_char sep);
! 31:
! 32: static ngx_int_t ngx_http_variable_unknown_header_in(ngx_http_request_t *r,
! 33: ngx_http_variable_value_t *v, uintptr_t data);
! 34: static ngx_int_t ngx_http_variable_unknown_header_out(ngx_http_request_t *r,
! 35: ngx_http_variable_value_t *v, uintptr_t data);
! 36: static ngx_int_t ngx_http_variable_request_line(ngx_http_request_t *r,
! 37: ngx_http_variable_value_t *v, uintptr_t data);
! 38: static ngx_int_t ngx_http_variable_cookie(ngx_http_request_t *r,
! 39: ngx_http_variable_value_t *v, uintptr_t data);
! 40: static ngx_int_t ngx_http_variable_argument(ngx_http_request_t *r,
! 41: ngx_http_variable_value_t *v, uintptr_t data);
! 42: #if (NGX_HAVE_TCP_INFO)
! 43: static ngx_int_t ngx_http_variable_tcpinfo(ngx_http_request_t *r,
! 44: ngx_http_variable_value_t *v, uintptr_t data);
! 45: #endif
! 46:
! 47: static ngx_int_t ngx_http_variable_content_length(ngx_http_request_t *r,
! 48: ngx_http_variable_value_t *v, uintptr_t data);
! 49: static ngx_int_t ngx_http_variable_host(ngx_http_request_t *r,
! 50: ngx_http_variable_value_t *v, uintptr_t data);
! 51: static ngx_int_t ngx_http_variable_binary_remote_addr(ngx_http_request_t *r,
! 52: ngx_http_variable_value_t *v, uintptr_t data);
! 53: static ngx_int_t ngx_http_variable_remote_addr(ngx_http_request_t *r,
! 54: ngx_http_variable_value_t *v, uintptr_t data);
! 55: static ngx_int_t ngx_http_variable_remote_port(ngx_http_request_t *r,
! 56: ngx_http_variable_value_t *v, uintptr_t data);
! 57: static ngx_int_t ngx_http_variable_server_addr(ngx_http_request_t *r,
! 58: ngx_http_variable_value_t *v, uintptr_t data);
! 59: static ngx_int_t ngx_http_variable_server_port(ngx_http_request_t *r,
! 60: ngx_http_variable_value_t *v, uintptr_t data);
! 61: static ngx_int_t ngx_http_variable_scheme(ngx_http_request_t *r,
! 62: ngx_http_variable_value_t *v, uintptr_t data);
! 63: static ngx_int_t ngx_http_variable_https(ngx_http_request_t *r,
! 64: ngx_http_variable_value_t *v, uintptr_t data);
! 65: static ngx_int_t ngx_http_variable_is_args(ngx_http_request_t *r,
! 66: ngx_http_variable_value_t *v, uintptr_t data);
! 67: static ngx_int_t ngx_http_variable_document_root(ngx_http_request_t *r,
! 68: ngx_http_variable_value_t *v, uintptr_t data);
! 69: static ngx_int_t ngx_http_variable_realpath_root(ngx_http_request_t *r,
! 70: ngx_http_variable_value_t *v, uintptr_t data);
! 71: static ngx_int_t ngx_http_variable_request_filename(ngx_http_request_t *r,
! 72: ngx_http_variable_value_t *v, uintptr_t data);
! 73: static ngx_int_t ngx_http_variable_server_name(ngx_http_request_t *r,
! 74: ngx_http_variable_value_t *v, uintptr_t data);
! 75: static ngx_int_t ngx_http_variable_request_method(ngx_http_request_t *r,
! 76: ngx_http_variable_value_t *v, uintptr_t data);
! 77: static ngx_int_t ngx_http_variable_remote_user(ngx_http_request_t *r,
! 78: ngx_http_variable_value_t *v, uintptr_t data);
! 79: static ngx_int_t ngx_http_variable_bytes_sent(ngx_http_request_t *r,
! 80: ngx_http_variable_value_t *v, uintptr_t data);
! 81: static ngx_int_t ngx_http_variable_body_bytes_sent(ngx_http_request_t *r,
! 82: ngx_http_variable_value_t *v, uintptr_t data);
! 83: static ngx_int_t ngx_http_variable_pipe(ngx_http_request_t *r,
! 84: ngx_http_variable_value_t *v, uintptr_t data);
! 85: static ngx_int_t ngx_http_variable_request_completion(ngx_http_request_t *r,
! 86: ngx_http_variable_value_t *v, uintptr_t data);
! 87: static ngx_int_t ngx_http_variable_request_body(ngx_http_request_t *r,
! 88: ngx_http_variable_value_t *v, uintptr_t data);
! 89: static ngx_int_t ngx_http_variable_request_body_file(ngx_http_request_t *r,
! 90: ngx_http_variable_value_t *v, uintptr_t data);
! 91: static ngx_int_t ngx_http_variable_request_length(ngx_http_request_t *r,
! 92: ngx_http_variable_value_t *v, uintptr_t data);
! 93: static ngx_int_t ngx_http_variable_request_time(ngx_http_request_t *r,
! 94: ngx_http_variable_value_t *v, uintptr_t data);
! 95: static ngx_int_t ngx_http_variable_status(ngx_http_request_t *r,
! 96: ngx_http_variable_value_t *v, uintptr_t data);
! 97:
! 98: static ngx_int_t ngx_http_variable_sent_content_type(ngx_http_request_t *r,
! 99: ngx_http_variable_value_t *v, uintptr_t data);
! 100: static ngx_int_t ngx_http_variable_sent_content_length(ngx_http_request_t *r,
! 101: ngx_http_variable_value_t *v, uintptr_t data);
! 102: static ngx_int_t ngx_http_variable_sent_location(ngx_http_request_t *r,
! 103: ngx_http_variable_value_t *v, uintptr_t data);
! 104: static ngx_int_t ngx_http_variable_sent_last_modified(ngx_http_request_t *r,
! 105: ngx_http_variable_value_t *v, uintptr_t data);
! 106: static ngx_int_t ngx_http_variable_sent_connection(ngx_http_request_t *r,
! 107: ngx_http_variable_value_t *v, uintptr_t data);
! 108: static ngx_int_t ngx_http_variable_sent_keep_alive(ngx_http_request_t *r,
! 109: ngx_http_variable_value_t *v, uintptr_t data);
! 110: static ngx_int_t ngx_http_variable_sent_transfer_encoding(ngx_http_request_t *r,
! 111: ngx_http_variable_value_t *v, uintptr_t data);
! 112:
! 113: static ngx_int_t ngx_http_variable_connection(ngx_http_request_t *r,
! 114: ngx_http_variable_value_t *v, uintptr_t data);
! 115: static ngx_int_t ngx_http_variable_connection_requests(ngx_http_request_t *r,
! 116: ngx_http_variable_value_t *v, uintptr_t data);
! 117:
! 118: static ngx_int_t ngx_http_variable_nginx_version(ngx_http_request_t *r,
! 119: ngx_http_variable_value_t *v, uintptr_t data);
! 120: static ngx_int_t ngx_http_variable_hostname(ngx_http_request_t *r,
! 121: ngx_http_variable_value_t *v, uintptr_t data);
! 122: static ngx_int_t ngx_http_variable_pid(ngx_http_request_t *r,
! 123: ngx_http_variable_value_t *v, uintptr_t data);
! 124: static ngx_int_t ngx_http_variable_msec(ngx_http_request_t *r,
! 125: ngx_http_variable_value_t *v, uintptr_t data);
! 126: static ngx_int_t ngx_http_variable_time_iso8601(ngx_http_request_t *r,
! 127: ngx_http_variable_value_t *v, uintptr_t data);
! 128: static ngx_int_t ngx_http_variable_time_local(ngx_http_request_t *r,
! 129: ngx_http_variable_value_t *v, uintptr_t data);
! 130:
! 131: /*
! 132: * TODO:
! 133: * Apache CGI: AUTH_TYPE, PATH_INFO (null), PATH_TRANSLATED
! 134: * REMOTE_HOST (null), REMOTE_IDENT (null),
! 135: * SERVER_SOFTWARE
! 136: *
! 137: * Apache SSI: DOCUMENT_NAME, LAST_MODIFIED, USER_NAME (file owner)
! 138: */
! 139:
! 140: /*
! 141: * the $http_host, $http_user_agent, $http_referer, and $http_via
! 142: * variables may be handled by generic
! 143: * ngx_http_variable_unknown_header_in(), but for performance reasons
! 144: * they are handled using dedicated entries
! 145: */
! 146:
! 147: static ngx_http_variable_t ngx_http_core_variables[] = {
! 148:
! 149: { ngx_string("http_host"), NULL, ngx_http_variable_header,
! 150: offsetof(ngx_http_request_t, headers_in.host), 0, 0 },
! 151:
! 152: { ngx_string("http_user_agent"), NULL, ngx_http_variable_header,
! 153: offsetof(ngx_http_request_t, headers_in.user_agent), 0, 0 },
! 154:
! 155: { ngx_string("http_referer"), NULL, ngx_http_variable_header,
! 156: offsetof(ngx_http_request_t, headers_in.referer), 0, 0 },
! 157:
! 158: #if (NGX_HTTP_GZIP)
! 159: { ngx_string("http_via"), NULL, ngx_http_variable_header,
! 160: offsetof(ngx_http_request_t, headers_in.via), 0, 0 },
! 161: #endif
! 162:
! 163: #if (NGX_HTTP_X_FORWARDED_FOR)
! 164: { ngx_string("http_x_forwarded_for"), NULL, ngx_http_variable_headers,
! 165: offsetof(ngx_http_request_t, headers_in.x_forwarded_for), 0, 0 },
! 166: #endif
! 167:
! 168: { ngx_string("http_cookie"), NULL, ngx_http_variable_cookies,
! 169: offsetof(ngx_http_request_t, headers_in.cookies), 0, 0 },
! 170:
! 171: { ngx_string("content_length"), NULL, ngx_http_variable_content_length,
! 172: 0, 0, 0 },
! 173:
! 174: { ngx_string("content_type"), NULL, ngx_http_variable_header,
! 175: offsetof(ngx_http_request_t, headers_in.content_type), 0, 0 },
! 176:
! 177: { ngx_string("host"), NULL, ngx_http_variable_host, 0, 0, 0 },
! 178:
! 179: { ngx_string("binary_remote_addr"), NULL,
! 180: ngx_http_variable_binary_remote_addr, 0, 0, 0 },
! 181:
! 182: { ngx_string("remote_addr"), NULL, ngx_http_variable_remote_addr, 0, 0, 0 },
! 183:
! 184: { ngx_string("remote_port"), NULL, ngx_http_variable_remote_port, 0, 0, 0 },
! 185:
! 186: { ngx_string("server_addr"), NULL, ngx_http_variable_server_addr, 0, 0, 0 },
! 187:
! 188: { ngx_string("server_port"), NULL, ngx_http_variable_server_port, 0, 0, 0 },
! 189:
! 190: { ngx_string("server_protocol"), NULL, ngx_http_variable_request,
! 191: offsetof(ngx_http_request_t, http_protocol), 0, 0 },
! 192:
! 193: { ngx_string("scheme"), NULL, ngx_http_variable_scheme, 0, 0, 0 },
! 194:
! 195: { ngx_string("https"), NULL, ngx_http_variable_https, 0, 0, 0 },
! 196:
! 197: { ngx_string("request_uri"), NULL, ngx_http_variable_request,
! 198: offsetof(ngx_http_request_t, unparsed_uri), 0, 0 },
! 199:
! 200: { ngx_string("uri"), NULL, ngx_http_variable_request,
! 201: offsetof(ngx_http_request_t, uri),
! 202: NGX_HTTP_VAR_NOCACHEABLE, 0 },
! 203:
! 204: { ngx_string("document_uri"), NULL, ngx_http_variable_request,
! 205: offsetof(ngx_http_request_t, uri),
! 206: NGX_HTTP_VAR_NOCACHEABLE, 0 },
! 207:
! 208: { ngx_string("request"), NULL, ngx_http_variable_request_line, 0, 0, 0 },
! 209:
! 210: { ngx_string("document_root"), NULL,
! 211: ngx_http_variable_document_root, 0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
! 212:
! 213: { ngx_string("realpath_root"), NULL,
! 214: ngx_http_variable_realpath_root, 0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
! 215:
! 216: { ngx_string("query_string"), NULL, ngx_http_variable_request,
! 217: offsetof(ngx_http_request_t, args),
! 218: NGX_HTTP_VAR_NOCACHEABLE, 0 },
! 219:
! 220: { ngx_string("args"),
! 221: ngx_http_variable_request_set,
! 222: ngx_http_variable_request,
! 223: offsetof(ngx_http_request_t, args),
! 224: NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE, 0 },
! 225:
! 226: { ngx_string("is_args"), NULL, ngx_http_variable_is_args,
! 227: 0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
! 228:
! 229: { ngx_string("request_filename"), NULL,
! 230: ngx_http_variable_request_filename, 0,
! 231: NGX_HTTP_VAR_NOCACHEABLE, 0 },
! 232:
! 233: { ngx_string("server_name"), NULL, ngx_http_variable_server_name, 0, 0, 0 },
! 234:
! 235: { ngx_string("request_method"), NULL,
! 236: ngx_http_variable_request_method, 0,
! 237: NGX_HTTP_VAR_NOCACHEABLE, 0 },
! 238:
! 239: { ngx_string("remote_user"), NULL, ngx_http_variable_remote_user, 0, 0, 0 },
! 240:
! 241: { ngx_string("bytes_sent"), NULL, ngx_http_variable_bytes_sent,
! 242: 0, 0, 0 },
! 243:
! 244: { ngx_string("body_bytes_sent"), NULL, ngx_http_variable_body_bytes_sent,
! 245: 0, 0, 0 },
! 246:
! 247: { ngx_string("pipe"), NULL, ngx_http_variable_pipe,
! 248: 0, 0, 0 },
! 249:
! 250: { ngx_string("request_completion"), NULL,
! 251: ngx_http_variable_request_completion,
! 252: 0, 0, 0 },
! 253:
! 254: { ngx_string("request_body"), NULL,
! 255: ngx_http_variable_request_body,
! 256: 0, 0, 0 },
! 257:
! 258: { ngx_string("request_body_file"), NULL,
! 259: ngx_http_variable_request_body_file,
! 260: 0, 0, 0 },
! 261:
! 262: { ngx_string("request_length"), NULL, ngx_http_variable_request_length,
! 263: 0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
! 264:
! 265: { ngx_string("request_time"), NULL, ngx_http_variable_request_time,
! 266: 0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
! 267:
! 268: { ngx_string("status"), NULL,
! 269: ngx_http_variable_status, 0,
! 270: NGX_HTTP_VAR_NOCACHEABLE, 0 },
! 271:
! 272: { ngx_string("sent_http_content_type"), NULL,
! 273: ngx_http_variable_sent_content_type, 0, 0, 0 },
! 274:
! 275: { ngx_string("sent_http_content_length"), NULL,
! 276: ngx_http_variable_sent_content_length, 0, 0, 0 },
! 277:
! 278: { ngx_string("sent_http_location"), NULL,
! 279: ngx_http_variable_sent_location, 0, 0, 0 },
! 280:
! 281: { ngx_string("sent_http_last_modified"), NULL,
! 282: ngx_http_variable_sent_last_modified, 0, 0, 0 },
! 283:
! 284: { ngx_string("sent_http_connection"), NULL,
! 285: ngx_http_variable_sent_connection, 0, 0, 0 },
! 286:
! 287: { ngx_string("sent_http_keep_alive"), NULL,
! 288: ngx_http_variable_sent_keep_alive, 0, 0, 0 },
! 289:
! 290: { ngx_string("sent_http_transfer_encoding"), NULL,
! 291: ngx_http_variable_sent_transfer_encoding, 0, 0, 0 },
! 292:
! 293: { ngx_string("sent_http_cache_control"), NULL, ngx_http_variable_headers,
! 294: offsetof(ngx_http_request_t, headers_out.cache_control), 0, 0 },
! 295:
! 296: { ngx_string("limit_rate"), ngx_http_variable_request_set_size,
! 297: ngx_http_variable_request_get_size,
! 298: offsetof(ngx_http_request_t, limit_rate),
! 299: NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE, 0 },
! 300:
! 301: { ngx_string("connection"), NULL,
! 302: ngx_http_variable_connection, 0, 0, 0 },
! 303:
! 304: { ngx_string("connection_requests"), NULL,
! 305: ngx_http_variable_connection_requests, 0, 0, 0 },
! 306:
! 307: { ngx_string("nginx_version"), NULL, ngx_http_variable_nginx_version,
! 308: 0, 0, 0 },
! 309:
! 310: { ngx_string("hostname"), NULL, ngx_http_variable_hostname,
! 311: 0, 0, 0 },
! 312:
! 313: { ngx_string("pid"), NULL, ngx_http_variable_pid,
! 314: 0, 0, 0 },
! 315:
! 316: { ngx_string("msec"), NULL, ngx_http_variable_msec,
! 317: 0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
! 318:
! 319: { ngx_string("time_iso8601"), NULL, ngx_http_variable_time_iso8601,
! 320: 0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
! 321:
! 322: { ngx_string("time_local"), NULL, ngx_http_variable_time_local,
! 323: 0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
! 324:
! 325: #if (NGX_HAVE_TCP_INFO)
! 326: { ngx_string("tcpinfo_rtt"), NULL, ngx_http_variable_tcpinfo,
! 327: 0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
! 328:
! 329: { ngx_string("tcpinfo_rttvar"), NULL, ngx_http_variable_tcpinfo,
! 330: 1, NGX_HTTP_VAR_NOCACHEABLE, 0 },
! 331:
! 332: { ngx_string("tcpinfo_snd_cwnd"), NULL, ngx_http_variable_tcpinfo,
! 333: 2, NGX_HTTP_VAR_NOCACHEABLE, 0 },
! 334:
! 335: { ngx_string("tcpinfo_rcv_space"), NULL, ngx_http_variable_tcpinfo,
! 336: 3, NGX_HTTP_VAR_NOCACHEABLE, 0 },
! 337: #endif
! 338:
! 339: { ngx_null_string, NULL, NULL, 0, 0, 0 }
! 340: };
! 341:
! 342:
! 343: ngx_http_variable_value_t ngx_http_variable_null_value =
! 344: ngx_http_variable("");
! 345: ngx_http_variable_value_t ngx_http_variable_true_value =
! 346: ngx_http_variable("1");
! 347:
! 348:
! 349: ngx_http_variable_t *
! 350: ngx_http_add_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t flags)
! 351: {
! 352: ngx_int_t rc;
! 353: ngx_uint_t i;
! 354: ngx_hash_key_t *key;
! 355: ngx_http_variable_t *v;
! 356: ngx_http_core_main_conf_t *cmcf;
! 357:
! 358: if (name->len == 0) {
! 359: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 360: "invalid variable name \"$\"");
! 361: return NULL;
! 362: }
! 363:
! 364: cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
! 365:
! 366: key = cmcf->variables_keys->keys.elts;
! 367: for (i = 0; i < cmcf->variables_keys->keys.nelts; i++) {
! 368: if (name->len != key[i].key.len
! 369: || ngx_strncasecmp(name->data, key[i].key.data, name->len) != 0)
! 370: {
! 371: continue;
! 372: }
! 373:
! 374: v = key[i].value;
! 375:
! 376: if (!(v->flags & NGX_HTTP_VAR_CHANGEABLE)) {
! 377: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 378: "the duplicate \"%V\" variable", name);
! 379: return NULL;
! 380: }
! 381:
! 382: return v;
! 383: }
! 384:
! 385: v = ngx_palloc(cf->pool, sizeof(ngx_http_variable_t));
! 386: if (v == NULL) {
! 387: return NULL;
! 388: }
! 389:
! 390: v->name.len = name->len;
! 391: v->name.data = ngx_pnalloc(cf->pool, name->len);
! 392: if (v->name.data == NULL) {
! 393: return NULL;
! 394: }
! 395:
! 396: ngx_strlow(v->name.data, name->data, name->len);
! 397:
! 398: v->set_handler = NULL;
! 399: v->get_handler = NULL;
! 400: v->data = 0;
! 401: v->flags = flags;
! 402: v->index = 0;
! 403:
! 404: rc = ngx_hash_add_key(cmcf->variables_keys, &v->name, v, 0);
! 405:
! 406: if (rc == NGX_ERROR) {
! 407: return NULL;
! 408: }
! 409:
! 410: if (rc == NGX_BUSY) {
! 411: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 412: "conflicting variable name \"%V\"", name);
! 413: return NULL;
! 414: }
! 415:
! 416: return v;
! 417: }
! 418:
! 419:
! 420: ngx_int_t
! 421: ngx_http_get_variable_index(ngx_conf_t *cf, ngx_str_t *name)
! 422: {
! 423: ngx_uint_t i;
! 424: ngx_http_variable_t *v;
! 425: ngx_http_core_main_conf_t *cmcf;
! 426:
! 427: if (name->len == 0) {
! 428: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 429: "invalid variable name \"$\"");
! 430: return NGX_ERROR;
! 431: }
! 432:
! 433: cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
! 434:
! 435: v = cmcf->variables.elts;
! 436:
! 437: if (v == NULL) {
! 438: if (ngx_array_init(&cmcf->variables, cf->pool, 4,
! 439: sizeof(ngx_http_variable_t))
! 440: != NGX_OK)
! 441: {
! 442: return NGX_ERROR;
! 443: }
! 444:
! 445: } else {
! 446: for (i = 0; i < cmcf->variables.nelts; i++) {
! 447: if (name->len != v[i].name.len
! 448: || ngx_strncasecmp(name->data, v[i].name.data, name->len) != 0)
! 449: {
! 450: continue;
! 451: }
! 452:
! 453: return i;
! 454: }
! 455: }
! 456:
! 457: v = ngx_array_push(&cmcf->variables);
! 458: if (v == NULL) {
! 459: return NGX_ERROR;
! 460: }
! 461:
! 462: v->name.len = name->len;
! 463: v->name.data = ngx_pnalloc(cf->pool, name->len);
! 464: if (v->name.data == NULL) {
! 465: return NGX_ERROR;
! 466: }
! 467:
! 468: ngx_strlow(v->name.data, name->data, name->len);
! 469:
! 470: v->set_handler = NULL;
! 471: v->get_handler = NULL;
! 472: v->data = 0;
! 473: v->flags = 0;
! 474: v->index = cmcf->variables.nelts - 1;
! 475:
! 476: return v->index;
! 477: }
! 478:
! 479:
! 480: ngx_http_variable_value_t *
! 481: ngx_http_get_indexed_variable(ngx_http_request_t *r, ngx_uint_t index)
! 482: {
! 483: ngx_http_variable_t *v;
! 484: ngx_http_core_main_conf_t *cmcf;
! 485:
! 486: cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
! 487:
! 488: if (cmcf->variables.nelts <= index) {
! 489: ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
! 490: "unknown variable index: %d", index);
! 491: return NULL;
! 492: }
! 493:
! 494: if (r->variables[index].not_found || r->variables[index].valid) {
! 495: return &r->variables[index];
! 496: }
! 497:
! 498: v = cmcf->variables.elts;
! 499:
! 500: if (v[index].get_handler(r, &r->variables[index], v[index].data)
! 501: == NGX_OK)
! 502: {
! 503: if (v[index].flags & NGX_HTTP_VAR_NOCACHEABLE) {
! 504: r->variables[index].no_cacheable = 1;
! 505: }
! 506:
! 507: return &r->variables[index];
! 508: }
! 509:
! 510: r->variables[index].valid = 0;
! 511: r->variables[index].not_found = 1;
! 512:
! 513: return NULL;
! 514: }
! 515:
! 516:
! 517: ngx_http_variable_value_t *
! 518: ngx_http_get_flushed_variable(ngx_http_request_t *r, ngx_uint_t index)
! 519: {
! 520: ngx_http_variable_value_t *v;
! 521:
! 522: v = &r->variables[index];
! 523:
! 524: if (v->valid || v->not_found) {
! 525: if (!v->no_cacheable) {
! 526: return v;
! 527: }
! 528:
! 529: v->valid = 0;
! 530: v->not_found = 0;
! 531: }
! 532:
! 533: return ngx_http_get_indexed_variable(r, index);
! 534: }
! 535:
! 536:
! 537: ngx_http_variable_value_t *
! 538: ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name, ngx_uint_t key)
! 539: {
! 540: ngx_http_variable_t *v;
! 541: ngx_http_variable_value_t *vv;
! 542: ngx_http_core_main_conf_t *cmcf;
! 543:
! 544: cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
! 545:
! 546: v = ngx_hash_find(&cmcf->variables_hash, key, name->data, name->len);
! 547:
! 548: if (v) {
! 549: if (v->flags & NGX_HTTP_VAR_INDEXED) {
! 550: return ngx_http_get_flushed_variable(r, v->index);
! 551:
! 552: } else {
! 553:
! 554: vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
! 555:
! 556: if (vv && v->get_handler(r, vv, v->data) == NGX_OK) {
! 557: return vv;
! 558: }
! 559:
! 560: return NULL;
! 561: }
! 562: }
! 563:
! 564: vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
! 565: if (vv == NULL) {
! 566: return NULL;
! 567: }
! 568:
! 569: if (ngx_strncmp(name->data, "http_", 5) == 0) {
! 570:
! 571: if (ngx_http_variable_unknown_header_in(r, vv, (uintptr_t) name)
! 572: == NGX_OK)
! 573: {
! 574: return vv;
! 575: }
! 576:
! 577: return NULL;
! 578: }
! 579:
! 580: if (ngx_strncmp(name->data, "sent_http_", 10) == 0) {
! 581:
! 582: if (ngx_http_variable_unknown_header_out(r, vv, (uintptr_t) name)
! 583: == NGX_OK)
! 584: {
! 585: return vv;
! 586: }
! 587:
! 588: return NULL;
! 589: }
! 590:
! 591: if (ngx_strncmp(name->data, "upstream_http_", 14) == 0) {
! 592:
! 593: if (ngx_http_upstream_header_variable(r, vv, (uintptr_t) name)
! 594: == NGX_OK)
! 595: {
! 596: return vv;
! 597: }
! 598:
! 599: return NULL;
! 600: }
! 601:
! 602: if (ngx_strncmp(name->data, "cookie_", 7) == 0) {
! 603:
! 604: if (ngx_http_variable_cookie(r, vv, (uintptr_t) name) == NGX_OK) {
! 605: return vv;
! 606: }
! 607:
! 608: return NULL;
! 609: }
! 610:
! 611: if (ngx_strncmp(name->data, "arg_", 4) == 0) {
! 612:
! 613: if (ngx_http_variable_argument(r, vv, (uintptr_t) name) == NGX_OK) {
! 614: return vv;
! 615: }
! 616:
! 617: return NULL;
! 618: }
! 619:
! 620: vv->not_found = 1;
! 621:
! 622: return vv;
! 623: }
! 624:
! 625:
! 626: static ngx_int_t
! 627: ngx_http_variable_request(ngx_http_request_t *r, ngx_http_variable_value_t *v,
! 628: uintptr_t data)
! 629: {
! 630: ngx_str_t *s;
! 631:
! 632: s = (ngx_str_t *) ((char *) r + data);
! 633:
! 634: if (s->data) {
! 635: v->len = s->len;
! 636: v->valid = 1;
! 637: v->no_cacheable = 0;
! 638: v->not_found = 0;
! 639: v->data = s->data;
! 640:
! 641: } else {
! 642: v->not_found = 1;
! 643: }
! 644:
! 645: return NGX_OK;
! 646: }
! 647:
! 648:
! 649: static void
! 650: ngx_http_variable_request_set(ngx_http_request_t *r,
! 651: ngx_http_variable_value_t *v, uintptr_t data)
! 652: {
! 653: ngx_str_t *s;
! 654:
! 655: s = (ngx_str_t *) ((char *) r + data);
! 656:
! 657: s->len = v->len;
! 658: s->data = v->data;
! 659: }
! 660:
! 661:
! 662: static ngx_int_t
! 663: ngx_http_variable_request_get_size(ngx_http_request_t *r,
! 664: ngx_http_variable_value_t *v, uintptr_t data)
! 665: {
! 666: size_t *sp;
! 667:
! 668: sp = (size_t *) ((char *) r + data);
! 669:
! 670: v->data = ngx_pnalloc(r->pool, NGX_SIZE_T_LEN);
! 671: if (v->data == NULL) {
! 672: return NGX_ERROR;
! 673: }
! 674:
! 675: v->len = ngx_sprintf(v->data, "%uz", *sp) - v->data;
! 676: v->valid = 1;
! 677: v->no_cacheable = 0;
! 678: v->not_found = 0;
! 679:
! 680: return NGX_OK;
! 681: }
! 682:
! 683:
! 684: static void
! 685: ngx_http_variable_request_set_size(ngx_http_request_t *r,
! 686: ngx_http_variable_value_t *v, uintptr_t data)
! 687: {
! 688: ssize_t s, *sp;
! 689: ngx_str_t val;
! 690:
! 691: val.len = v->len;
! 692: val.data = v->data;
! 693:
! 694: s = ngx_parse_size(&val);
! 695:
! 696: if (s == NGX_ERROR) {
! 697: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
! 698: "invalid size \"%V\"", &val);
! 699: return;
! 700: }
! 701:
! 702: sp = (ssize_t *) ((char *) r + data);
! 703:
! 704: *sp = s;
! 705:
! 706: return;
! 707: }
! 708:
! 709:
! 710: static ngx_int_t
! 711: ngx_http_variable_header(ngx_http_request_t *r, ngx_http_variable_value_t *v,
! 712: uintptr_t data)
! 713: {
! 714: ngx_table_elt_t *h;
! 715:
! 716: h = *(ngx_table_elt_t **) ((char *) r + data);
! 717:
! 718: if (h) {
! 719: v->len = h->value.len;
! 720: v->valid = 1;
! 721: v->no_cacheable = 0;
! 722: v->not_found = 0;
! 723: v->data = h->value.data;
! 724:
! 725: } else {
! 726: v->not_found = 1;
! 727: }
! 728:
! 729: return NGX_OK;
! 730: }
! 731:
! 732:
! 733: static ngx_int_t
! 734: ngx_http_variable_cookies(ngx_http_request_t *r,
! 735: ngx_http_variable_value_t *v, uintptr_t data)
! 736: {
! 737: return ngx_http_variable_headers_internal(r, v, data, ';');
! 738: }
! 739:
! 740:
! 741: static ngx_int_t
! 742: ngx_http_variable_headers(ngx_http_request_t *r,
! 743: ngx_http_variable_value_t *v, uintptr_t data)
! 744: {
! 745: return ngx_http_variable_headers_internal(r, v, data, ',');
! 746: }
! 747:
! 748:
! 749: static ngx_int_t
! 750: ngx_http_variable_headers_internal(ngx_http_request_t *r,
! 751: ngx_http_variable_value_t *v, uintptr_t data, u_char sep)
! 752: {
! 753: size_t len;
! 754: u_char *p, *end;
! 755: ngx_uint_t i, n;
! 756: ngx_array_t *a;
! 757: ngx_table_elt_t **h;
! 758:
! 759: a = (ngx_array_t *) ((char *) r + data);
! 760:
! 761: n = a->nelts;
! 762: h = a->elts;
! 763:
! 764: len = 0;
! 765:
! 766: for (i = 0; i < n; i++) {
! 767:
! 768: if (h[i]->hash == 0) {
! 769: continue;
! 770: }
! 771:
! 772: len += h[i]->value.len + 2;
! 773: }
! 774:
! 775: if (len == 0) {
! 776: v->not_found = 1;
! 777: return NGX_OK;
! 778: }
! 779:
! 780: len -= 2;
! 781:
! 782: v->valid = 1;
! 783: v->no_cacheable = 0;
! 784: v->not_found = 0;
! 785:
! 786: if (n == 1) {
! 787: v->len = (*h)->value.len;
! 788: v->data = (*h)->value.data;
! 789:
! 790: return NGX_OK;
! 791: }
! 792:
! 793: p = ngx_pnalloc(r->pool, len);
! 794: if (p == NULL) {
! 795: return NGX_ERROR;
! 796: }
! 797:
! 798: v->len = len;
! 799: v->data = p;
! 800:
! 801: end = p + len;
! 802:
! 803: for (i = 0; /* void */ ; i++) {
! 804:
! 805: if (h[i]->hash == 0) {
! 806: continue;
! 807: }
! 808:
! 809: p = ngx_copy(p, h[i]->value.data, h[i]->value.len);
! 810:
! 811: if (p == end) {
! 812: break;
! 813: }
! 814:
! 815: *p++ = sep; *p++ = ' ';
! 816: }
! 817:
! 818: return NGX_OK;
! 819: }
! 820:
! 821:
! 822: static ngx_int_t
! 823: ngx_http_variable_unknown_header_in(ngx_http_request_t *r,
! 824: ngx_http_variable_value_t *v, uintptr_t data)
! 825: {
! 826: return ngx_http_variable_unknown_header(v, (ngx_str_t *) data,
! 827: &r->headers_in.headers.part,
! 828: sizeof("http_") - 1);
! 829: }
! 830:
! 831:
! 832: static ngx_int_t
! 833: ngx_http_variable_unknown_header_out(ngx_http_request_t *r,
! 834: ngx_http_variable_value_t *v, uintptr_t data)
! 835: {
! 836: return ngx_http_variable_unknown_header(v, (ngx_str_t *) data,
! 837: &r->headers_out.headers.part,
! 838: sizeof("sent_http_") - 1);
! 839: }
! 840:
! 841:
! 842: ngx_int_t
! 843: ngx_http_variable_unknown_header(ngx_http_variable_value_t *v, ngx_str_t *var,
! 844: ngx_list_part_t *part, size_t prefix)
! 845: {
! 846: u_char ch;
! 847: ngx_uint_t i, n;
! 848: ngx_table_elt_t *header;
! 849:
! 850: header = part->elts;
! 851:
! 852: for (i = 0; /* void */ ; i++) {
! 853:
! 854: if (i >= part->nelts) {
! 855: if (part->next == NULL) {
! 856: break;
! 857: }
! 858:
! 859: part = part->next;
! 860: header = part->elts;
! 861: i = 0;
! 862: }
! 863:
! 864: if (header[i].hash == 0) {
! 865: continue;
! 866: }
! 867:
! 868: for (n = 0; n + prefix < var->len && n < header[i].key.len; n++) {
! 869: ch = header[i].key.data[n];
! 870:
! 871: if (ch >= 'A' && ch <= 'Z') {
! 872: ch |= 0x20;
! 873:
! 874: } else if (ch == '-') {
! 875: ch = '_';
! 876: }
! 877:
! 878: if (var->data[n + prefix] != ch) {
! 879: break;
! 880: }
! 881: }
! 882:
! 883: if (n + prefix == var->len && n == header[i].key.len) {
! 884: v->len = header[i].value.len;
! 885: v->valid = 1;
! 886: v->no_cacheable = 0;
! 887: v->not_found = 0;
! 888: v->data = header[i].value.data;
! 889:
! 890: return NGX_OK;
! 891: }
! 892: }
! 893:
! 894: v->not_found = 1;
! 895:
! 896: return NGX_OK;
! 897: }
! 898:
! 899:
! 900: static ngx_int_t
! 901: ngx_http_variable_request_line(ngx_http_request_t *r,
! 902: ngx_http_variable_value_t *v, uintptr_t data)
! 903: {
! 904: u_char *p, *s;
! 905:
! 906: s = r->request_line.data;
! 907:
! 908: if (s == NULL) {
! 909: s = r->request_start;
! 910:
! 911: if (s == NULL) {
! 912: v->not_found = 1;
! 913: return NGX_OK;
! 914: }
! 915:
! 916: for (p = s; p < r->header_in->last; p++) {
! 917: if (*p == CR || *p == LF) {
! 918: break;
! 919: }
! 920: }
! 921:
! 922: r->request_line.len = p - s;
! 923: r->request_line.data = s;
! 924: }
! 925:
! 926: v->len = r->request_line.len;
! 927: v->valid = 1;
! 928: v->no_cacheable = 0;
! 929: v->not_found = 0;
! 930: v->data = s;
! 931:
! 932: return NGX_OK;
! 933: }
! 934:
! 935:
! 936: static ngx_int_t
! 937: ngx_http_variable_cookie(ngx_http_request_t *r, ngx_http_variable_value_t *v,
! 938: uintptr_t data)
! 939: {
! 940: ngx_str_t *name = (ngx_str_t *) data;
! 941:
! 942: ngx_str_t cookie, s;
! 943:
! 944: s.len = name->len - (sizeof("cookie_") - 1);
! 945: s.data = name->data + sizeof("cookie_") - 1;
! 946:
! 947: if (ngx_http_parse_multi_header_lines(&r->headers_in.cookies, &s, &cookie)
! 948: == NGX_DECLINED)
! 949: {
! 950: v->not_found = 1;
! 951: return NGX_OK;
! 952: }
! 953:
! 954: v->len = cookie.len;
! 955: v->valid = 1;
! 956: v->no_cacheable = 0;
! 957: v->not_found = 0;
! 958: v->data = cookie.data;
! 959:
! 960: return NGX_OK;
! 961: }
! 962:
! 963:
! 964: static ngx_int_t
! 965: ngx_http_variable_argument(ngx_http_request_t *r, ngx_http_variable_value_t *v,
! 966: uintptr_t data)
! 967: {
! 968: ngx_str_t *name = (ngx_str_t *) data;
! 969:
! 970: u_char *arg;
! 971: size_t len;
! 972: ngx_str_t value;
! 973:
! 974: len = name->len - (sizeof("arg_") - 1);
! 975: arg = name->data + sizeof("arg_") - 1;
! 976:
! 977: if (ngx_http_arg(r, arg, len, &value) != NGX_OK) {
! 978: v->not_found = 1;
! 979: return NGX_OK;
! 980: }
! 981:
! 982: v->data = value.data;
! 983: v->len = value.len;
! 984: v->valid = 1;
! 985: v->no_cacheable = 0;
! 986: v->not_found = 0;
! 987:
! 988: return NGX_OK;
! 989: }
! 990:
! 991:
! 992: #if (NGX_HAVE_TCP_INFO)
! 993:
! 994: static ngx_int_t
! 995: ngx_http_variable_tcpinfo(ngx_http_request_t *r, ngx_http_variable_value_t *v,
! 996: uintptr_t data)
! 997: {
! 998: struct tcp_info ti;
! 999: socklen_t len;
! 1000: uint32_t value;
! 1001:
! 1002: len = sizeof(struct tcp_info);
! 1003: if (getsockopt(r->connection->fd, IPPROTO_TCP, TCP_INFO, &ti, &len) == -1) {
! 1004: v->not_found = 1;
! 1005: return NGX_OK;
! 1006: }
! 1007:
! 1008: v->data = ngx_pnalloc(r->pool, NGX_INT32_LEN);
! 1009: if (v->data == NULL) {
! 1010: return NGX_ERROR;
! 1011: }
! 1012:
! 1013: switch (data) {
! 1014: case 0:
! 1015: value = ti.tcpi_rtt;
! 1016: break;
! 1017:
! 1018: case 1:
! 1019: value = ti.tcpi_rttvar;
! 1020: break;
! 1021:
! 1022: case 2:
! 1023: value = ti.tcpi_snd_cwnd;
! 1024: break;
! 1025:
! 1026: case 3:
! 1027: value = ti.tcpi_rcv_space;
! 1028: break;
! 1029:
! 1030: /* suppress warning */
! 1031: default:
! 1032: value = 0;
! 1033: break;
! 1034: }
! 1035:
! 1036: v->len = ngx_sprintf(v->data, "%uD", value) - v->data;
! 1037: v->valid = 1;
! 1038: v->no_cacheable = 0;
! 1039: v->not_found = 0;
! 1040:
! 1041: return NGX_OK;
! 1042: }
! 1043:
! 1044: #endif
! 1045:
! 1046:
! 1047: static ngx_int_t
! 1048: ngx_http_variable_content_length(ngx_http_request_t *r,
! 1049: ngx_http_variable_value_t *v, uintptr_t data)
! 1050: {
! 1051: u_char *p;
! 1052:
! 1053: if (r->headers_in.content_length) {
! 1054: v->len = r->headers_in.content_length->value.len;
! 1055: v->data = r->headers_in.content_length->value.data;
! 1056: v->valid = 1;
! 1057: v->no_cacheable = 0;
! 1058: v->not_found = 0;
! 1059:
! 1060: } else if (r->headers_in.content_length_n >= 0) {
! 1061: p = ngx_pnalloc(r->pool, NGX_OFF_T_LEN);
! 1062: if (p == NULL) {
! 1063: return NGX_ERROR;
! 1064: }
! 1065:
! 1066: v->len = ngx_sprintf(p, "%O", r->headers_in.content_length_n) - p;
! 1067: v->data = p;
! 1068: v->valid = 1;
! 1069: v->no_cacheable = 0;
! 1070: v->not_found = 0;
! 1071:
! 1072: } else {
! 1073: v->not_found = 1;
! 1074: }
! 1075:
! 1076: return NGX_OK;
! 1077: }
! 1078:
! 1079:
! 1080: static ngx_int_t
! 1081: ngx_http_variable_host(ngx_http_request_t *r, ngx_http_variable_value_t *v,
! 1082: uintptr_t data)
! 1083: {
! 1084: ngx_http_core_srv_conf_t *cscf;
! 1085:
! 1086: if (r->headers_in.server.len) {
! 1087: v->len = r->headers_in.server.len;
! 1088: v->data = r->headers_in.server.data;
! 1089:
! 1090: } else {
! 1091: cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
! 1092:
! 1093: v->len = cscf->server_name.len;
! 1094: v->data = cscf->server_name.data;
! 1095: }
! 1096:
! 1097: v->valid = 1;
! 1098: v->no_cacheable = 0;
! 1099: v->not_found = 0;
! 1100:
! 1101: return NGX_OK;
! 1102: }
! 1103:
! 1104:
! 1105: static ngx_int_t
! 1106: ngx_http_variable_binary_remote_addr(ngx_http_request_t *r,
! 1107: ngx_http_variable_value_t *v, uintptr_t data)
! 1108: {
! 1109: struct sockaddr_in *sin;
! 1110: #if (NGX_HAVE_INET6)
! 1111: struct sockaddr_in6 *sin6;
! 1112: #endif
! 1113:
! 1114: switch (r->connection->sockaddr->sa_family) {
! 1115:
! 1116: #if (NGX_HAVE_INET6)
! 1117: case AF_INET6:
! 1118: sin6 = (struct sockaddr_in6 *) r->connection->sockaddr;
! 1119:
! 1120: v->len = sizeof(struct in6_addr);
! 1121: v->valid = 1;
! 1122: v->no_cacheable = 0;
! 1123: v->not_found = 0;
! 1124: v->data = sin6->sin6_addr.s6_addr;
! 1125:
! 1126: break;
! 1127: #endif
! 1128:
! 1129: default: /* AF_INET */
! 1130: sin = (struct sockaddr_in *) r->connection->sockaddr;
! 1131:
! 1132: v->len = sizeof(in_addr_t);
! 1133: v->valid = 1;
! 1134: v->no_cacheable = 0;
! 1135: v->not_found = 0;
! 1136: v->data = (u_char *) &sin->sin_addr;
! 1137:
! 1138: break;
! 1139: }
! 1140:
! 1141: return NGX_OK;
! 1142: }
! 1143:
! 1144:
! 1145: static ngx_int_t
! 1146: ngx_http_variable_remote_addr(ngx_http_request_t *r,
! 1147: ngx_http_variable_value_t *v, uintptr_t data)
! 1148: {
! 1149: v->len = r->connection->addr_text.len;
! 1150: v->valid = 1;
! 1151: v->no_cacheable = 0;
! 1152: v->not_found = 0;
! 1153: v->data = r->connection->addr_text.data;
! 1154:
! 1155: return NGX_OK;
! 1156: }
! 1157:
! 1158:
! 1159: static ngx_int_t
! 1160: ngx_http_variable_remote_port(ngx_http_request_t *r,
! 1161: ngx_http_variable_value_t *v, uintptr_t data)
! 1162: {
! 1163: ngx_uint_t port;
! 1164: struct sockaddr_in *sin;
! 1165: #if (NGX_HAVE_INET6)
! 1166: struct sockaddr_in6 *sin6;
! 1167: #endif
! 1168:
! 1169: v->len = 0;
! 1170: v->valid = 1;
! 1171: v->no_cacheable = 0;
! 1172: v->not_found = 0;
! 1173:
! 1174: v->data = ngx_pnalloc(r->pool, sizeof("65535") - 1);
! 1175: if (v->data == NULL) {
! 1176: return NGX_ERROR;
! 1177: }
! 1178:
! 1179: switch (r->connection->sockaddr->sa_family) {
! 1180:
! 1181: #if (NGX_HAVE_INET6)
! 1182: case AF_INET6:
! 1183: sin6 = (struct sockaddr_in6 *) r->connection->sockaddr;
! 1184: port = ntohs(sin6->sin6_port);
! 1185: break;
! 1186: #endif
! 1187:
! 1188: default: /* AF_INET */
! 1189: sin = (struct sockaddr_in *) r->connection->sockaddr;
! 1190: port = ntohs(sin->sin_port);
! 1191: break;
! 1192: }
! 1193:
! 1194: if (port > 0 && port < 65536) {
! 1195: v->len = ngx_sprintf(v->data, "%ui", port) - v->data;
! 1196: }
! 1197:
! 1198: return NGX_OK;
! 1199: }
! 1200:
! 1201:
! 1202: static ngx_int_t
! 1203: ngx_http_variable_server_addr(ngx_http_request_t *r,
! 1204: ngx_http_variable_value_t *v, uintptr_t data)
! 1205: {
! 1206: ngx_str_t s;
! 1207: u_char addr[NGX_SOCKADDR_STRLEN];
! 1208:
! 1209: s.len = NGX_SOCKADDR_STRLEN;
! 1210: s.data = addr;
! 1211:
! 1212: if (ngx_connection_local_sockaddr(r->connection, &s, 0) != NGX_OK) {
! 1213: return NGX_ERROR;
! 1214: }
! 1215:
! 1216: s.data = ngx_pnalloc(r->pool, s.len);
! 1217: if (s.data == NULL) {
! 1218: return NGX_ERROR;
! 1219: }
! 1220:
! 1221: ngx_memcpy(s.data, addr, s.len);
! 1222:
! 1223: v->len = s.len;
! 1224: v->valid = 1;
! 1225: v->no_cacheable = 0;
! 1226: v->not_found = 0;
! 1227: v->data = s.data;
! 1228:
! 1229: return NGX_OK;
! 1230: }
! 1231:
! 1232:
! 1233: static ngx_int_t
! 1234: ngx_http_variable_server_port(ngx_http_request_t *r,
! 1235: ngx_http_variable_value_t *v, uintptr_t data)
! 1236: {
! 1237: ngx_uint_t port;
! 1238: struct sockaddr_in *sin;
! 1239: #if (NGX_HAVE_INET6)
! 1240: struct sockaddr_in6 *sin6;
! 1241: #endif
! 1242:
! 1243: v->len = 0;
! 1244: v->valid = 1;
! 1245: v->no_cacheable = 0;
! 1246: v->not_found = 0;
! 1247:
! 1248: if (ngx_connection_local_sockaddr(r->connection, NULL, 0) != NGX_OK) {
! 1249: return NGX_ERROR;
! 1250: }
! 1251:
! 1252: v->data = ngx_pnalloc(r->pool, sizeof("65535") - 1);
! 1253: if (v->data == NULL) {
! 1254: return NGX_ERROR;
! 1255: }
! 1256:
! 1257: switch (r->connection->local_sockaddr->sa_family) {
! 1258:
! 1259: #if (NGX_HAVE_INET6)
! 1260: case AF_INET6:
! 1261: sin6 = (struct sockaddr_in6 *) r->connection->local_sockaddr;
! 1262: port = ntohs(sin6->sin6_port);
! 1263: break;
! 1264: #endif
! 1265:
! 1266: default: /* AF_INET */
! 1267: sin = (struct sockaddr_in *) r->connection->local_sockaddr;
! 1268: port = ntohs(sin->sin_port);
! 1269: break;
! 1270: }
! 1271:
! 1272: if (port > 0 && port < 65536) {
! 1273: v->len = ngx_sprintf(v->data, "%ui", port) - v->data;
! 1274: }
! 1275:
! 1276: return NGX_OK;
! 1277: }
! 1278:
! 1279:
! 1280: static ngx_int_t
! 1281: ngx_http_variable_scheme(ngx_http_request_t *r,
! 1282: ngx_http_variable_value_t *v, uintptr_t data)
! 1283: {
! 1284: #if (NGX_HTTP_SSL)
! 1285:
! 1286: if (r->connection->ssl) {
! 1287: v->len = sizeof("https") - 1;
! 1288: v->valid = 1;
! 1289: v->no_cacheable = 0;
! 1290: v->not_found = 0;
! 1291: v->data = (u_char *) "https";
! 1292:
! 1293: return NGX_OK;
! 1294: }
! 1295:
! 1296: #endif
! 1297:
! 1298: v->len = sizeof("http") - 1;
! 1299: v->valid = 1;
! 1300: v->no_cacheable = 0;
! 1301: v->not_found = 0;
! 1302: v->data = (u_char *) "http";
! 1303:
! 1304: return NGX_OK;
! 1305: }
! 1306:
! 1307:
! 1308: static ngx_int_t
! 1309: ngx_http_variable_https(ngx_http_request_t *r,
! 1310: ngx_http_variable_value_t *v, uintptr_t data)
! 1311: {
! 1312: #if (NGX_HTTP_SSL)
! 1313:
! 1314: if (r->connection->ssl) {
! 1315: v->len = sizeof("on") - 1;
! 1316: v->valid = 1;
! 1317: v->no_cacheable = 0;
! 1318: v->not_found = 0;
! 1319: v->data = (u_char *) "on";
! 1320:
! 1321: return NGX_OK;
! 1322: }
! 1323:
! 1324: #endif
! 1325:
! 1326: *v = ngx_http_variable_null_value;
! 1327:
! 1328: return NGX_OK;
! 1329: }
! 1330:
! 1331:
! 1332: static ngx_int_t
! 1333: ngx_http_variable_is_args(ngx_http_request_t *r,
! 1334: ngx_http_variable_value_t *v, uintptr_t data)
! 1335: {
! 1336: v->valid = 1;
! 1337: v->no_cacheable = 0;
! 1338: v->not_found = 0;
! 1339:
! 1340: if (r->args.len == 0) {
! 1341: v->len = 0;
! 1342: v->data = NULL;
! 1343: return NGX_OK;
! 1344: }
! 1345:
! 1346: v->len = 1;
! 1347: v->data = (u_char *) "?";
! 1348:
! 1349: return NGX_OK;
! 1350: }
! 1351:
! 1352:
! 1353: static ngx_int_t
! 1354: ngx_http_variable_document_root(ngx_http_request_t *r,
! 1355: ngx_http_variable_value_t *v, uintptr_t data)
! 1356: {
! 1357: ngx_str_t path;
! 1358: ngx_http_core_loc_conf_t *clcf;
! 1359:
! 1360: clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
! 1361:
! 1362: if (clcf->root_lengths == NULL) {
! 1363: v->len = clcf->root.len;
! 1364: v->valid = 1;
! 1365: v->no_cacheable = 0;
! 1366: v->not_found = 0;
! 1367: v->data = clcf->root.data;
! 1368:
! 1369: } else {
! 1370: if (ngx_http_script_run(r, &path, clcf->root_lengths->elts, 0,
! 1371: clcf->root_values->elts)
! 1372: == NULL)
! 1373: {
! 1374: return NGX_ERROR;
! 1375: }
! 1376:
! 1377: if (ngx_conf_full_name((ngx_cycle_t *) ngx_cycle, &path, 0) != NGX_OK) {
! 1378: return NGX_ERROR;
! 1379: }
! 1380:
! 1381: v->len = path.len;
! 1382: v->valid = 1;
! 1383: v->no_cacheable = 0;
! 1384: v->not_found = 0;
! 1385: v->data = path.data;
! 1386: }
! 1387:
! 1388: return NGX_OK;
! 1389: }
! 1390:
! 1391:
! 1392: static ngx_int_t
! 1393: ngx_http_variable_realpath_root(ngx_http_request_t *r,
! 1394: ngx_http_variable_value_t *v, uintptr_t data)
! 1395: {
! 1396: u_char *real;
! 1397: size_t len;
! 1398: ngx_str_t path;
! 1399: ngx_http_core_loc_conf_t *clcf;
! 1400: #if (NGX_HAVE_MAX_PATH)
! 1401: u_char buffer[NGX_MAX_PATH];
! 1402: #endif
! 1403:
! 1404: clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
! 1405:
! 1406: if (clcf->root_lengths == NULL) {
! 1407: path = clcf->root;
! 1408:
! 1409: } else {
! 1410: if (ngx_http_script_run(r, &path, clcf->root_lengths->elts, 1,
! 1411: clcf->root_values->elts)
! 1412: == NULL)
! 1413: {
! 1414: return NGX_ERROR;
! 1415: }
! 1416:
! 1417: path.data[path.len - 1] = '\0';
! 1418:
! 1419: if (ngx_conf_full_name((ngx_cycle_t *) ngx_cycle, &path, 0) != NGX_OK) {
! 1420: return NGX_ERROR;
! 1421: }
! 1422: }
! 1423:
! 1424: #if (NGX_HAVE_MAX_PATH)
! 1425: real = buffer;
! 1426: #else
! 1427: real = NULL;
! 1428: #endif
! 1429:
! 1430: real = ngx_realpath(path.data, real);
! 1431:
! 1432: if (real == NULL) {
! 1433: ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
! 1434: ngx_realpath_n " \"%s\" failed", path.data);
! 1435: return NGX_ERROR;
! 1436: }
! 1437:
! 1438: len = ngx_strlen(real);
! 1439:
! 1440: v->data = ngx_pnalloc(r->pool, len);
! 1441: if (v->data == NULL) {
! 1442: #if !(NGX_HAVE_MAX_PATH)
! 1443: ngx_free(real);
! 1444: #endif
! 1445: return NGX_ERROR;
! 1446: }
! 1447:
! 1448: v->len = len;
! 1449: v->valid = 1;
! 1450: v->no_cacheable = 0;
! 1451: v->not_found = 0;
! 1452:
! 1453: ngx_memcpy(v->data, real, len);
! 1454:
! 1455: #if !(NGX_HAVE_MAX_PATH)
! 1456: ngx_free(real);
! 1457: #endif
! 1458:
! 1459: return NGX_OK;
! 1460: }
! 1461:
! 1462:
! 1463: static ngx_int_t
! 1464: ngx_http_variable_request_filename(ngx_http_request_t *r,
! 1465: ngx_http_variable_value_t *v, uintptr_t data)
! 1466: {
! 1467: size_t root;
! 1468: ngx_str_t path;
! 1469:
! 1470: if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) {
! 1471: return NGX_ERROR;
! 1472: }
! 1473:
! 1474: /* ngx_http_map_uri_to_path() allocates memory for terminating '\0' */
! 1475:
! 1476: v->len = path.len - 1;
! 1477: v->valid = 1;
! 1478: v->no_cacheable = 0;
! 1479: v->not_found = 0;
! 1480: v->data = path.data;
! 1481:
! 1482: return NGX_OK;
! 1483: }
! 1484:
! 1485:
! 1486: static ngx_int_t
! 1487: ngx_http_variable_server_name(ngx_http_request_t *r,
! 1488: ngx_http_variable_value_t *v, uintptr_t data)
! 1489: {
! 1490: ngx_http_core_srv_conf_t *cscf;
! 1491:
! 1492: cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
! 1493:
! 1494: v->len = cscf->server_name.len;
! 1495: v->valid = 1;
! 1496: v->no_cacheable = 0;
! 1497: v->not_found = 0;
! 1498: v->data = cscf->server_name.data;
! 1499:
! 1500: return NGX_OK;
! 1501: }
! 1502:
! 1503:
! 1504: static ngx_int_t
! 1505: ngx_http_variable_request_method(ngx_http_request_t *r,
! 1506: ngx_http_variable_value_t *v, uintptr_t data)
! 1507: {
! 1508: if (r->main->method_name.data) {
! 1509: v->len = r->main->method_name.len;
! 1510: v->valid = 1;
! 1511: v->no_cacheable = 0;
! 1512: v->not_found = 0;
! 1513: v->data = r->main->method_name.data;
! 1514:
! 1515: } else {
! 1516: v->not_found = 1;
! 1517: }
! 1518:
! 1519: return NGX_OK;
! 1520: }
! 1521:
! 1522:
! 1523: static ngx_int_t
! 1524: ngx_http_variable_remote_user(ngx_http_request_t *r,
! 1525: ngx_http_variable_value_t *v, uintptr_t data)
! 1526: {
! 1527: ngx_int_t rc;
! 1528:
! 1529: rc = ngx_http_auth_basic_user(r);
! 1530:
! 1531: if (rc == NGX_DECLINED) {
! 1532: v->not_found = 1;
! 1533: return NGX_OK;
! 1534: }
! 1535:
! 1536: if (rc == NGX_ERROR) {
! 1537: return NGX_ERROR;
! 1538: }
! 1539:
! 1540: v->len = r->headers_in.user.len;
! 1541: v->valid = 1;
! 1542: v->no_cacheable = 0;
! 1543: v->not_found = 0;
! 1544: v->data = r->headers_in.user.data;
! 1545:
! 1546: return NGX_OK;
! 1547: }
! 1548:
! 1549:
! 1550: static ngx_int_t
! 1551: ngx_http_variable_bytes_sent(ngx_http_request_t *r,
! 1552: ngx_http_variable_value_t *v, uintptr_t data)
! 1553: {
! 1554: u_char *p;
! 1555:
! 1556: p = ngx_pnalloc(r->pool, NGX_OFF_T_LEN);
! 1557: if (p == NULL) {
! 1558: return NGX_ERROR;
! 1559: }
! 1560:
! 1561: v->len = ngx_sprintf(p, "%O", r->connection->sent) - p;
! 1562: v->valid = 1;
! 1563: v->no_cacheable = 0;
! 1564: v->not_found = 0;
! 1565: v->data = p;
! 1566:
! 1567: return NGX_OK;
! 1568: }
! 1569:
! 1570:
! 1571: static ngx_int_t
! 1572: ngx_http_variable_body_bytes_sent(ngx_http_request_t *r,
! 1573: ngx_http_variable_value_t *v, uintptr_t data)
! 1574: {
! 1575: off_t sent;
! 1576: u_char *p;
! 1577:
! 1578: sent = r->connection->sent - r->header_size;
! 1579:
! 1580: if (sent < 0) {
! 1581: sent = 0;
! 1582: }
! 1583:
! 1584: p = ngx_pnalloc(r->pool, NGX_OFF_T_LEN);
! 1585: if (p == NULL) {
! 1586: return NGX_ERROR;
! 1587: }
! 1588:
! 1589: v->len = ngx_sprintf(p, "%O", sent) - p;
! 1590: v->valid = 1;
! 1591: v->no_cacheable = 0;
! 1592: v->not_found = 0;
! 1593: v->data = p;
! 1594:
! 1595: return NGX_OK;
! 1596: }
! 1597:
! 1598:
! 1599: static ngx_int_t
! 1600: ngx_http_variable_pipe(ngx_http_request_t *r,
! 1601: ngx_http_variable_value_t *v, uintptr_t data)
! 1602: {
! 1603: v->data = (u_char *) (r->pipeline ? "p" : ".");
! 1604: v->len = 1;
! 1605: v->valid = 1;
! 1606: v->no_cacheable = 0;
! 1607: v->not_found = 0;
! 1608:
! 1609: return NGX_OK;
! 1610: }
! 1611:
! 1612:
! 1613: static ngx_int_t
! 1614: ngx_http_variable_status(ngx_http_request_t *r,
! 1615: ngx_http_variable_value_t *v, uintptr_t data)
! 1616: {
! 1617: ngx_uint_t status;
! 1618:
! 1619: v->data = ngx_pnalloc(r->pool, NGX_INT_T_LEN);
! 1620: if (v->data == NULL) {
! 1621: return NGX_ERROR;
! 1622: }
! 1623:
! 1624: if (r->err_status) {
! 1625: status = r->err_status;
! 1626:
! 1627: } else if (r->headers_out.status) {
! 1628: status = r->headers_out.status;
! 1629:
! 1630: } else if (r->http_version == NGX_HTTP_VERSION_9) {
! 1631: status = 9;
! 1632:
! 1633: } else {
! 1634: status = 0;
! 1635: }
! 1636:
! 1637: v->len = ngx_sprintf(v->data, "%03ui", status) - v->data;
! 1638: v->valid = 1;
! 1639: v->no_cacheable = 0;
! 1640: v->not_found = 0;
! 1641:
! 1642: return NGX_OK;
! 1643: }
! 1644:
! 1645:
! 1646: static ngx_int_t
! 1647: ngx_http_variable_sent_content_type(ngx_http_request_t *r,
! 1648: ngx_http_variable_value_t *v, uintptr_t data)
! 1649: {
! 1650: if (r->headers_out.content_type.len) {
! 1651: v->len = r->headers_out.content_type.len;
! 1652: v->valid = 1;
! 1653: v->no_cacheable = 0;
! 1654: v->not_found = 0;
! 1655: v->data = r->headers_out.content_type.data;
! 1656:
! 1657: } else {
! 1658: v->not_found = 1;
! 1659: }
! 1660:
! 1661: return NGX_OK;
! 1662: }
! 1663:
! 1664:
! 1665: static ngx_int_t
! 1666: ngx_http_variable_sent_content_length(ngx_http_request_t *r,
! 1667: ngx_http_variable_value_t *v, uintptr_t data)
! 1668: {
! 1669: u_char *p;
! 1670:
! 1671: if (r->headers_out.content_length) {
! 1672: v->len = r->headers_out.content_length->value.len;
! 1673: v->valid = 1;
! 1674: v->no_cacheable = 0;
! 1675: v->not_found = 0;
! 1676: v->data = r->headers_out.content_length->value.data;
! 1677:
! 1678: return NGX_OK;
! 1679: }
! 1680:
! 1681: if (r->headers_out.content_length_n >= 0) {
! 1682: p = ngx_pnalloc(r->pool, NGX_OFF_T_LEN);
! 1683: if (p == NULL) {
! 1684: return NGX_ERROR;
! 1685: }
! 1686:
! 1687: v->len = ngx_sprintf(p, "%O", r->headers_out.content_length_n) - p;
! 1688: v->valid = 1;
! 1689: v->no_cacheable = 0;
! 1690: v->not_found = 0;
! 1691: v->data = p;
! 1692:
! 1693: return NGX_OK;
! 1694: }
! 1695:
! 1696: v->not_found = 1;
! 1697:
! 1698: return NGX_OK;
! 1699: }
! 1700:
! 1701:
! 1702: static ngx_int_t
! 1703: ngx_http_variable_sent_location(ngx_http_request_t *r,
! 1704: ngx_http_variable_value_t *v, uintptr_t data)
! 1705: {
! 1706: ngx_str_t name;
! 1707:
! 1708: if (r->headers_out.location) {
! 1709: v->len = r->headers_out.location->value.len;
! 1710: v->valid = 1;
! 1711: v->no_cacheable = 0;
! 1712: v->not_found = 0;
! 1713: v->data = r->headers_out.location->value.data;
! 1714:
! 1715: return NGX_OK;
! 1716: }
! 1717:
! 1718: ngx_str_set(&name, "sent_http_location");
! 1719:
! 1720: return ngx_http_variable_unknown_header(v, &name,
! 1721: &r->headers_out.headers.part,
! 1722: sizeof("sent_http_") - 1);
! 1723: }
! 1724:
! 1725:
! 1726: static ngx_int_t
! 1727: ngx_http_variable_sent_last_modified(ngx_http_request_t *r,
! 1728: ngx_http_variable_value_t *v, uintptr_t data)
! 1729: {
! 1730: u_char *p;
! 1731:
! 1732: if (r->headers_out.last_modified) {
! 1733: v->len = r->headers_out.last_modified->value.len;
! 1734: v->valid = 1;
! 1735: v->no_cacheable = 0;
! 1736: v->not_found = 0;
! 1737: v->data = r->headers_out.last_modified->value.data;
! 1738:
! 1739: return NGX_OK;
! 1740: }
! 1741:
! 1742: if (r->headers_out.last_modified_time >= 0) {
! 1743: p = ngx_pnalloc(r->pool,
! 1744: sizeof("Last-Modified: Mon, 28 Sep 1970 06:00:00 GMT") - 1);
! 1745: if (p == NULL) {
! 1746: return NGX_ERROR;
! 1747: }
! 1748:
! 1749: v->len = ngx_http_time(p, r->headers_out.last_modified_time) - p;
! 1750: v->valid = 1;
! 1751: v->no_cacheable = 0;
! 1752: v->not_found = 0;
! 1753: v->data = p;
! 1754:
! 1755: return NGX_OK;
! 1756: }
! 1757:
! 1758: v->not_found = 1;
! 1759:
! 1760: return NGX_OK;
! 1761: }
! 1762:
! 1763:
! 1764: static ngx_int_t
! 1765: ngx_http_variable_sent_connection(ngx_http_request_t *r,
! 1766: ngx_http_variable_value_t *v, uintptr_t data)
! 1767: {
! 1768: size_t len;
! 1769: char *p;
! 1770:
! 1771: if (r->headers_out.status == NGX_HTTP_SWITCHING_PROTOCOLS) {
! 1772: len = sizeof("upgrade") - 1;
! 1773: p = "upgrade";
! 1774:
! 1775: } else if (r->keepalive) {
! 1776: len = sizeof("keep-alive") - 1;
! 1777: p = "keep-alive";
! 1778:
! 1779: } else {
! 1780: len = sizeof("close") - 1;
! 1781: p = "close";
! 1782: }
! 1783:
! 1784: v->len = len;
! 1785: v->valid = 1;
! 1786: v->no_cacheable = 0;
! 1787: v->not_found = 0;
! 1788: v->data = (u_char *) p;
! 1789:
! 1790: return NGX_OK;
! 1791: }
! 1792:
! 1793:
! 1794: static ngx_int_t
! 1795: ngx_http_variable_sent_keep_alive(ngx_http_request_t *r,
! 1796: ngx_http_variable_value_t *v, uintptr_t data)
! 1797: {
! 1798: u_char *p;
! 1799: ngx_http_core_loc_conf_t *clcf;
! 1800:
! 1801: if (r->keepalive) {
! 1802: clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
! 1803:
! 1804: if (clcf->keepalive_header) {
! 1805:
! 1806: p = ngx_pnalloc(r->pool, sizeof("timeout=") - 1 + NGX_TIME_T_LEN);
! 1807: if (p == NULL) {
! 1808: return NGX_ERROR;
! 1809: }
! 1810:
! 1811: v->len = ngx_sprintf(p, "timeout=%T", clcf->keepalive_header) - p;
! 1812: v->valid = 1;
! 1813: v->no_cacheable = 0;
! 1814: v->not_found = 0;
! 1815: v->data = p;
! 1816:
! 1817: return NGX_OK;
! 1818: }
! 1819: }
! 1820:
! 1821: v->not_found = 1;
! 1822:
! 1823: return NGX_OK;
! 1824: }
! 1825:
! 1826:
! 1827: static ngx_int_t
! 1828: ngx_http_variable_sent_transfer_encoding(ngx_http_request_t *r,
! 1829: ngx_http_variable_value_t *v, uintptr_t data)
! 1830: {
! 1831: if (r->chunked) {
! 1832: v->len = sizeof("chunked") - 1;
! 1833: v->valid = 1;
! 1834: v->no_cacheable = 0;
! 1835: v->not_found = 0;
! 1836: v->data = (u_char *) "chunked";
! 1837:
! 1838: } else {
! 1839: v->not_found = 1;
! 1840: }
! 1841:
! 1842: return NGX_OK;
! 1843: }
! 1844:
! 1845:
! 1846: static ngx_int_t
! 1847: ngx_http_variable_request_completion(ngx_http_request_t *r,
! 1848: ngx_http_variable_value_t *v, uintptr_t data)
! 1849: {
! 1850: if (r->request_complete) {
! 1851: v->len = 2;
! 1852: v->valid = 1;
! 1853: v->no_cacheable = 0;
! 1854: v->not_found = 0;
! 1855: v->data = (u_char *) "OK";
! 1856:
! 1857: return NGX_OK;
! 1858: }
! 1859:
! 1860: v->len = 0;
! 1861: v->valid = 1;
! 1862: v->no_cacheable = 0;
! 1863: v->not_found = 0;
! 1864: v->data = (u_char *) "";
! 1865:
! 1866: return NGX_OK;
! 1867: }
! 1868:
! 1869:
! 1870: static ngx_int_t
! 1871: ngx_http_variable_request_body(ngx_http_request_t *r,
! 1872: ngx_http_variable_value_t *v, uintptr_t data)
! 1873: {
! 1874: u_char *p;
! 1875: size_t len;
! 1876: ngx_buf_t *buf;
! 1877: ngx_chain_t *cl;
! 1878:
! 1879: if (r->request_body == NULL
! 1880: || r->request_body->bufs == NULL
! 1881: || r->request_body->temp_file)
! 1882: {
! 1883: v->not_found = 1;
! 1884:
! 1885: return NGX_OK;
! 1886: }
! 1887:
! 1888: cl = r->request_body->bufs;
! 1889: buf = cl->buf;
! 1890:
! 1891: if (cl->next == NULL) {
! 1892: v->len = buf->last - buf->pos;
! 1893: v->valid = 1;
! 1894: v->no_cacheable = 0;
! 1895: v->not_found = 0;
! 1896: v->data = buf->pos;
! 1897:
! 1898: return NGX_OK;
! 1899: }
! 1900:
! 1901: len = buf->last - buf->pos;
! 1902: cl = cl->next;
! 1903:
! 1904: for ( /* void */ ; cl; cl = cl->next) {
! 1905: buf = cl->buf;
! 1906: len += buf->last - buf->pos;
! 1907: }
! 1908:
! 1909: p = ngx_pnalloc(r->pool, len);
! 1910: if (p == NULL) {
! 1911: return NGX_ERROR;
! 1912: }
! 1913:
! 1914: v->data = p;
! 1915: cl = r->request_body->bufs;
! 1916:
! 1917: for ( /* void */ ; cl; cl = cl->next) {
! 1918: buf = cl->buf;
! 1919: p = ngx_cpymem(p, buf->pos, buf->last - buf->pos);
! 1920: }
! 1921:
! 1922: v->len = len;
! 1923: v->valid = 1;
! 1924: v->no_cacheable = 0;
! 1925: v->not_found = 0;
! 1926:
! 1927: return NGX_OK;
! 1928: }
! 1929:
! 1930:
! 1931: static ngx_int_t
! 1932: ngx_http_variable_request_body_file(ngx_http_request_t *r,
! 1933: ngx_http_variable_value_t *v, uintptr_t data)
! 1934: {
! 1935: if (r->request_body == NULL || r->request_body->temp_file == NULL) {
! 1936: v->not_found = 1;
! 1937:
! 1938: return NGX_OK;
! 1939: }
! 1940:
! 1941: v->len = r->request_body->temp_file->file.name.len;
! 1942: v->valid = 1;
! 1943: v->no_cacheable = 0;
! 1944: v->not_found = 0;
! 1945: v->data = r->request_body->temp_file->file.name.data;
! 1946:
! 1947: return NGX_OK;
! 1948: }
! 1949:
! 1950:
! 1951: static ngx_int_t
! 1952: ngx_http_variable_request_length(ngx_http_request_t *r,
! 1953: ngx_http_variable_value_t *v, uintptr_t data)
! 1954: {
! 1955: u_char *p;
! 1956:
! 1957: p = ngx_pnalloc(r->pool, NGX_OFF_T_LEN);
! 1958: if (p == NULL) {
! 1959: return NGX_ERROR;
! 1960: }
! 1961:
! 1962: v->len = ngx_sprintf(p, "%O", r->request_length) - p;
! 1963: v->valid = 1;
! 1964: v->no_cacheable = 0;
! 1965: v->not_found = 0;
! 1966: v->data = p;
! 1967:
! 1968: return NGX_OK;
! 1969: }
! 1970:
! 1971:
! 1972: static ngx_int_t
! 1973: ngx_http_variable_request_time(ngx_http_request_t *r,
! 1974: ngx_http_variable_value_t *v, uintptr_t data)
! 1975: {
! 1976: u_char *p;
! 1977: ngx_time_t *tp;
! 1978: ngx_msec_int_t ms;
! 1979:
! 1980: p = ngx_pnalloc(r->pool, NGX_TIME_T_LEN + 4);
! 1981: if (p == NULL) {
! 1982: return NGX_ERROR;
! 1983: }
! 1984:
! 1985: tp = ngx_timeofday();
! 1986:
! 1987: ms = (ngx_msec_int_t)
! 1988: ((tp->sec - r->start_sec) * 1000 + (tp->msec - r->start_msec));
! 1989: ms = ngx_max(ms, 0);
! 1990:
! 1991: v->len = ngx_sprintf(p, "%T.%03M", (time_t) ms / 1000, ms % 1000) - p;
! 1992: v->valid = 1;
! 1993: v->no_cacheable = 0;
! 1994: v->not_found = 0;
! 1995: v->data = p;
! 1996:
! 1997: return NGX_OK;
! 1998: }
! 1999:
! 2000:
! 2001: static ngx_int_t
! 2002: ngx_http_variable_connection(ngx_http_request_t *r,
! 2003: ngx_http_variable_value_t *v, uintptr_t data)
! 2004: {
! 2005: u_char *p;
! 2006:
! 2007: p = ngx_pnalloc(r->pool, NGX_ATOMIC_T_LEN);
! 2008: if (p == NULL) {
! 2009: return NGX_ERROR;
! 2010: }
! 2011:
! 2012: v->len = ngx_sprintf(p, "%uA", r->connection->number) - p;
! 2013: v->valid = 1;
! 2014: v->no_cacheable = 0;
! 2015: v->not_found = 0;
! 2016: v->data = p;
! 2017:
! 2018: return NGX_OK;
! 2019: }
! 2020:
! 2021:
! 2022: static ngx_int_t
! 2023: ngx_http_variable_connection_requests(ngx_http_request_t *r,
! 2024: ngx_http_variable_value_t *v, uintptr_t data)
! 2025: {
! 2026: u_char *p;
! 2027:
! 2028: p = ngx_pnalloc(r->pool, NGX_INT_T_LEN);
! 2029: if (p == NULL) {
! 2030: return NGX_ERROR;
! 2031: }
! 2032:
! 2033: v->len = ngx_sprintf(p, "%ui", r->connection->requests) - p;
! 2034: v->valid = 1;
! 2035: v->no_cacheable = 0;
! 2036: v->not_found = 0;
! 2037: v->data = p;
! 2038:
! 2039: return NGX_OK;
! 2040: }
! 2041:
! 2042:
! 2043: static ngx_int_t
! 2044: ngx_http_variable_nginx_version(ngx_http_request_t *r,
! 2045: ngx_http_variable_value_t *v, uintptr_t data)
! 2046: {
! 2047: v->len = sizeof(NGINX_VERSION) - 1;
! 2048: v->valid = 1;
! 2049: v->no_cacheable = 0;
! 2050: v->not_found = 0;
! 2051: v->data = (u_char *) NGINX_VERSION;
! 2052:
! 2053: return NGX_OK;
! 2054: }
! 2055:
! 2056:
! 2057: static ngx_int_t
! 2058: ngx_http_variable_hostname(ngx_http_request_t *r,
! 2059: ngx_http_variable_value_t *v, uintptr_t data)
! 2060: {
! 2061: v->len = ngx_cycle->hostname.len;
! 2062: v->valid = 1;
! 2063: v->no_cacheable = 0;
! 2064: v->not_found = 0;
! 2065: v->data = ngx_cycle->hostname.data;
! 2066:
! 2067: return NGX_OK;
! 2068: }
! 2069:
! 2070:
! 2071: static ngx_int_t
! 2072: ngx_http_variable_pid(ngx_http_request_t *r,
! 2073: ngx_http_variable_value_t *v, uintptr_t data)
! 2074: {
! 2075: u_char *p;
! 2076:
! 2077: p = ngx_pnalloc(r->pool, NGX_INT64_LEN);
! 2078: if (p == NULL) {
! 2079: return NGX_ERROR;
! 2080: }
! 2081:
! 2082: v->len = ngx_sprintf(p, "%P", ngx_pid) - p;
! 2083: v->valid = 1;
! 2084: v->no_cacheable = 0;
! 2085: v->not_found = 0;
! 2086: v->data = p;
! 2087:
! 2088: return NGX_OK;
! 2089: }
! 2090:
! 2091:
! 2092: static ngx_int_t
! 2093: ngx_http_variable_msec(ngx_http_request_t *r,
! 2094: ngx_http_variable_value_t *v, uintptr_t data)
! 2095: {
! 2096: u_char *p;
! 2097: ngx_time_t *tp;
! 2098:
! 2099: p = ngx_pnalloc(r->pool, NGX_TIME_T_LEN + 4);
! 2100: if (p == NULL) {
! 2101: return NGX_ERROR;
! 2102: }
! 2103:
! 2104: tp = ngx_timeofday();
! 2105:
! 2106: v->len = ngx_sprintf(p, "%T.%03M", tp->sec, tp->msec) - p;
! 2107: v->valid = 1;
! 2108: v->no_cacheable = 0;
! 2109: v->not_found = 0;
! 2110: v->data = p;
! 2111:
! 2112: return NGX_OK;
! 2113: }
! 2114:
! 2115:
! 2116: static ngx_int_t
! 2117: ngx_http_variable_time_iso8601(ngx_http_request_t *r,
! 2118: ngx_http_variable_value_t *v, uintptr_t data)
! 2119: {
! 2120: u_char *p;
! 2121:
! 2122: p = ngx_pnalloc(r->pool, ngx_cached_http_log_iso8601.len);
! 2123: if (p == NULL) {
! 2124: return NGX_ERROR;
! 2125: }
! 2126:
! 2127: ngx_memcpy(p, ngx_cached_http_log_iso8601.data,
! 2128: ngx_cached_http_log_iso8601.len);
! 2129:
! 2130: v->len = ngx_cached_http_log_iso8601.len;
! 2131: v->valid = 1;
! 2132: v->no_cacheable = 0;
! 2133: v->not_found = 0;
! 2134: v->data = p;
! 2135:
! 2136: return NGX_OK;
! 2137: }
! 2138:
! 2139:
! 2140: static ngx_int_t
! 2141: ngx_http_variable_time_local(ngx_http_request_t *r,
! 2142: ngx_http_variable_value_t *v, uintptr_t data)
! 2143: {
! 2144: u_char *p;
! 2145:
! 2146: p = ngx_pnalloc(r->pool, ngx_cached_http_log_time.len);
! 2147: if (p == NULL) {
! 2148: return NGX_ERROR;
! 2149: }
! 2150:
! 2151: ngx_memcpy(p, ngx_cached_http_log_time.data, ngx_cached_http_log_time.len);
! 2152:
! 2153: v->len = ngx_cached_http_log_time.len;
! 2154: v->valid = 1;
! 2155: v->no_cacheable = 0;
! 2156: v->not_found = 0;
! 2157: v->data = p;
! 2158:
! 2159: return NGX_OK;
! 2160: }
! 2161:
! 2162:
! 2163: void *
! 2164: ngx_http_map_find(ngx_http_request_t *r, ngx_http_map_t *map, ngx_str_t *match)
! 2165: {
! 2166: void *value;
! 2167: u_char *low;
! 2168: size_t len;
! 2169: ngx_uint_t key;
! 2170:
! 2171: len = match->len;
! 2172:
! 2173: if (len) {
! 2174: low = ngx_pnalloc(r->pool, len);
! 2175: if (low == NULL) {
! 2176: return NULL;
! 2177: }
! 2178:
! 2179: } else {
! 2180: low = NULL;
! 2181: }
! 2182:
! 2183: key = ngx_hash_strlow(low, match->data, len);
! 2184:
! 2185: value = ngx_hash_find_combined(&map->hash, key, low, len);
! 2186: if (value) {
! 2187: return value;
! 2188: }
! 2189:
! 2190: #if (NGX_PCRE)
! 2191:
! 2192: if (len && map->nregex) {
! 2193: ngx_int_t n;
! 2194: ngx_uint_t i;
! 2195: ngx_http_map_regex_t *reg;
! 2196:
! 2197: reg = map->regex;
! 2198:
! 2199: for (i = 0; i < map->nregex; i++) {
! 2200:
! 2201: n = ngx_http_regex_exec(r, reg[i].regex, match);
! 2202:
! 2203: if (n == NGX_OK) {
! 2204: return reg[i].value;
! 2205: }
! 2206:
! 2207: if (n == NGX_DECLINED) {
! 2208: continue;
! 2209: }
! 2210:
! 2211: /* NGX_ERROR */
! 2212:
! 2213: return NULL;
! 2214: }
! 2215: }
! 2216:
! 2217: #endif
! 2218:
! 2219: return NULL;
! 2220: }
! 2221:
! 2222:
! 2223: #if (NGX_PCRE)
! 2224:
! 2225: static ngx_int_t
! 2226: ngx_http_variable_not_found(ngx_http_request_t *r, ngx_http_variable_value_t *v,
! 2227: uintptr_t data)
! 2228: {
! 2229: v->not_found = 1;
! 2230: return NGX_OK;
! 2231: }
! 2232:
! 2233:
! 2234: ngx_http_regex_t *
! 2235: ngx_http_regex_compile(ngx_conf_t *cf, ngx_regex_compile_t *rc)
! 2236: {
! 2237: u_char *p;
! 2238: size_t size;
! 2239: ngx_str_t name;
! 2240: ngx_uint_t i, n;
! 2241: ngx_http_variable_t *v;
! 2242: ngx_http_regex_t *re;
! 2243: ngx_http_regex_variable_t *rv;
! 2244: ngx_http_core_main_conf_t *cmcf;
! 2245:
! 2246: rc->pool = cf->pool;
! 2247:
! 2248: if (ngx_regex_compile(rc) != NGX_OK) {
! 2249: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc->err);
! 2250: return NULL;
! 2251: }
! 2252:
! 2253: re = ngx_pcalloc(cf->pool, sizeof(ngx_http_regex_t));
! 2254: if (re == NULL) {
! 2255: return NULL;
! 2256: }
! 2257:
! 2258: re->regex = rc->regex;
! 2259: re->ncaptures = rc->captures;
! 2260:
! 2261: cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
! 2262: cmcf->ncaptures = ngx_max(cmcf->ncaptures, re->ncaptures);
! 2263:
! 2264: n = (ngx_uint_t) rc->named_captures;
! 2265:
! 2266: if (n == 0) {
! 2267: return re;
! 2268: }
! 2269:
! 2270: rv = ngx_palloc(rc->pool, n * sizeof(ngx_http_regex_variable_t));
! 2271: if (rv == NULL) {
! 2272: return NULL;
! 2273: }
! 2274:
! 2275: re->variables = rv;
! 2276: re->nvariables = n;
! 2277: re->name = rc->pattern;
! 2278:
! 2279: size = rc->name_size;
! 2280: p = rc->names;
! 2281:
! 2282: for (i = 0; i < n; i++) {
! 2283: rv[i].capture = 2 * ((p[0] << 8) + p[1]);
! 2284:
! 2285: name.data = &p[2];
! 2286: name.len = ngx_strlen(name.data);
! 2287:
! 2288: v = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGEABLE);
! 2289: if (v == NULL) {
! 2290: return NULL;
! 2291: }
! 2292:
! 2293: rv[i].index = ngx_http_get_variable_index(cf, &name);
! 2294: if (rv[i].index == NGX_ERROR) {
! 2295: return NULL;
! 2296: }
! 2297:
! 2298: v->get_handler = ngx_http_variable_not_found;
! 2299:
! 2300: p += size;
! 2301: }
! 2302:
! 2303: return re;
! 2304: }
! 2305:
! 2306:
! 2307: ngx_int_t
! 2308: ngx_http_regex_exec(ngx_http_request_t *r, ngx_http_regex_t *re, ngx_str_t *s)
! 2309: {
! 2310: ngx_int_t rc, index;
! 2311: ngx_uint_t i, n, len;
! 2312: ngx_http_variable_value_t *vv;
! 2313: ngx_http_core_main_conf_t *cmcf;
! 2314:
! 2315: cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
! 2316:
! 2317: if (re->ncaptures) {
! 2318: len = cmcf->ncaptures;
! 2319:
! 2320: if (r->captures == NULL) {
! 2321: r->captures = ngx_palloc(r->pool, len * sizeof(int));
! 2322: if (r->captures == NULL) {
! 2323: return NGX_ERROR;
! 2324: }
! 2325: }
! 2326:
! 2327: } else {
! 2328: len = 0;
! 2329: }
! 2330:
! 2331: rc = ngx_regex_exec(re->regex, s, r->captures, len);
! 2332:
! 2333: if (rc == NGX_REGEX_NO_MATCHED) {
! 2334: return NGX_DECLINED;
! 2335: }
! 2336:
! 2337: if (rc < 0) {
! 2338: ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
! 2339: ngx_regex_exec_n " failed: %i on \"%V\" using \"%V\"",
! 2340: rc, s, &re->name);
! 2341: return NGX_ERROR;
! 2342: }
! 2343:
! 2344: for (i = 0; i < re->nvariables; i++) {
! 2345:
! 2346: n = re->variables[i].capture;
! 2347: index = re->variables[i].index;
! 2348: vv = &r->variables[index];
! 2349:
! 2350: vv->len = r->captures[n + 1] - r->captures[n];
! 2351: vv->valid = 1;
! 2352: vv->no_cacheable = 0;
! 2353: vv->not_found = 0;
! 2354: vv->data = &s->data[r->captures[n]];
! 2355:
! 2356: #if (NGX_DEBUG)
! 2357: {
! 2358: ngx_http_variable_t *v;
! 2359:
! 2360: v = cmcf->variables.elts;
! 2361:
! 2362: ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
! 2363: "http regex set $%V to \"%*s\"",
! 2364: &v[index].name, vv->len, vv->data);
! 2365: }
! 2366: #endif
! 2367: }
! 2368:
! 2369: r->ncaptures = rc * 2;
! 2370: r->captures_data = s->data;
! 2371:
! 2372: return NGX_OK;
! 2373: }
! 2374:
! 2375: #endif
! 2376:
! 2377:
! 2378: ngx_int_t
! 2379: ngx_http_variables_add_core_vars(ngx_conf_t *cf)
! 2380: {
! 2381: ngx_int_t rc;
! 2382: ngx_http_variable_t *cv, *v;
! 2383: ngx_http_core_main_conf_t *cmcf;
! 2384:
! 2385: cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
! 2386:
! 2387: cmcf->variables_keys = ngx_pcalloc(cf->temp_pool,
! 2388: sizeof(ngx_hash_keys_arrays_t));
! 2389: if (cmcf->variables_keys == NULL) {
! 2390: return NGX_ERROR;
! 2391: }
! 2392:
! 2393: cmcf->variables_keys->pool = cf->pool;
! 2394: cmcf->variables_keys->temp_pool = cf->pool;
! 2395:
! 2396: if (ngx_hash_keys_array_init(cmcf->variables_keys, NGX_HASH_SMALL)
! 2397: != NGX_OK)
! 2398: {
! 2399: return NGX_ERROR;
! 2400: }
! 2401:
! 2402: for (cv = ngx_http_core_variables; cv->name.len; cv++) {
! 2403: v = ngx_palloc(cf->pool, sizeof(ngx_http_variable_t));
! 2404: if (v == NULL) {
! 2405: return NGX_ERROR;
! 2406: }
! 2407:
! 2408: *v = *cv;
! 2409:
! 2410: rc = ngx_hash_add_key(cmcf->variables_keys, &v->name, v,
! 2411: NGX_HASH_READONLY_KEY);
! 2412:
! 2413: if (rc == NGX_OK) {
! 2414: continue;
! 2415: }
! 2416:
! 2417: if (rc == NGX_BUSY) {
! 2418: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 2419: "conflicting variable name \"%V\"", &v->name);
! 2420: }
! 2421:
! 2422: return NGX_ERROR;
! 2423: }
! 2424:
! 2425: return NGX_OK;
! 2426: }
! 2427:
! 2428:
! 2429: ngx_int_t
! 2430: ngx_http_variables_init_vars(ngx_conf_t *cf)
! 2431: {
! 2432: ngx_uint_t i, n;
! 2433: ngx_hash_key_t *key;
! 2434: ngx_hash_init_t hash;
! 2435: ngx_http_variable_t *v, *av;
! 2436: ngx_http_core_main_conf_t *cmcf;
! 2437:
! 2438: /* set the handlers for the indexed http variables */
! 2439:
! 2440: cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
! 2441:
! 2442: v = cmcf->variables.elts;
! 2443: key = cmcf->variables_keys->keys.elts;
! 2444:
! 2445: for (i = 0; i < cmcf->variables.nelts; i++) {
! 2446:
! 2447: for (n = 0; n < cmcf->variables_keys->keys.nelts; n++) {
! 2448:
! 2449: av = key[n].value;
! 2450:
! 2451: if (av->get_handler
! 2452: && v[i].name.len == key[n].key.len
! 2453: && ngx_strncmp(v[i].name.data, key[n].key.data, v[i].name.len)
! 2454: == 0)
! 2455: {
! 2456: v[i].get_handler = av->get_handler;
! 2457: v[i].data = av->data;
! 2458:
! 2459: av->flags |= NGX_HTTP_VAR_INDEXED;
! 2460: v[i].flags = av->flags;
! 2461:
! 2462: av->index = i;
! 2463:
! 2464: goto next;
! 2465: }
! 2466: }
! 2467:
! 2468: if (ngx_strncmp(v[i].name.data, "http_", 5) == 0) {
! 2469: v[i].get_handler = ngx_http_variable_unknown_header_in;
! 2470: v[i].data = (uintptr_t) &v[i].name;
! 2471:
! 2472: continue;
! 2473: }
! 2474:
! 2475: if (ngx_strncmp(v[i].name.data, "sent_http_", 10) == 0) {
! 2476: v[i].get_handler = ngx_http_variable_unknown_header_out;
! 2477: v[i].data = (uintptr_t) &v[i].name;
! 2478:
! 2479: continue;
! 2480: }
! 2481:
! 2482: if (ngx_strncmp(v[i].name.data, "upstream_http_", 14) == 0) {
! 2483: v[i].get_handler = ngx_http_upstream_header_variable;
! 2484: v[i].data = (uintptr_t) &v[i].name;
! 2485: v[i].flags = NGX_HTTP_VAR_NOCACHEABLE;
! 2486:
! 2487: continue;
! 2488: }
! 2489:
! 2490: if (ngx_strncmp(v[i].name.data, "cookie_", 7) == 0) {
! 2491: v[i].get_handler = ngx_http_variable_cookie;
! 2492: v[i].data = (uintptr_t) &v[i].name;
! 2493:
! 2494: continue;
! 2495: }
! 2496:
! 2497: if (ngx_strncmp(v[i].name.data, "arg_", 4) == 0) {
! 2498: v[i].get_handler = ngx_http_variable_argument;
! 2499: v[i].data = (uintptr_t) &v[i].name;
! 2500: v[i].flags = NGX_HTTP_VAR_NOCACHEABLE;
! 2501:
! 2502: continue;
! 2503: }
! 2504:
! 2505: ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
! 2506: "unknown \"%V\" variable", &v[i].name);
! 2507:
! 2508: return NGX_ERROR;
! 2509:
! 2510: next:
! 2511: continue;
! 2512: }
! 2513:
! 2514:
! 2515: for (n = 0; n < cmcf->variables_keys->keys.nelts; n++) {
! 2516: av = key[n].value;
! 2517:
! 2518: if (av->flags & NGX_HTTP_VAR_NOHASH) {
! 2519: key[n].key.data = NULL;
! 2520: }
! 2521: }
! 2522:
! 2523:
! 2524: hash.hash = &cmcf->variables_hash;
! 2525: hash.key = ngx_hash_key;
! 2526: hash.max_size = cmcf->variables_hash_max_size;
! 2527: hash.bucket_size = cmcf->variables_hash_bucket_size;
! 2528: hash.name = "variables_hash";
! 2529: hash.pool = cf->pool;
! 2530: hash.temp_pool = NULL;
! 2531:
! 2532: if (ngx_hash_init(&hash, cmcf->variables_keys->keys.elts,
! 2533: cmcf->variables_keys->keys.nelts)
! 2534: != NGX_OK)
! 2535: {
! 2536: return NGX_ERROR;
! 2537: }
! 2538:
! 2539: cmcf->variables_keys = NULL;
! 2540:
! 2541: return NGX_OK;
! 2542: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>