Return to ngx_http_variables.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / nginx / src / http |
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: }