Annotation of embedaddon/nginx/src/http/modules/ngx_http_proxy_module.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:
! 12:
! 13: typedef struct ngx_http_proxy_rewrite_s ngx_http_proxy_rewrite_t;
! 14:
! 15: typedef ngx_int_t (*ngx_http_proxy_rewrite_pt)(ngx_http_request_t *r,
! 16: ngx_table_elt_t *h, size_t prefix, size_t len,
! 17: ngx_http_proxy_rewrite_t *pr);
! 18:
! 19: struct ngx_http_proxy_rewrite_s {
! 20: ngx_http_proxy_rewrite_pt handler;
! 21:
! 22: union {
! 23: ngx_http_complex_value_t complex;
! 24: #if (NGX_PCRE)
! 25: ngx_http_regex_t *regex;
! 26: #endif
! 27: } pattern;
! 28:
! 29: ngx_http_complex_value_t replacement;
! 30: };
! 31:
! 32:
! 33: typedef struct {
! 34: ngx_str_t key_start;
! 35: ngx_str_t schema;
! 36: ngx_str_t host_header;
! 37: ngx_str_t port;
! 38: ngx_str_t uri;
! 39: } ngx_http_proxy_vars_t;
! 40:
! 41:
! 42: typedef struct {
! 43: ngx_http_upstream_conf_t upstream;
! 44:
! 45: ngx_array_t *flushes;
! 46: ngx_array_t *body_set_len;
! 47: ngx_array_t *body_set;
! 48: ngx_array_t *headers_set_len;
! 49: ngx_array_t *headers_set;
! 50: ngx_hash_t headers_set_hash;
! 51:
! 52: ngx_array_t *headers_source;
! 53:
! 54: ngx_array_t *proxy_lengths;
! 55: ngx_array_t *proxy_values;
! 56:
! 57: ngx_array_t *redirects;
! 58: ngx_array_t *cookie_domains;
! 59: ngx_array_t *cookie_paths;
! 60:
! 61: ngx_str_t body_source;
! 62:
! 63: ngx_str_t method;
! 64: ngx_str_t location;
! 65: ngx_str_t url;
! 66:
! 67: #if (NGX_HTTP_CACHE)
! 68: ngx_http_complex_value_t cache_key;
! 69: #endif
! 70:
! 71: ngx_http_proxy_vars_t vars;
! 72:
! 73: ngx_flag_t redirect;
! 74:
! 75: ngx_uint_t http_version;
! 76:
! 77: ngx_uint_t headers_hash_max_size;
! 78: ngx_uint_t headers_hash_bucket_size;
! 79: } ngx_http_proxy_loc_conf_t;
! 80:
! 81:
! 82: typedef struct {
! 83: ngx_http_status_t status;
! 84: ngx_http_chunked_t chunked;
! 85: ngx_http_proxy_vars_t vars;
! 86: off_t internal_body_length;
! 87:
! 88: ngx_uint_t head; /* unsigned head:1 */
! 89: } ngx_http_proxy_ctx_t;
! 90:
! 91:
! 92: static ngx_int_t ngx_http_proxy_eval(ngx_http_request_t *r,
! 93: ngx_http_proxy_ctx_t *ctx, ngx_http_proxy_loc_conf_t *plcf);
! 94: #if (NGX_HTTP_CACHE)
! 95: static ngx_int_t ngx_http_proxy_create_key(ngx_http_request_t *r);
! 96: #endif
! 97: static ngx_int_t ngx_http_proxy_create_request(ngx_http_request_t *r);
! 98: static ngx_int_t ngx_http_proxy_reinit_request(ngx_http_request_t *r);
! 99: static ngx_int_t ngx_http_proxy_process_status_line(ngx_http_request_t *r);
! 100: static ngx_int_t ngx_http_proxy_process_header(ngx_http_request_t *r);
! 101: static ngx_int_t ngx_http_proxy_input_filter_init(void *data);
! 102: static ngx_int_t ngx_http_proxy_copy_filter(ngx_event_pipe_t *p,
! 103: ngx_buf_t *buf);
! 104: static ngx_int_t ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p,
! 105: ngx_buf_t *buf);
! 106: static ngx_int_t ngx_http_proxy_non_buffered_copy_filter(void *data,
! 107: ssize_t bytes);
! 108: static ngx_int_t ngx_http_proxy_non_buffered_chunked_filter(void *data,
! 109: ssize_t bytes);
! 110: static void ngx_http_proxy_abort_request(ngx_http_request_t *r);
! 111: static void ngx_http_proxy_finalize_request(ngx_http_request_t *r,
! 112: ngx_int_t rc);
! 113:
! 114: static ngx_int_t ngx_http_proxy_host_variable(ngx_http_request_t *r,
! 115: ngx_http_variable_value_t *v, uintptr_t data);
! 116: static ngx_int_t ngx_http_proxy_port_variable(ngx_http_request_t *r,
! 117: ngx_http_variable_value_t *v, uintptr_t data);
! 118: static ngx_int_t
! 119: ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r,
! 120: ngx_http_variable_value_t *v, uintptr_t data);
! 121: static ngx_int_t
! 122: ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r,
! 123: ngx_http_variable_value_t *v, uintptr_t data);
! 124: static ngx_int_t ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r,
! 125: ngx_table_elt_t *h, size_t prefix);
! 126: static ngx_int_t ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r,
! 127: ngx_table_elt_t *h);
! 128: static ngx_int_t ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r,
! 129: ngx_table_elt_t *h, u_char *value, ngx_array_t *rewrites);
! 130: static ngx_int_t ngx_http_proxy_rewrite(ngx_http_request_t *r,
! 131: ngx_table_elt_t *h, size_t prefix, size_t len, ngx_str_t *replacement);
! 132:
! 133: static ngx_int_t ngx_http_proxy_add_variables(ngx_conf_t *cf);
! 134: static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf);
! 135: static char *ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf,
! 136: void *parent, void *child);
! 137: static ngx_int_t ngx_http_proxy_merge_headers(ngx_conf_t *cf,
! 138: ngx_http_proxy_loc_conf_t *conf, ngx_http_proxy_loc_conf_t *prev);
! 139:
! 140: static char *ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd,
! 141: void *conf);
! 142: static char *ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd,
! 143: void *conf);
! 144: static char *ngx_http_proxy_cookie_domain(ngx_conf_t *cf, ngx_command_t *cmd,
! 145: void *conf);
! 146: static char *ngx_http_proxy_cookie_path(ngx_conf_t *cf, ngx_command_t *cmd,
! 147: void *conf);
! 148: static char *ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd,
! 149: void *conf);
! 150: #if (NGX_HTTP_CACHE)
! 151: static char *ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd,
! 152: void *conf);
! 153: static char *ngx_http_proxy_cache_key(ngx_conf_t *cf, ngx_command_t *cmd,
! 154: void *conf);
! 155: #endif
! 156:
! 157: static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data);
! 158:
! 159: static ngx_int_t ngx_http_proxy_rewrite_regex(ngx_conf_t *cf,
! 160: ngx_http_proxy_rewrite_t *pr, ngx_str_t *regex, ngx_uint_t caseless);
! 161:
! 162: #if (NGX_HTTP_SSL)
! 163: static ngx_int_t ngx_http_proxy_set_ssl(ngx_conf_t *cf,
! 164: ngx_http_proxy_loc_conf_t *plcf);
! 165: #endif
! 166: static void ngx_http_proxy_set_vars(ngx_url_t *u, ngx_http_proxy_vars_t *v);
! 167:
! 168:
! 169: static ngx_conf_post_t ngx_http_proxy_lowat_post =
! 170: { ngx_http_proxy_lowat_check };
! 171:
! 172:
! 173: static ngx_conf_bitmask_t ngx_http_proxy_next_upstream_masks[] = {
! 174: { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR },
! 175: { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT },
! 176: { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER },
! 177: { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 },
! 178: { ngx_string("http_502"), NGX_HTTP_UPSTREAM_FT_HTTP_502 },
! 179: { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 },
! 180: { ngx_string("http_504"), NGX_HTTP_UPSTREAM_FT_HTTP_504 },
! 181: { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 },
! 182: { ngx_string("updating"), NGX_HTTP_UPSTREAM_FT_UPDATING },
! 183: { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF },
! 184: { ngx_null_string, 0 }
! 185: };
! 186:
! 187:
! 188: static ngx_conf_enum_t ngx_http_proxy_http_version[] = {
! 189: { ngx_string("1.0"), NGX_HTTP_VERSION_10 },
! 190: { ngx_string("1.1"), NGX_HTTP_VERSION_11 },
! 191: { ngx_null_string, 0 }
! 192: };
! 193:
! 194:
! 195: ngx_module_t ngx_http_proxy_module;
! 196:
! 197:
! 198: static ngx_command_t ngx_http_proxy_commands[] = {
! 199:
! 200: { ngx_string("proxy_pass"),
! 201: NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_HTTP_LMT_CONF|NGX_CONF_TAKE1,
! 202: ngx_http_proxy_pass,
! 203: NGX_HTTP_LOC_CONF_OFFSET,
! 204: 0,
! 205: NULL },
! 206:
! 207: { ngx_string("proxy_redirect"),
! 208: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
! 209: ngx_http_proxy_redirect,
! 210: NGX_HTTP_LOC_CONF_OFFSET,
! 211: 0,
! 212: NULL },
! 213:
! 214: { ngx_string("proxy_cookie_domain"),
! 215: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
! 216: ngx_http_proxy_cookie_domain,
! 217: NGX_HTTP_LOC_CONF_OFFSET,
! 218: 0,
! 219: NULL },
! 220:
! 221: { ngx_string("proxy_cookie_path"),
! 222: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
! 223: ngx_http_proxy_cookie_path,
! 224: NGX_HTTP_LOC_CONF_OFFSET,
! 225: 0,
! 226: NULL },
! 227:
! 228: { ngx_string("proxy_store"),
! 229: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
! 230: ngx_http_proxy_store,
! 231: NGX_HTTP_LOC_CONF_OFFSET,
! 232: 0,
! 233: NULL },
! 234:
! 235: { ngx_string("proxy_store_access"),
! 236: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,
! 237: ngx_conf_set_access_slot,
! 238: NGX_HTTP_LOC_CONF_OFFSET,
! 239: offsetof(ngx_http_proxy_loc_conf_t, upstream.store_access),
! 240: NULL },
! 241:
! 242: { ngx_string("proxy_buffering"),
! 243: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
! 244: ngx_conf_set_flag_slot,
! 245: NGX_HTTP_LOC_CONF_OFFSET,
! 246: offsetof(ngx_http_proxy_loc_conf_t, upstream.buffering),
! 247: NULL },
! 248:
! 249: { ngx_string("proxy_ignore_client_abort"),
! 250: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
! 251: ngx_conf_set_flag_slot,
! 252: NGX_HTTP_LOC_CONF_OFFSET,
! 253: offsetof(ngx_http_proxy_loc_conf_t, upstream.ignore_client_abort),
! 254: NULL },
! 255:
! 256: { ngx_string("proxy_bind"),
! 257: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
! 258: ngx_http_upstream_bind_set_slot,
! 259: NGX_HTTP_LOC_CONF_OFFSET,
! 260: offsetof(ngx_http_proxy_loc_conf_t, upstream.local),
! 261: NULL },
! 262:
! 263: { ngx_string("proxy_connect_timeout"),
! 264: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
! 265: ngx_conf_set_msec_slot,
! 266: NGX_HTTP_LOC_CONF_OFFSET,
! 267: offsetof(ngx_http_proxy_loc_conf_t, upstream.connect_timeout),
! 268: NULL },
! 269:
! 270: { ngx_string("proxy_send_timeout"),
! 271: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
! 272: ngx_conf_set_msec_slot,
! 273: NGX_HTTP_LOC_CONF_OFFSET,
! 274: offsetof(ngx_http_proxy_loc_conf_t, upstream.send_timeout),
! 275: NULL },
! 276:
! 277: { ngx_string("proxy_send_lowat"),
! 278: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
! 279: ngx_conf_set_size_slot,
! 280: NGX_HTTP_LOC_CONF_OFFSET,
! 281: offsetof(ngx_http_proxy_loc_conf_t, upstream.send_lowat),
! 282: &ngx_http_proxy_lowat_post },
! 283:
! 284: { ngx_string("proxy_intercept_errors"),
! 285: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
! 286: ngx_conf_set_flag_slot,
! 287: NGX_HTTP_LOC_CONF_OFFSET,
! 288: offsetof(ngx_http_proxy_loc_conf_t, upstream.intercept_errors),
! 289: NULL },
! 290:
! 291: { ngx_string("proxy_set_header"),
! 292: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
! 293: ngx_conf_set_keyval_slot,
! 294: NGX_HTTP_LOC_CONF_OFFSET,
! 295: offsetof(ngx_http_proxy_loc_conf_t, headers_source),
! 296: NULL },
! 297:
! 298: { ngx_string("proxy_headers_hash_max_size"),
! 299: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
! 300: ngx_conf_set_num_slot,
! 301: NGX_HTTP_LOC_CONF_OFFSET,
! 302: offsetof(ngx_http_proxy_loc_conf_t, headers_hash_max_size),
! 303: NULL },
! 304:
! 305: { ngx_string("proxy_headers_hash_bucket_size"),
! 306: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
! 307: ngx_conf_set_num_slot,
! 308: NGX_HTTP_LOC_CONF_OFFSET,
! 309: offsetof(ngx_http_proxy_loc_conf_t, headers_hash_bucket_size),
! 310: NULL },
! 311:
! 312: { ngx_string("proxy_set_body"),
! 313: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
! 314: ngx_conf_set_str_slot,
! 315: NGX_HTTP_LOC_CONF_OFFSET,
! 316: offsetof(ngx_http_proxy_loc_conf_t, body_source),
! 317: NULL },
! 318:
! 319: { ngx_string("proxy_method"),
! 320: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
! 321: ngx_conf_set_str_slot,
! 322: NGX_HTTP_LOC_CONF_OFFSET,
! 323: offsetof(ngx_http_proxy_loc_conf_t, method),
! 324: NULL },
! 325:
! 326: { ngx_string("proxy_pass_request_headers"),
! 327: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
! 328: ngx_conf_set_flag_slot,
! 329: NGX_HTTP_LOC_CONF_OFFSET,
! 330: offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_headers),
! 331: NULL },
! 332:
! 333: { ngx_string("proxy_pass_request_body"),
! 334: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
! 335: ngx_conf_set_flag_slot,
! 336: NGX_HTTP_LOC_CONF_OFFSET,
! 337: offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_body),
! 338: NULL },
! 339:
! 340: { ngx_string("proxy_buffer_size"),
! 341: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
! 342: ngx_conf_set_size_slot,
! 343: NGX_HTTP_LOC_CONF_OFFSET,
! 344: offsetof(ngx_http_proxy_loc_conf_t, upstream.buffer_size),
! 345: NULL },
! 346:
! 347: { ngx_string("proxy_read_timeout"),
! 348: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
! 349: ngx_conf_set_msec_slot,
! 350: NGX_HTTP_LOC_CONF_OFFSET,
! 351: offsetof(ngx_http_proxy_loc_conf_t, upstream.read_timeout),
! 352: NULL },
! 353:
! 354: { ngx_string("proxy_buffers"),
! 355: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
! 356: ngx_conf_set_bufs_slot,
! 357: NGX_HTTP_LOC_CONF_OFFSET,
! 358: offsetof(ngx_http_proxy_loc_conf_t, upstream.bufs),
! 359: NULL },
! 360:
! 361: { ngx_string("proxy_busy_buffers_size"),
! 362: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
! 363: ngx_conf_set_size_slot,
! 364: NGX_HTTP_LOC_CONF_OFFSET,
! 365: offsetof(ngx_http_proxy_loc_conf_t, upstream.busy_buffers_size_conf),
! 366: NULL },
! 367:
! 368: #if (NGX_HTTP_CACHE)
! 369:
! 370: { ngx_string("proxy_cache"),
! 371: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
! 372: ngx_http_proxy_cache,
! 373: NGX_HTTP_LOC_CONF_OFFSET,
! 374: 0,
! 375: NULL },
! 376:
! 377: { ngx_string("proxy_cache_key"),
! 378: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
! 379: ngx_http_proxy_cache_key,
! 380: NGX_HTTP_LOC_CONF_OFFSET,
! 381: 0,
! 382: NULL },
! 383:
! 384: { ngx_string("proxy_cache_path"),
! 385: NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE,
! 386: ngx_http_file_cache_set_slot,
! 387: 0,
! 388: 0,
! 389: &ngx_http_proxy_module },
! 390:
! 391: { ngx_string("proxy_cache_bypass"),
! 392: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
! 393: ngx_http_set_predicate_slot,
! 394: NGX_HTTP_LOC_CONF_OFFSET,
! 395: offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_bypass),
! 396: NULL },
! 397:
! 398: { ngx_string("proxy_no_cache"),
! 399: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
! 400: ngx_http_set_predicate_slot,
! 401: NGX_HTTP_LOC_CONF_OFFSET,
! 402: offsetof(ngx_http_proxy_loc_conf_t, upstream.no_cache),
! 403: NULL },
! 404:
! 405: { ngx_string("proxy_cache_valid"),
! 406: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
! 407: ngx_http_file_cache_valid_set_slot,
! 408: NGX_HTTP_LOC_CONF_OFFSET,
! 409: offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_valid),
! 410: NULL },
! 411:
! 412: { ngx_string("proxy_cache_min_uses"),
! 413: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
! 414: ngx_conf_set_num_slot,
! 415: NGX_HTTP_LOC_CONF_OFFSET,
! 416: offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_min_uses),
! 417: NULL },
! 418:
! 419: { ngx_string("proxy_cache_use_stale"),
! 420: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
! 421: ngx_conf_set_bitmask_slot,
! 422: NGX_HTTP_LOC_CONF_OFFSET,
! 423: offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_use_stale),
! 424: &ngx_http_proxy_next_upstream_masks },
! 425:
! 426: { ngx_string("proxy_cache_methods"),
! 427: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
! 428: ngx_conf_set_bitmask_slot,
! 429: NGX_HTTP_LOC_CONF_OFFSET,
! 430: offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_methods),
! 431: &ngx_http_upstream_cache_method_mask },
! 432:
! 433: { ngx_string("proxy_cache_lock"),
! 434: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
! 435: ngx_conf_set_flag_slot,
! 436: NGX_HTTP_LOC_CONF_OFFSET,
! 437: offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_lock),
! 438: NULL },
! 439:
! 440: { ngx_string("proxy_cache_lock_timeout"),
! 441: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
! 442: ngx_conf_set_msec_slot,
! 443: NGX_HTTP_LOC_CONF_OFFSET,
! 444: offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_lock_timeout),
! 445: NULL },
! 446:
! 447: #endif
! 448:
! 449: { ngx_string("proxy_temp_path"),
! 450: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
! 451: ngx_conf_set_path_slot,
! 452: NGX_HTTP_LOC_CONF_OFFSET,
! 453: offsetof(ngx_http_proxy_loc_conf_t, upstream.temp_path),
! 454: NULL },
! 455:
! 456: { ngx_string("proxy_max_temp_file_size"),
! 457: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
! 458: ngx_conf_set_size_slot,
! 459: NGX_HTTP_LOC_CONF_OFFSET,
! 460: offsetof(ngx_http_proxy_loc_conf_t, upstream.max_temp_file_size_conf),
! 461: NULL },
! 462:
! 463: { ngx_string("proxy_temp_file_write_size"),
! 464: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
! 465: ngx_conf_set_size_slot,
! 466: NGX_HTTP_LOC_CONF_OFFSET,
! 467: offsetof(ngx_http_proxy_loc_conf_t, upstream.temp_file_write_size_conf),
! 468: NULL },
! 469:
! 470: { ngx_string("proxy_next_upstream"),
! 471: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
! 472: ngx_conf_set_bitmask_slot,
! 473: NGX_HTTP_LOC_CONF_OFFSET,
! 474: offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream),
! 475: &ngx_http_proxy_next_upstream_masks },
! 476:
! 477: { ngx_string("proxy_pass_header"),
! 478: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
! 479: ngx_conf_set_str_array_slot,
! 480: NGX_HTTP_LOC_CONF_OFFSET,
! 481: offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_headers),
! 482: NULL },
! 483:
! 484: { ngx_string("proxy_hide_header"),
! 485: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
! 486: ngx_conf_set_str_array_slot,
! 487: NGX_HTTP_LOC_CONF_OFFSET,
! 488: offsetof(ngx_http_proxy_loc_conf_t, upstream.hide_headers),
! 489: NULL },
! 490:
! 491: { ngx_string("proxy_ignore_headers"),
! 492: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
! 493: ngx_conf_set_bitmask_slot,
! 494: NGX_HTTP_LOC_CONF_OFFSET,
! 495: offsetof(ngx_http_proxy_loc_conf_t, upstream.ignore_headers),
! 496: &ngx_http_upstream_ignore_headers_masks },
! 497:
! 498: { ngx_string("proxy_http_version"),
! 499: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
! 500: ngx_conf_set_enum_slot,
! 501: NGX_HTTP_LOC_CONF_OFFSET,
! 502: offsetof(ngx_http_proxy_loc_conf_t, http_version),
! 503: &ngx_http_proxy_http_version },
! 504:
! 505: #if (NGX_HTTP_SSL)
! 506:
! 507: { ngx_string("proxy_ssl_session_reuse"),
! 508: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
! 509: ngx_conf_set_flag_slot,
! 510: NGX_HTTP_LOC_CONF_OFFSET,
! 511: offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_session_reuse),
! 512: NULL },
! 513:
! 514: #endif
! 515:
! 516: ngx_null_command
! 517: };
! 518:
! 519:
! 520: static ngx_http_module_t ngx_http_proxy_module_ctx = {
! 521: ngx_http_proxy_add_variables, /* preconfiguration */
! 522: NULL, /* postconfiguration */
! 523:
! 524: NULL, /* create main configuration */
! 525: NULL, /* init main configuration */
! 526:
! 527: NULL, /* create server configuration */
! 528: NULL, /* merge server configuration */
! 529:
! 530: ngx_http_proxy_create_loc_conf, /* create location configuration */
! 531: ngx_http_proxy_merge_loc_conf /* merge location configuration */
! 532: };
! 533:
! 534:
! 535: ngx_module_t ngx_http_proxy_module = {
! 536: NGX_MODULE_V1,
! 537: &ngx_http_proxy_module_ctx, /* module context */
! 538: ngx_http_proxy_commands, /* module directives */
! 539: NGX_HTTP_MODULE, /* module type */
! 540: NULL, /* init master */
! 541: NULL, /* init module */
! 542: NULL, /* init process */
! 543: NULL, /* init thread */
! 544: NULL, /* exit thread */
! 545: NULL, /* exit process */
! 546: NULL, /* exit master */
! 547: NGX_MODULE_V1_PADDING
! 548: };
! 549:
! 550:
! 551: static char ngx_http_proxy_version[] = " HTTP/1.0" CRLF;
! 552: static char ngx_http_proxy_version_11[] = " HTTP/1.1" CRLF;
! 553:
! 554:
! 555: static ngx_keyval_t ngx_http_proxy_headers[] = {
! 556: { ngx_string("Host"), ngx_string("$proxy_host") },
! 557: { ngx_string("Connection"), ngx_string("close") },
! 558: { ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") },
! 559: { ngx_string("Transfer-Encoding"), ngx_string("") },
! 560: { ngx_string("Keep-Alive"), ngx_string("") },
! 561: { ngx_string("Expect"), ngx_string("") },
! 562: { ngx_string("Upgrade"), ngx_string("") },
! 563: { ngx_null_string, ngx_null_string }
! 564: };
! 565:
! 566:
! 567: static ngx_str_t ngx_http_proxy_hide_headers[] = {
! 568: ngx_string("Date"),
! 569: ngx_string("Server"),
! 570: ngx_string("X-Pad"),
! 571: ngx_string("X-Accel-Expires"),
! 572: ngx_string("X-Accel-Redirect"),
! 573: ngx_string("X-Accel-Limit-Rate"),
! 574: ngx_string("X-Accel-Buffering"),
! 575: ngx_string("X-Accel-Charset"),
! 576: ngx_null_string
! 577: };
! 578:
! 579:
! 580: #if (NGX_HTTP_CACHE)
! 581:
! 582: static ngx_keyval_t ngx_http_proxy_cache_headers[] = {
! 583: { ngx_string("Host"), ngx_string("$proxy_host") },
! 584: { ngx_string("Connection"), ngx_string("close") },
! 585: { ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") },
! 586: { ngx_string("Transfer-Encoding"), ngx_string("") },
! 587: { ngx_string("Keep-Alive"), ngx_string("") },
! 588: { ngx_string("Expect"), ngx_string("") },
! 589: { ngx_string("Upgrade"), ngx_string("") },
! 590: { ngx_string("If-Modified-Since"), ngx_string("") },
! 591: { ngx_string("If-Unmodified-Since"), ngx_string("") },
! 592: { ngx_string("If-None-Match"), ngx_string("") },
! 593: { ngx_string("If-Match"), ngx_string("") },
! 594: { ngx_string("Range"), ngx_string("") },
! 595: { ngx_string("If-Range"), ngx_string("") },
! 596: { ngx_null_string, ngx_null_string }
! 597: };
! 598:
! 599: #endif
! 600:
! 601:
! 602: static ngx_http_variable_t ngx_http_proxy_vars[] = {
! 603:
! 604: { ngx_string("proxy_host"), NULL, ngx_http_proxy_host_variable, 0,
! 605: NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
! 606:
! 607: { ngx_string("proxy_port"), NULL, ngx_http_proxy_port_variable, 0,
! 608: NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
! 609:
! 610: { ngx_string("proxy_add_x_forwarded_for"), NULL,
! 611: ngx_http_proxy_add_x_forwarded_for_variable, 0, NGX_HTTP_VAR_NOHASH, 0 },
! 612:
! 613: #if 0
! 614: { ngx_string("proxy_add_via"), NULL, NULL, 0, NGX_HTTP_VAR_NOHASH, 0 },
! 615: #endif
! 616:
! 617: { ngx_string("proxy_internal_body_length"), NULL,
! 618: ngx_http_proxy_internal_body_length_variable, 0,
! 619: NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
! 620:
! 621: { ngx_null_string, NULL, NULL, 0, 0, 0 }
! 622: };
! 623:
! 624:
! 625: static ngx_path_init_t ngx_http_proxy_temp_path = {
! 626: ngx_string(NGX_HTTP_PROXY_TEMP_PATH), { 1, 2, 0 }
! 627: };
! 628:
! 629:
! 630: static ngx_int_t
! 631: ngx_http_proxy_handler(ngx_http_request_t *r)
! 632: {
! 633: ngx_int_t rc;
! 634: ngx_http_upstream_t *u;
! 635: ngx_http_proxy_ctx_t *ctx;
! 636: ngx_http_proxy_loc_conf_t *plcf;
! 637:
! 638: if (ngx_http_upstream_create(r) != NGX_OK) {
! 639: return NGX_HTTP_INTERNAL_SERVER_ERROR;
! 640: }
! 641:
! 642: ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_ctx_t));
! 643: if (ctx == NULL) {
! 644: return NGX_ERROR;
! 645: }
! 646:
! 647: ngx_http_set_ctx(r, ctx, ngx_http_proxy_module);
! 648:
! 649: plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
! 650:
! 651: u = r->upstream;
! 652:
! 653: if (plcf->proxy_lengths == NULL) {
! 654: ctx->vars = plcf->vars;
! 655: u->schema = plcf->vars.schema;
! 656: #if (NGX_HTTP_SSL)
! 657: u->ssl = (plcf->upstream.ssl != NULL);
! 658: #endif
! 659:
! 660: } else {
! 661: if (ngx_http_proxy_eval(r, ctx, plcf) != NGX_OK) {
! 662: return NGX_HTTP_INTERNAL_SERVER_ERROR;
! 663: }
! 664: }
! 665:
! 666: u->output.tag = (ngx_buf_tag_t) &ngx_http_proxy_module;
! 667:
! 668: u->conf = &plcf->upstream;
! 669:
! 670: #if (NGX_HTTP_CACHE)
! 671: u->create_key = ngx_http_proxy_create_key;
! 672: #endif
! 673: u->create_request = ngx_http_proxy_create_request;
! 674: u->reinit_request = ngx_http_proxy_reinit_request;
! 675: u->process_header = ngx_http_proxy_process_status_line;
! 676: u->abort_request = ngx_http_proxy_abort_request;
! 677: u->finalize_request = ngx_http_proxy_finalize_request;
! 678: r->state = 0;
! 679:
! 680: if (plcf->redirects) {
! 681: u->rewrite_redirect = ngx_http_proxy_rewrite_redirect;
! 682: }
! 683:
! 684: if (plcf->cookie_domains || plcf->cookie_paths) {
! 685: u->rewrite_cookie = ngx_http_proxy_rewrite_cookie;
! 686: }
! 687:
! 688: u->buffering = plcf->upstream.buffering;
! 689:
! 690: u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
! 691: if (u->pipe == NULL) {
! 692: return NGX_HTTP_INTERNAL_SERVER_ERROR;
! 693: }
! 694:
! 695: u->pipe->input_filter = ngx_http_proxy_copy_filter;
! 696: u->pipe->input_ctx = r;
! 697:
! 698: u->input_filter_init = ngx_http_proxy_input_filter_init;
! 699: u->input_filter = ngx_http_proxy_non_buffered_copy_filter;
! 700: u->input_filter_ctx = r;
! 701:
! 702: u->accel = 1;
! 703:
! 704: rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
! 705:
! 706: if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
! 707: return rc;
! 708: }
! 709:
! 710: return NGX_DONE;
! 711: }
! 712:
! 713:
! 714: static ngx_int_t
! 715: ngx_http_proxy_eval(ngx_http_request_t *r, ngx_http_proxy_ctx_t *ctx,
! 716: ngx_http_proxy_loc_conf_t *plcf)
! 717: {
! 718: u_char *p;
! 719: size_t add;
! 720: u_short port;
! 721: ngx_str_t proxy;
! 722: ngx_url_t url;
! 723: ngx_http_upstream_t *u;
! 724:
! 725: if (ngx_http_script_run(r, &proxy, plcf->proxy_lengths->elts, 0,
! 726: plcf->proxy_values->elts)
! 727: == NULL)
! 728: {
! 729: return NGX_ERROR;
! 730: }
! 731:
! 732: if (proxy.len > 7
! 733: && ngx_strncasecmp(proxy.data, (u_char *) "http://", 7) == 0)
! 734: {
! 735: add = 7;
! 736: port = 80;
! 737:
! 738: #if (NGX_HTTP_SSL)
! 739:
! 740: } else if (proxy.len > 8
! 741: && ngx_strncasecmp(proxy.data, (u_char *) "https://", 8) == 0)
! 742: {
! 743: add = 8;
! 744: port = 443;
! 745: r->upstream->ssl = 1;
! 746:
! 747: #endif
! 748:
! 749: } else {
! 750: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
! 751: "invalid URL prefix in \"%V\"", &proxy);
! 752: return NGX_ERROR;
! 753: }
! 754:
! 755: u = r->upstream;
! 756:
! 757: u->schema.len = add;
! 758: u->schema.data = proxy.data;
! 759:
! 760: ngx_memzero(&url, sizeof(ngx_url_t));
! 761:
! 762: url.url.len = proxy.len - add;
! 763: url.url.data = proxy.data + add;
! 764: url.default_port = port;
! 765: url.uri_part = 1;
! 766: url.no_resolve = 1;
! 767:
! 768: if (ngx_parse_url(r->pool, &url) != NGX_OK) {
! 769: if (url.err) {
! 770: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
! 771: "%s in upstream \"%V\"", url.err, &url.url);
! 772: }
! 773:
! 774: return NGX_ERROR;
! 775: }
! 776:
! 777: if (url.uri.len) {
! 778: if (url.uri.data[0] == '?') {
! 779: p = ngx_pnalloc(r->pool, url.uri.len + 1);
! 780: if (p == NULL) {
! 781: return NGX_ERROR;
! 782: }
! 783:
! 784: *p++ = '/';
! 785: ngx_memcpy(p, url.uri.data, url.uri.len);
! 786:
! 787: url.uri.len++;
! 788: url.uri.data = p - 1;
! 789: }
! 790: }
! 791:
! 792: ctx->vars.key_start = u->schema;
! 793:
! 794: ngx_http_proxy_set_vars(&url, &ctx->vars);
! 795:
! 796: u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
! 797: if (u->resolved == NULL) {
! 798: return NGX_ERROR;
! 799: }
! 800:
! 801: if (url.addrs && url.addrs[0].sockaddr) {
! 802: u->resolved->sockaddr = url.addrs[0].sockaddr;
! 803: u->resolved->socklen = url.addrs[0].socklen;
! 804: u->resolved->naddrs = 1;
! 805: u->resolved->host = url.addrs[0].name;
! 806:
! 807: } else {
! 808: u->resolved->host = url.host;
! 809: u->resolved->port = (in_port_t) (url.no_port ? port : url.port);
! 810: u->resolved->no_port = url.no_port;
! 811: }
! 812:
! 813: return NGX_OK;
! 814: }
! 815:
! 816:
! 817: #if (NGX_HTTP_CACHE)
! 818:
! 819: static ngx_int_t
! 820: ngx_http_proxy_create_key(ngx_http_request_t *r)
! 821: {
! 822: size_t len, loc_len;
! 823: u_char *p;
! 824: uintptr_t escape;
! 825: ngx_str_t *key;
! 826: ngx_http_upstream_t *u;
! 827: ngx_http_proxy_ctx_t *ctx;
! 828: ngx_http_proxy_loc_conf_t *plcf;
! 829:
! 830: u = r->upstream;
! 831:
! 832: plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
! 833:
! 834: ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
! 835:
! 836: key = ngx_array_push(&r->cache->keys);
! 837: if (key == NULL) {
! 838: return NGX_ERROR;
! 839: }
! 840:
! 841: if (plcf->cache_key.value.data) {
! 842:
! 843: if (ngx_http_complex_value(r, &plcf->cache_key, key) != NGX_OK) {
! 844: return NGX_ERROR;
! 845: }
! 846:
! 847: return NGX_OK;
! 848: }
! 849:
! 850: *key = ctx->vars.key_start;
! 851:
! 852: key = ngx_array_push(&r->cache->keys);
! 853: if (key == NULL) {
! 854: return NGX_ERROR;
! 855: }
! 856:
! 857: if (plcf->proxy_lengths && ctx->vars.uri.len) {
! 858:
! 859: *key = ctx->vars.uri;
! 860: u->uri = ctx->vars.uri;
! 861:
! 862: return NGX_OK;
! 863:
! 864: } else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri && r == r->main)
! 865: {
! 866: *key = r->unparsed_uri;
! 867: u->uri = r->unparsed_uri;
! 868:
! 869: return NGX_OK;
! 870: }
! 871:
! 872: loc_len = (r->valid_location && ctx->vars.uri.len) ? plcf->location.len : 0;
! 873:
! 874: if (r->quoted_uri || r->internal) {
! 875: escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len,
! 876: r->uri.len - loc_len, NGX_ESCAPE_URI);
! 877: } else {
! 878: escape = 0;
! 879: }
! 880:
! 881: len = ctx->vars.uri.len + r->uri.len - loc_len + escape
! 882: + sizeof("?") - 1 + r->args.len;
! 883:
! 884: p = ngx_pnalloc(r->pool, len);
! 885: if (p == NULL) {
! 886: return NGX_ERROR;
! 887: }
! 888:
! 889: key->data = p;
! 890:
! 891: if (r->valid_location) {
! 892: p = ngx_copy(p, ctx->vars.uri.data, ctx->vars.uri.len);
! 893: }
! 894:
! 895: if (escape) {
! 896: ngx_escape_uri(p, r->uri.data + loc_len,
! 897: r->uri.len - loc_len, NGX_ESCAPE_URI);
! 898: p += r->uri.len - loc_len + escape;
! 899:
! 900: } else {
! 901: p = ngx_copy(p, r->uri.data + loc_len, r->uri.len - loc_len);
! 902: }
! 903:
! 904: if (r->args.len > 0) {
! 905: *p++ = '?';
! 906: p = ngx_copy(p, r->args.data, r->args.len);
! 907: }
! 908:
! 909: key->len = p - key->data;
! 910: u->uri = *key;
! 911:
! 912: return NGX_OK;
! 913: }
! 914:
! 915: #endif
! 916:
! 917:
! 918: static ngx_int_t
! 919: ngx_http_proxy_create_request(ngx_http_request_t *r)
! 920: {
! 921: size_t len, uri_len, loc_len, body_len;
! 922: uintptr_t escape;
! 923: ngx_buf_t *b;
! 924: ngx_str_t method;
! 925: ngx_uint_t i, unparsed_uri;
! 926: ngx_chain_t *cl, *body;
! 927: ngx_list_part_t *part;
! 928: ngx_table_elt_t *header;
! 929: ngx_http_upstream_t *u;
! 930: ngx_http_proxy_ctx_t *ctx;
! 931: ngx_http_script_code_pt code;
! 932: ngx_http_script_engine_t e, le;
! 933: ngx_http_proxy_loc_conf_t *plcf;
! 934: ngx_http_script_len_code_pt lcode;
! 935:
! 936: u = r->upstream;
! 937:
! 938: plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
! 939:
! 940: if (u->method.len) {
! 941: /* HEAD was changed to GET to cache response */
! 942: method = u->method;
! 943: method.len++;
! 944:
! 945: } else if (plcf->method.len) {
! 946: method = plcf->method;
! 947:
! 948: } else {
! 949: method = r->method_name;
! 950: method.len++;
! 951: }
! 952:
! 953: ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
! 954:
! 955: if (method.len == 5
! 956: && ngx_strncasecmp(method.data, (u_char *) "HEAD ", 5) == 0)
! 957: {
! 958: ctx->head = 1;
! 959: }
! 960:
! 961: len = method.len + sizeof(ngx_http_proxy_version) - 1 + sizeof(CRLF) - 1;
! 962:
! 963: escape = 0;
! 964: loc_len = 0;
! 965: unparsed_uri = 0;
! 966:
! 967: if (plcf->proxy_lengths && ctx->vars.uri.len) {
! 968: uri_len = ctx->vars.uri.len;
! 969:
! 970: } else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri && r == r->main)
! 971: {
! 972: unparsed_uri = 1;
! 973: uri_len = r->unparsed_uri.len;
! 974:
! 975: } else {
! 976: loc_len = (r->valid_location && ctx->vars.uri.len) ?
! 977: plcf->location.len : 0;
! 978:
! 979: if (r->quoted_uri || r->space_in_uri || r->internal) {
! 980: escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len,
! 981: r->uri.len - loc_len, NGX_ESCAPE_URI);
! 982: }
! 983:
! 984: uri_len = ctx->vars.uri.len + r->uri.len - loc_len + escape
! 985: + sizeof("?") - 1 + r->args.len;
! 986: }
! 987:
! 988: if (uri_len == 0) {
! 989: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
! 990: "zero length URI to proxy");
! 991: return NGX_ERROR;
! 992: }
! 993:
! 994: len += uri_len;
! 995:
! 996: ngx_http_script_flush_no_cacheable_variables(r, plcf->flushes);
! 997:
! 998: if (plcf->body_set_len) {
! 999: le.ip = plcf->body_set_len->elts;
! 1000: le.request = r;
! 1001: le.flushed = 1;
! 1002: body_len = 0;
! 1003:
! 1004: while (*(uintptr_t *) le.ip) {
! 1005: lcode = *(ngx_http_script_len_code_pt *) le.ip;
! 1006: body_len += lcode(&le);
! 1007: }
! 1008:
! 1009: ctx->internal_body_length = body_len;
! 1010: len += body_len;
! 1011:
! 1012: } else {
! 1013: ctx->internal_body_length = r->headers_in.content_length_n;
! 1014: }
! 1015:
! 1016: le.ip = plcf->headers_set_len->elts;
! 1017: le.request = r;
! 1018: le.flushed = 1;
! 1019:
! 1020: while (*(uintptr_t *) le.ip) {
! 1021: while (*(uintptr_t *) le.ip) {
! 1022: lcode = *(ngx_http_script_len_code_pt *) le.ip;
! 1023: len += lcode(&le);
! 1024: }
! 1025: le.ip += sizeof(uintptr_t);
! 1026: }
! 1027:
! 1028:
! 1029: if (plcf->upstream.pass_request_headers) {
! 1030: part = &r->headers_in.headers.part;
! 1031: header = part->elts;
! 1032:
! 1033: for (i = 0; /* void */; i++) {
! 1034:
! 1035: if (i >= part->nelts) {
! 1036: if (part->next == NULL) {
! 1037: break;
! 1038: }
! 1039:
! 1040: part = part->next;
! 1041: header = part->elts;
! 1042: i = 0;
! 1043: }
! 1044:
! 1045: if (ngx_hash_find(&plcf->headers_set_hash, header[i].hash,
! 1046: header[i].lowcase_key, header[i].key.len))
! 1047: {
! 1048: continue;
! 1049: }
! 1050:
! 1051: len += header[i].key.len + sizeof(": ") - 1
! 1052: + header[i].value.len + sizeof(CRLF) - 1;
! 1053: }
! 1054: }
! 1055:
! 1056:
! 1057: b = ngx_create_temp_buf(r->pool, len);
! 1058: if (b == NULL) {
! 1059: return NGX_ERROR;
! 1060: }
! 1061:
! 1062: cl = ngx_alloc_chain_link(r->pool);
! 1063: if (cl == NULL) {
! 1064: return NGX_ERROR;
! 1065: }
! 1066:
! 1067: cl->buf = b;
! 1068:
! 1069:
! 1070: /* the request line */
! 1071:
! 1072: b->last = ngx_copy(b->last, method.data, method.len);
! 1073:
! 1074: u->uri.data = b->last;
! 1075:
! 1076: if (plcf->proxy_lengths && ctx->vars.uri.len) {
! 1077: b->last = ngx_copy(b->last, ctx->vars.uri.data, ctx->vars.uri.len);
! 1078:
! 1079: } else if (unparsed_uri) {
! 1080: b->last = ngx_copy(b->last, r->unparsed_uri.data, r->unparsed_uri.len);
! 1081:
! 1082: } else {
! 1083: if (r->valid_location) {
! 1084: b->last = ngx_copy(b->last, ctx->vars.uri.data, ctx->vars.uri.len);
! 1085: }
! 1086:
! 1087: if (escape) {
! 1088: ngx_escape_uri(b->last, r->uri.data + loc_len,
! 1089: r->uri.len - loc_len, NGX_ESCAPE_URI);
! 1090: b->last += r->uri.len - loc_len + escape;
! 1091:
! 1092: } else {
! 1093: b->last = ngx_copy(b->last, r->uri.data + loc_len,
! 1094: r->uri.len - loc_len);
! 1095: }
! 1096:
! 1097: if (r->args.len > 0) {
! 1098: *b->last++ = '?';
! 1099: b->last = ngx_copy(b->last, r->args.data, r->args.len);
! 1100: }
! 1101: }
! 1102:
! 1103: u->uri.len = b->last - u->uri.data;
! 1104:
! 1105: if (plcf->http_version == NGX_HTTP_VERSION_11) {
! 1106: b->last = ngx_cpymem(b->last, ngx_http_proxy_version_11,
! 1107: sizeof(ngx_http_proxy_version_11) - 1);
! 1108:
! 1109: } else {
! 1110: b->last = ngx_cpymem(b->last, ngx_http_proxy_version,
! 1111: sizeof(ngx_http_proxy_version) - 1);
! 1112: }
! 1113:
! 1114: ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
! 1115:
! 1116: e.ip = plcf->headers_set->elts;
! 1117: e.pos = b->last;
! 1118: e.request = r;
! 1119: e.flushed = 1;
! 1120:
! 1121: le.ip = plcf->headers_set_len->elts;
! 1122:
! 1123: while (*(uintptr_t *) le.ip) {
! 1124: lcode = *(ngx_http_script_len_code_pt *) le.ip;
! 1125:
! 1126: /* skip the header line name length */
! 1127: (void) lcode(&le);
! 1128:
! 1129: if (*(ngx_http_script_len_code_pt *) le.ip) {
! 1130:
! 1131: for (len = 0; *(uintptr_t *) le.ip; len += lcode(&le)) {
! 1132: lcode = *(ngx_http_script_len_code_pt *) le.ip;
! 1133: }
! 1134:
! 1135: e.skip = (len == sizeof(CRLF) - 1) ? 1 : 0;
! 1136:
! 1137: } else {
! 1138: e.skip = 0;
! 1139: }
! 1140:
! 1141: le.ip += sizeof(uintptr_t);
! 1142:
! 1143: while (*(uintptr_t *) e.ip) {
! 1144: code = *(ngx_http_script_code_pt *) e.ip;
! 1145: code((ngx_http_script_engine_t *) &e);
! 1146: }
! 1147: e.ip += sizeof(uintptr_t);
! 1148: }
! 1149:
! 1150: b->last = e.pos;
! 1151:
! 1152:
! 1153: if (plcf->upstream.pass_request_headers) {
! 1154: part = &r->headers_in.headers.part;
! 1155: header = part->elts;
! 1156:
! 1157: for (i = 0; /* void */; i++) {
! 1158:
! 1159: if (i >= part->nelts) {
! 1160: if (part->next == NULL) {
! 1161: break;
! 1162: }
! 1163:
! 1164: part = part->next;
! 1165: header = part->elts;
! 1166: i = 0;
! 1167: }
! 1168:
! 1169: if (ngx_hash_find(&plcf->headers_set_hash, header[i].hash,
! 1170: header[i].lowcase_key, header[i].key.len))
! 1171: {
! 1172: continue;
! 1173: }
! 1174:
! 1175: b->last = ngx_copy(b->last, header[i].key.data, header[i].key.len);
! 1176:
! 1177: *b->last++ = ':'; *b->last++ = ' ';
! 1178:
! 1179: b->last = ngx_copy(b->last, header[i].value.data,
! 1180: header[i].value.len);
! 1181:
! 1182: *b->last++ = CR; *b->last++ = LF;
! 1183:
! 1184: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
! 1185: "http proxy header: \"%V: %V\"",
! 1186: &header[i].key, &header[i].value);
! 1187: }
! 1188: }
! 1189:
! 1190:
! 1191: /* add "\r\n" at the header end */
! 1192: *b->last++ = CR; *b->last++ = LF;
! 1193:
! 1194: if (plcf->body_set) {
! 1195: e.ip = plcf->body_set->elts;
! 1196: e.pos = b->last;
! 1197:
! 1198: while (*(uintptr_t *) e.ip) {
! 1199: code = *(ngx_http_script_code_pt *) e.ip;
! 1200: code((ngx_http_script_engine_t *) &e);
! 1201: }
! 1202:
! 1203: b->last = e.pos;
! 1204: }
! 1205:
! 1206: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
! 1207: "http proxy header:\n\"%*s\"",
! 1208: (size_t) (b->last - b->pos), b->pos);
! 1209:
! 1210: if (plcf->body_set == NULL && plcf->upstream.pass_request_body) {
! 1211:
! 1212: body = u->request_bufs;
! 1213: u->request_bufs = cl;
! 1214:
! 1215: while (body) {
! 1216: b = ngx_alloc_buf(r->pool);
! 1217: if (b == NULL) {
! 1218: return NGX_ERROR;
! 1219: }
! 1220:
! 1221: ngx_memcpy(b, body->buf, sizeof(ngx_buf_t));
! 1222:
! 1223: cl->next = ngx_alloc_chain_link(r->pool);
! 1224: if (cl->next == NULL) {
! 1225: return NGX_ERROR;
! 1226: }
! 1227:
! 1228: cl = cl->next;
! 1229: cl->buf = b;
! 1230:
! 1231: body = body->next;
! 1232: }
! 1233:
! 1234: } else {
! 1235: u->request_bufs = cl;
! 1236: }
! 1237:
! 1238: b->flush = 1;
! 1239: cl->next = NULL;
! 1240:
! 1241: return NGX_OK;
! 1242: }
! 1243:
! 1244:
! 1245: static ngx_int_t
! 1246: ngx_http_proxy_reinit_request(ngx_http_request_t *r)
! 1247: {
! 1248: ngx_http_proxy_ctx_t *ctx;
! 1249:
! 1250: ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
! 1251:
! 1252: if (ctx == NULL) {
! 1253: return NGX_OK;
! 1254: }
! 1255:
! 1256: ctx->status.code = 0;
! 1257: ctx->status.count = 0;
! 1258: ctx->status.start = NULL;
! 1259: ctx->status.end = NULL;
! 1260: ctx->chunked.state = 0;
! 1261:
! 1262: r->upstream->process_header = ngx_http_proxy_process_status_line;
! 1263: r->upstream->pipe->input_filter = ngx_http_proxy_copy_filter;
! 1264: r->upstream->input_filter = ngx_http_proxy_non_buffered_copy_filter;
! 1265: r->state = 0;
! 1266:
! 1267: return NGX_OK;
! 1268: }
! 1269:
! 1270:
! 1271: static ngx_int_t
! 1272: ngx_http_proxy_process_status_line(ngx_http_request_t *r)
! 1273: {
! 1274: size_t len;
! 1275: ngx_int_t rc;
! 1276: ngx_http_upstream_t *u;
! 1277: ngx_http_proxy_ctx_t *ctx;
! 1278:
! 1279: ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
! 1280:
! 1281: if (ctx == NULL) {
! 1282: return NGX_ERROR;
! 1283: }
! 1284:
! 1285: u = r->upstream;
! 1286:
! 1287: rc = ngx_http_parse_status_line(r, &u->buffer, &ctx->status);
! 1288:
! 1289: if (rc == NGX_AGAIN) {
! 1290: return rc;
! 1291: }
! 1292:
! 1293: if (rc == NGX_ERROR) {
! 1294:
! 1295: #if (NGX_HTTP_CACHE)
! 1296:
! 1297: if (r->cache) {
! 1298: r->http_version = NGX_HTTP_VERSION_9;
! 1299: return NGX_OK;
! 1300: }
! 1301:
! 1302: #endif
! 1303:
! 1304: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
! 1305: "upstream sent no valid HTTP/1.0 header");
! 1306:
! 1307: #if 0
! 1308: if (u->accel) {
! 1309: return NGX_HTTP_UPSTREAM_INVALID_HEADER;
! 1310: }
! 1311: #endif
! 1312:
! 1313: r->http_version = NGX_HTTP_VERSION_9;
! 1314: u->state->status = NGX_HTTP_OK;
! 1315: u->headers_in.connection_close = 1;
! 1316:
! 1317: return NGX_OK;
! 1318: }
! 1319:
! 1320: if (u->state) {
! 1321: u->state->status = ctx->status.code;
! 1322: }
! 1323:
! 1324: u->headers_in.status_n = ctx->status.code;
! 1325:
! 1326: len = ctx->status.end - ctx->status.start;
! 1327: u->headers_in.status_line.len = len;
! 1328:
! 1329: u->headers_in.status_line.data = ngx_pnalloc(r->pool, len);
! 1330: if (u->headers_in.status_line.data == NULL) {
! 1331: return NGX_ERROR;
! 1332: }
! 1333:
! 1334: ngx_memcpy(u->headers_in.status_line.data, ctx->status.start, len);
! 1335:
! 1336: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
! 1337: "http proxy status %ui \"%V\"",
! 1338: u->headers_in.status_n, &u->headers_in.status_line);
! 1339:
! 1340: if (ctx->status.http_version < NGX_HTTP_VERSION_11) {
! 1341: u->headers_in.connection_close = 1;
! 1342: }
! 1343:
! 1344: u->process_header = ngx_http_proxy_process_header;
! 1345:
! 1346: return ngx_http_proxy_process_header(r);
! 1347: }
! 1348:
! 1349:
! 1350: static ngx_int_t
! 1351: ngx_http_proxy_process_header(ngx_http_request_t *r)
! 1352: {
! 1353: ngx_int_t rc;
! 1354: ngx_table_elt_t *h;
! 1355: ngx_http_upstream_t *u;
! 1356: ngx_http_proxy_ctx_t *ctx;
! 1357: ngx_http_upstream_header_t *hh;
! 1358: ngx_http_upstream_main_conf_t *umcf;
! 1359:
! 1360: umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
! 1361:
! 1362: for ( ;; ) {
! 1363:
! 1364: rc = ngx_http_parse_header_line(r, &r->upstream->buffer, 1);
! 1365:
! 1366: if (rc == NGX_OK) {
! 1367:
! 1368: /* a header line has been parsed successfully */
! 1369:
! 1370: h = ngx_list_push(&r->upstream->headers_in.headers);
! 1371: if (h == NULL) {
! 1372: return NGX_ERROR;
! 1373: }
! 1374:
! 1375: h->hash = r->header_hash;
! 1376:
! 1377: h->key.len = r->header_name_end - r->header_name_start;
! 1378: h->value.len = r->header_end - r->header_start;
! 1379:
! 1380: h->key.data = ngx_pnalloc(r->pool,
! 1381: h->key.len + 1 + h->value.len + 1 + h->key.len);
! 1382: if (h->key.data == NULL) {
! 1383: return NGX_ERROR;
! 1384: }
! 1385:
! 1386: h->value.data = h->key.data + h->key.len + 1;
! 1387: h->lowcase_key = h->key.data + h->key.len + 1 + h->value.len + 1;
! 1388:
! 1389: ngx_memcpy(h->key.data, r->header_name_start, h->key.len);
! 1390: h->key.data[h->key.len] = '\0';
! 1391: ngx_memcpy(h->value.data, r->header_start, h->value.len);
! 1392: h->value.data[h->value.len] = '\0';
! 1393:
! 1394: if (h->key.len == r->lowcase_index) {
! 1395: ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len);
! 1396:
! 1397: } else {
! 1398: ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
! 1399: }
! 1400:
! 1401: hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
! 1402: h->lowcase_key, h->key.len);
! 1403:
! 1404: if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
! 1405: return NGX_ERROR;
! 1406: }
! 1407:
! 1408: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
! 1409: "http proxy header: \"%V: %V\"",
! 1410: &h->key, &h->value);
! 1411:
! 1412: continue;
! 1413: }
! 1414:
! 1415: if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
! 1416:
! 1417: /* a whole header has been parsed successfully */
! 1418:
! 1419: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
! 1420: "http proxy header done");
! 1421:
! 1422: /*
! 1423: * if no "Server" and "Date" in header line,
! 1424: * then add the special empty headers
! 1425: */
! 1426:
! 1427: if (r->upstream->headers_in.server == NULL) {
! 1428: h = ngx_list_push(&r->upstream->headers_in.headers);
! 1429: if (h == NULL) {
! 1430: return NGX_ERROR;
! 1431: }
! 1432:
! 1433: h->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash(
! 1434: ngx_hash('s', 'e'), 'r'), 'v'), 'e'), 'r');
! 1435:
! 1436: ngx_str_set(&h->key, "Server");
! 1437: ngx_str_null(&h->value);
! 1438: h->lowcase_key = (u_char *) "server";
! 1439: }
! 1440:
! 1441: if (r->upstream->headers_in.date == NULL) {
! 1442: h = ngx_list_push(&r->upstream->headers_in.headers);
! 1443: if (h == NULL) {
! 1444: return NGX_ERROR;
! 1445: }
! 1446:
! 1447: h->hash = ngx_hash(ngx_hash(ngx_hash('d', 'a'), 't'), 'e');
! 1448:
! 1449: ngx_str_set(&h->key, "Date");
! 1450: ngx_str_null(&h->value);
! 1451: h->lowcase_key = (u_char *) "date";
! 1452: }
! 1453:
! 1454: /* clear content length if response is chunked */
! 1455:
! 1456: u = r->upstream;
! 1457:
! 1458: if (u->headers_in.chunked) {
! 1459: u->headers_in.content_length_n = -1;
! 1460: }
! 1461:
! 1462: /*
! 1463: * set u->keepalive if response has no body; this allows to keep
! 1464: * connections alive in case of r->header_only or X-Accel-Redirect
! 1465: */
! 1466:
! 1467: ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
! 1468:
! 1469: if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
! 1470: || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED
! 1471: || ctx->head
! 1472: || (!u->headers_in.chunked
! 1473: && u->headers_in.content_length_n == 0))
! 1474: {
! 1475: u->keepalive = !u->headers_in.connection_close;
! 1476: }
! 1477:
! 1478: if (u->headers_in.status_n == NGX_HTTP_SWITCHING_PROTOCOLS) {
! 1479: u->keepalive = 0;
! 1480:
! 1481: if (r->headers_in.upgrade) {
! 1482: u->upgrade = 1;
! 1483: }
! 1484: }
! 1485:
! 1486: return NGX_OK;
! 1487: }
! 1488:
! 1489: if (rc == NGX_AGAIN) {
! 1490: return NGX_AGAIN;
! 1491: }
! 1492:
! 1493: /* there was error while a header line parsing */
! 1494:
! 1495: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
! 1496: "upstream sent invalid header");
! 1497:
! 1498: return NGX_HTTP_UPSTREAM_INVALID_HEADER;
! 1499: }
! 1500: }
! 1501:
! 1502:
! 1503: static ngx_int_t
! 1504: ngx_http_proxy_input_filter_init(void *data)
! 1505: {
! 1506: ngx_http_request_t *r = data;
! 1507: ngx_http_upstream_t *u;
! 1508: ngx_http_proxy_ctx_t *ctx;
! 1509:
! 1510: u = r->upstream;
! 1511: ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
! 1512:
! 1513: if (ctx == NULL) {
! 1514: return NGX_ERROR;
! 1515: }
! 1516:
! 1517: ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
! 1518: "http proxy filter init s:%d h:%d c:%d l:%O",
! 1519: u->headers_in.status_n, ctx->head, u->headers_in.chunked,
! 1520: u->headers_in.content_length_n);
! 1521:
! 1522: /* as per RFC2616, 4.4 Message Length */
! 1523:
! 1524: if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
! 1525: || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED
! 1526: || ctx->head)
! 1527: {
! 1528: /* 1xx, 204, and 304 and replies to HEAD requests */
! 1529: /* no 1xx since we don't send Expect and Upgrade */
! 1530:
! 1531: u->pipe->length = 0;
! 1532: u->length = 0;
! 1533: u->keepalive = !u->headers_in.connection_close;
! 1534:
! 1535: } else if (u->headers_in.chunked) {
! 1536: /* chunked */
! 1537:
! 1538: u->pipe->input_filter = ngx_http_proxy_chunked_filter;
! 1539: u->pipe->length = 3; /* "0" LF LF */
! 1540:
! 1541: u->input_filter = ngx_http_proxy_non_buffered_chunked_filter;
! 1542: u->length = -1;
! 1543:
! 1544: } else if (u->headers_in.content_length_n == 0) {
! 1545: /* empty body: special case as filter won't be called */
! 1546:
! 1547: u->pipe->length = 0;
! 1548: u->length = 0;
! 1549: u->keepalive = !u->headers_in.connection_close;
! 1550:
! 1551: } else {
! 1552: /* content length or connection close */
! 1553:
! 1554: u->pipe->length = u->headers_in.content_length_n;
! 1555: u->length = u->headers_in.content_length_n;
! 1556: }
! 1557:
! 1558: return NGX_OK;
! 1559: }
! 1560:
! 1561:
! 1562: static ngx_int_t
! 1563: ngx_http_proxy_copy_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
! 1564: {
! 1565: ngx_buf_t *b;
! 1566: ngx_chain_t *cl;
! 1567: ngx_http_request_t *r;
! 1568:
! 1569: if (buf->pos == buf->last) {
! 1570: return NGX_OK;
! 1571: }
! 1572:
! 1573: if (p->free) {
! 1574: cl = p->free;
! 1575: b = cl->buf;
! 1576: p->free = cl->next;
! 1577: ngx_free_chain(p->pool, cl);
! 1578:
! 1579: } else {
! 1580: b = ngx_alloc_buf(p->pool);
! 1581: if (b == NULL) {
! 1582: return NGX_ERROR;
! 1583: }
! 1584: }
! 1585:
! 1586: ngx_memcpy(b, buf, sizeof(ngx_buf_t));
! 1587: b->shadow = buf;
! 1588: b->tag = p->tag;
! 1589: b->last_shadow = 1;
! 1590: b->recycled = 1;
! 1591: buf->shadow = b;
! 1592:
! 1593: cl = ngx_alloc_chain_link(p->pool);
! 1594: if (cl == NULL) {
! 1595: return NGX_ERROR;
! 1596: }
! 1597:
! 1598: cl->buf = b;
! 1599: cl->next = NULL;
! 1600:
! 1601: ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "input buf #%d", b->num);
! 1602:
! 1603: if (p->in) {
! 1604: *p->last_in = cl;
! 1605: } else {
! 1606: p->in = cl;
! 1607: }
! 1608: p->last_in = &cl->next;
! 1609:
! 1610: if (p->length == -1) {
! 1611: return NGX_OK;
! 1612: }
! 1613:
! 1614: p->length -= b->last - b->pos;
! 1615:
! 1616: if (p->length == 0) {
! 1617: r = p->input_ctx;
! 1618: p->upstream_done = 1;
! 1619: r->upstream->keepalive = !r->upstream->headers_in.connection_close;
! 1620:
! 1621: } else if (p->length < 0) {
! 1622: r = p->input_ctx;
! 1623: p->upstream_done = 1;
! 1624:
! 1625: ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
! 1626: "upstream sent more data than specified in "
! 1627: "\"Content-Length\" header");
! 1628: }
! 1629:
! 1630: return NGX_OK;
! 1631: }
! 1632:
! 1633:
! 1634: static ngx_int_t
! 1635: ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
! 1636: {
! 1637: ngx_int_t rc;
! 1638: ngx_buf_t *b, **prev;
! 1639: ngx_chain_t *cl;
! 1640: ngx_http_request_t *r;
! 1641: ngx_http_proxy_ctx_t *ctx;
! 1642:
! 1643: if (buf->pos == buf->last) {
! 1644: return NGX_OK;
! 1645: }
! 1646:
! 1647: r = p->input_ctx;
! 1648: ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
! 1649:
! 1650: if (ctx == NULL) {
! 1651: return NGX_ERROR;
! 1652: }
! 1653:
! 1654: b = NULL;
! 1655: prev = &buf->shadow;
! 1656:
! 1657: for ( ;; ) {
! 1658:
! 1659: rc = ngx_http_parse_chunked(r, buf, &ctx->chunked);
! 1660:
! 1661: if (rc == NGX_OK) {
! 1662:
! 1663: /* a chunk has been parsed successfully */
! 1664:
! 1665: if (p->free) {
! 1666: cl = p->free;
! 1667: b = cl->buf;
! 1668: p->free = cl->next;
! 1669: ngx_free_chain(p->pool, cl);
! 1670:
! 1671: } else {
! 1672: b = ngx_alloc_buf(p->pool);
! 1673: if (b == NULL) {
! 1674: return NGX_ERROR;
! 1675: }
! 1676: }
! 1677:
! 1678: ngx_memzero(b, sizeof(ngx_buf_t));
! 1679:
! 1680: b->pos = buf->pos;
! 1681: b->start = buf->start;
! 1682: b->end = buf->end;
! 1683: b->tag = p->tag;
! 1684: b->temporary = 1;
! 1685: b->recycled = 1;
! 1686:
! 1687: *prev = b;
! 1688: prev = &b->shadow;
! 1689:
! 1690: cl = ngx_alloc_chain_link(p->pool);
! 1691: if (cl == NULL) {
! 1692: return NGX_ERROR;
! 1693: }
! 1694:
! 1695: cl->buf = b;
! 1696: cl->next = NULL;
! 1697:
! 1698: if (p->in) {
! 1699: *p->last_in = cl;
! 1700: } else {
! 1701: p->in = cl;
! 1702: }
! 1703: p->last_in = &cl->next;
! 1704:
! 1705: /* STUB */ b->num = buf->num;
! 1706:
! 1707: ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
! 1708: "input buf #%d %p", b->num, b->pos);
! 1709:
! 1710: if (buf->last - buf->pos >= ctx->chunked.size) {
! 1711:
! 1712: buf->pos += ctx->chunked.size;
! 1713: b->last = buf->pos;
! 1714: ctx->chunked.size = 0;
! 1715:
! 1716: continue;
! 1717: }
! 1718:
! 1719: ctx->chunked.size -= buf->last - buf->pos;
! 1720: buf->pos = buf->last;
! 1721: b->last = buf->last;
! 1722:
! 1723: continue;
! 1724: }
! 1725:
! 1726: if (rc == NGX_DONE) {
! 1727:
! 1728: /* a whole response has been parsed successfully */
! 1729:
! 1730: p->upstream_done = 1;
! 1731: r->upstream->keepalive = !r->upstream->headers_in.connection_close;
! 1732:
! 1733: break;
! 1734: }
! 1735:
! 1736: if (rc == NGX_AGAIN) {
! 1737:
! 1738: /* set p->length, minimal amount of data we want to see */
! 1739:
! 1740: p->length = ctx->chunked.length;
! 1741:
! 1742: break;
! 1743: }
! 1744:
! 1745: /* invalid response */
! 1746:
! 1747: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
! 1748: "upstream sent invalid chunked response");
! 1749:
! 1750: return NGX_ERROR;
! 1751: }
! 1752:
! 1753: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
! 1754: "http proxy chunked state %d, length %d",
! 1755: ctx->chunked.state, p->length);
! 1756:
! 1757: if (b) {
! 1758: b->shadow = buf;
! 1759: b->last_shadow = 1;
! 1760:
! 1761: ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
! 1762: "input buf %p %z", b->pos, b->last - b->pos);
! 1763:
! 1764: return NGX_OK;
! 1765: }
! 1766:
! 1767: /* there is no data record in the buf, add it to free chain */
! 1768:
! 1769: if (ngx_event_pipe_add_free_buf(p, buf) != NGX_OK) {
! 1770: return NGX_ERROR;
! 1771: }
! 1772:
! 1773: return NGX_OK;
! 1774: }
! 1775:
! 1776:
! 1777: static ngx_int_t
! 1778: ngx_http_proxy_non_buffered_copy_filter(void *data, ssize_t bytes)
! 1779: {
! 1780: ngx_http_request_t *r = data;
! 1781:
! 1782: ngx_buf_t *b;
! 1783: ngx_chain_t *cl, **ll;
! 1784: ngx_http_upstream_t *u;
! 1785:
! 1786: u = r->upstream;
! 1787:
! 1788: for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
! 1789: ll = &cl->next;
! 1790: }
! 1791:
! 1792: cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
! 1793: if (cl == NULL) {
! 1794: return NGX_ERROR;
! 1795: }
! 1796:
! 1797: *ll = cl;
! 1798:
! 1799: cl->buf->flush = 1;
! 1800: cl->buf->memory = 1;
! 1801:
! 1802: b = &u->buffer;
! 1803:
! 1804: cl->buf->pos = b->last;
! 1805: b->last += bytes;
! 1806: cl->buf->last = b->last;
! 1807: cl->buf->tag = u->output.tag;
! 1808:
! 1809: if (u->length == -1) {
! 1810: return NGX_OK;
! 1811: }
! 1812:
! 1813: u->length -= bytes;
! 1814:
! 1815: if (u->length == 0) {
! 1816: u->keepalive = !u->headers_in.connection_close;
! 1817: }
! 1818:
! 1819: return NGX_OK;
! 1820: }
! 1821:
! 1822:
! 1823: static ngx_int_t
! 1824: ngx_http_proxy_non_buffered_chunked_filter(void *data, ssize_t bytes)
! 1825: {
! 1826: ngx_http_request_t *r = data;
! 1827:
! 1828: ngx_int_t rc;
! 1829: ngx_buf_t *b, *buf;
! 1830: ngx_chain_t *cl, **ll;
! 1831: ngx_http_upstream_t *u;
! 1832: ngx_http_proxy_ctx_t *ctx;
! 1833:
! 1834: ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
! 1835:
! 1836: if (ctx == NULL) {
! 1837: return NGX_ERROR;
! 1838: }
! 1839:
! 1840: u = r->upstream;
! 1841: buf = &u->buffer;
! 1842:
! 1843: buf->pos = buf->last;
! 1844: buf->last += bytes;
! 1845:
! 1846: for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
! 1847: ll = &cl->next;
! 1848: }
! 1849:
! 1850: for ( ;; ) {
! 1851:
! 1852: rc = ngx_http_parse_chunked(r, buf, &ctx->chunked);
! 1853:
! 1854: if (rc == NGX_OK) {
! 1855:
! 1856: /* a chunk has been parsed successfully */
! 1857:
! 1858: cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
! 1859: if (cl == NULL) {
! 1860: return NGX_ERROR;
! 1861: }
! 1862:
! 1863: *ll = cl;
! 1864: ll = &cl->next;
! 1865:
! 1866: b = cl->buf;
! 1867:
! 1868: b->flush = 1;
! 1869: b->memory = 1;
! 1870:
! 1871: b->pos = buf->pos;
! 1872: b->tag = u->output.tag;
! 1873:
! 1874: if (buf->last - buf->pos >= ctx->chunked.size) {
! 1875: buf->pos += ctx->chunked.size;
! 1876: b->last = buf->pos;
! 1877: ctx->chunked.size = 0;
! 1878:
! 1879: } else {
! 1880: ctx->chunked.size -= buf->last - buf->pos;
! 1881: buf->pos = buf->last;
! 1882: b->last = buf->last;
! 1883: }
! 1884:
! 1885: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
! 1886: "http proxy out buf %p %z",
! 1887: b->pos, b->last - b->pos);
! 1888:
! 1889: continue;
! 1890: }
! 1891:
! 1892: if (rc == NGX_DONE) {
! 1893:
! 1894: /* a whole response has been parsed successfully */
! 1895:
! 1896: u->keepalive = !u->headers_in.connection_close;
! 1897: u->length = 0;
! 1898:
! 1899: break;
! 1900: }
! 1901:
! 1902: if (rc == NGX_AGAIN) {
! 1903: break;
! 1904: }
! 1905:
! 1906: /* invalid response */
! 1907:
! 1908: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
! 1909: "upstream sent invalid chunked response");
! 1910:
! 1911: return NGX_ERROR;
! 1912: }
! 1913:
! 1914: /* provide continuous buffer for subrequests in memory */
! 1915:
! 1916: if (r->subrequest_in_memory) {
! 1917:
! 1918: cl = u->out_bufs;
! 1919:
! 1920: if (cl) {
! 1921: buf->pos = cl->buf->pos;
! 1922: }
! 1923:
! 1924: buf->last = buf->pos;
! 1925:
! 1926: for (cl = u->out_bufs; cl; cl = cl->next) {
! 1927: ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
! 1928: "http proxy in memory %p-%p %uz",
! 1929: cl->buf->pos, cl->buf->last, ngx_buf_size(cl->buf));
! 1930:
! 1931: if (buf->last == cl->buf->pos) {
! 1932: buf->last = cl->buf->last;
! 1933: continue;
! 1934: }
! 1935:
! 1936: buf->last = ngx_movemem(buf->last, cl->buf->pos,
! 1937: cl->buf->last - cl->buf->pos);
! 1938:
! 1939: cl->buf->pos = buf->last - (cl->buf->last - cl->buf->pos);
! 1940: cl->buf->last = buf->last;
! 1941: }
! 1942: }
! 1943:
! 1944: return NGX_OK;
! 1945: }
! 1946:
! 1947:
! 1948: static void
! 1949: ngx_http_proxy_abort_request(ngx_http_request_t *r)
! 1950: {
! 1951: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
! 1952: "abort http proxy request");
! 1953:
! 1954: return;
! 1955: }
! 1956:
! 1957:
! 1958: static void
! 1959: ngx_http_proxy_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
! 1960: {
! 1961: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
! 1962: "finalize http proxy request");
! 1963:
! 1964: return;
! 1965: }
! 1966:
! 1967:
! 1968: static ngx_int_t
! 1969: ngx_http_proxy_host_variable(ngx_http_request_t *r,
! 1970: ngx_http_variable_value_t *v, uintptr_t data)
! 1971: {
! 1972: ngx_http_proxy_ctx_t *ctx;
! 1973:
! 1974: ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
! 1975:
! 1976: if (ctx == NULL) {
! 1977: v->not_found = 1;
! 1978: return NGX_OK;
! 1979: }
! 1980:
! 1981: v->len = ctx->vars.host_header.len;
! 1982: v->valid = 1;
! 1983: v->no_cacheable = 0;
! 1984: v->not_found = 0;
! 1985: v->data = ctx->vars.host_header.data;
! 1986:
! 1987: return NGX_OK;
! 1988: }
! 1989:
! 1990:
! 1991: static ngx_int_t
! 1992: ngx_http_proxy_port_variable(ngx_http_request_t *r,
! 1993: ngx_http_variable_value_t *v, uintptr_t data)
! 1994: {
! 1995: ngx_http_proxy_ctx_t *ctx;
! 1996:
! 1997: ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
! 1998:
! 1999: if (ctx == NULL) {
! 2000: v->not_found = 1;
! 2001: return NGX_OK;
! 2002: }
! 2003:
! 2004: v->len = ctx->vars.port.len;
! 2005: v->valid = 1;
! 2006: v->no_cacheable = 0;
! 2007: v->not_found = 0;
! 2008: v->data = ctx->vars.port.data;
! 2009:
! 2010: return NGX_OK;
! 2011: }
! 2012:
! 2013:
! 2014: static ngx_int_t
! 2015: ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r,
! 2016: ngx_http_variable_value_t *v, uintptr_t data)
! 2017: {
! 2018: size_t len;
! 2019: u_char *p;
! 2020: ngx_uint_t i, n;
! 2021: ngx_table_elt_t **h;
! 2022:
! 2023: v->valid = 1;
! 2024: v->no_cacheable = 0;
! 2025: v->not_found = 0;
! 2026:
! 2027: n = r->headers_in.x_forwarded_for.nelts;
! 2028: h = r->headers_in.x_forwarded_for.elts;
! 2029:
! 2030: len = 0;
! 2031:
! 2032: for (i = 0; i < n; i++) {
! 2033: len += h[i]->value.len + sizeof(", ") - 1;
! 2034: }
! 2035:
! 2036: if (len == 0) {
! 2037: v->len = r->connection->addr_text.len;
! 2038: v->data = r->connection->addr_text.data;
! 2039: return NGX_OK;
! 2040: }
! 2041:
! 2042: len += r->connection->addr_text.len;
! 2043:
! 2044: p = ngx_pnalloc(r->pool, len);
! 2045: if (p == NULL) {
! 2046: return NGX_ERROR;
! 2047: }
! 2048:
! 2049: v->len = len;
! 2050: v->data = p;
! 2051:
! 2052: for (i = 0; i < n; i++) {
! 2053: p = ngx_copy(p, h[i]->value.data, h[i]->value.len);
! 2054: *p++ = ','; *p++ = ' ';
! 2055: }
! 2056:
! 2057: ngx_memcpy(p, r->connection->addr_text.data, r->connection->addr_text.len);
! 2058:
! 2059: return NGX_OK;
! 2060: }
! 2061:
! 2062:
! 2063: static ngx_int_t
! 2064: ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r,
! 2065: ngx_http_variable_value_t *v, uintptr_t data)
! 2066: {
! 2067: ngx_http_proxy_ctx_t *ctx;
! 2068:
! 2069: ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
! 2070:
! 2071: if (ctx == NULL || ctx->internal_body_length < 0) {
! 2072: v->not_found = 1;
! 2073: return NGX_OK;
! 2074: }
! 2075:
! 2076: v->valid = 1;
! 2077: v->no_cacheable = 0;
! 2078: v->not_found = 0;
! 2079:
! 2080: v->data = ngx_pnalloc(r->connection->pool, NGX_OFF_T_LEN);
! 2081:
! 2082: if (v->data == NULL) {
! 2083: return NGX_ERROR;
! 2084: }
! 2085:
! 2086: v->len = ngx_sprintf(v->data, "%O", ctx->internal_body_length) - v->data;
! 2087:
! 2088: return NGX_OK;
! 2089: }
! 2090:
! 2091:
! 2092: static ngx_int_t
! 2093: ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, ngx_table_elt_t *h,
! 2094: size_t prefix)
! 2095: {
! 2096: size_t len;
! 2097: ngx_int_t rc;
! 2098: ngx_uint_t i;
! 2099: ngx_http_proxy_rewrite_t *pr;
! 2100: ngx_http_proxy_loc_conf_t *plcf;
! 2101:
! 2102: plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
! 2103:
! 2104: pr = plcf->redirects->elts;
! 2105:
! 2106: if (pr == NULL) {
! 2107: return NGX_DECLINED;
! 2108: }
! 2109:
! 2110: len = h->value.len - prefix;
! 2111:
! 2112: for (i = 0; i < plcf->redirects->nelts; i++) {
! 2113: rc = pr[i].handler(r, h, prefix, len, &pr[i]);
! 2114:
! 2115: if (rc != NGX_DECLINED) {
! 2116: return rc;
! 2117: }
! 2118: }
! 2119:
! 2120: return NGX_DECLINED;
! 2121: }
! 2122:
! 2123:
! 2124: static ngx_int_t
! 2125: ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r, ngx_table_elt_t *h)
! 2126: {
! 2127: size_t prefix;
! 2128: u_char *p;
! 2129: ngx_int_t rc, rv;
! 2130: ngx_http_proxy_loc_conf_t *plcf;
! 2131:
! 2132: p = (u_char *) ngx_strchr(h->value.data, ';');
! 2133: if (p == NULL) {
! 2134: return NGX_DECLINED;
! 2135: }
! 2136:
! 2137: prefix = p + 1 - h->value.data;
! 2138:
! 2139: rv = NGX_DECLINED;
! 2140:
! 2141: plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
! 2142:
! 2143: if (plcf->cookie_domains) {
! 2144: p = ngx_strcasestrn(h->value.data + prefix, "domain=", 7 - 1);
! 2145:
! 2146: if (p) {
! 2147: rc = ngx_http_proxy_rewrite_cookie_value(r, h, p + 7,
! 2148: plcf->cookie_domains);
! 2149: if (rc == NGX_ERROR) {
! 2150: return NGX_ERROR;
! 2151: }
! 2152:
! 2153: if (rc != NGX_DECLINED) {
! 2154: rv = rc;
! 2155: }
! 2156: }
! 2157: }
! 2158:
! 2159: if (plcf->cookie_paths) {
! 2160: p = ngx_strcasestrn(h->value.data + prefix, "path=", 5 - 1);
! 2161:
! 2162: if (p) {
! 2163: rc = ngx_http_proxy_rewrite_cookie_value(r, h, p + 5,
! 2164: plcf->cookie_paths);
! 2165: if (rc == NGX_ERROR) {
! 2166: return NGX_ERROR;
! 2167: }
! 2168:
! 2169: if (rc != NGX_DECLINED) {
! 2170: rv = rc;
! 2171: }
! 2172: }
! 2173: }
! 2174:
! 2175: return rv;
! 2176: }
! 2177:
! 2178:
! 2179: static ngx_int_t
! 2180: ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r, ngx_table_elt_t *h,
! 2181: u_char *value, ngx_array_t *rewrites)
! 2182: {
! 2183: size_t len, prefix;
! 2184: u_char *p;
! 2185: ngx_int_t rc;
! 2186: ngx_uint_t i;
! 2187: ngx_http_proxy_rewrite_t *pr;
! 2188:
! 2189: prefix = value - h->value.data;
! 2190:
! 2191: p = (u_char *) ngx_strchr(value, ';');
! 2192:
! 2193: len = p ? (size_t) (p - value) : (h->value.len - prefix);
! 2194:
! 2195: pr = rewrites->elts;
! 2196:
! 2197: for (i = 0; i < rewrites->nelts; i++) {
! 2198: rc = pr[i].handler(r, h, prefix, len, &pr[i]);
! 2199:
! 2200: if (rc != NGX_DECLINED) {
! 2201: return rc;
! 2202: }
! 2203: }
! 2204:
! 2205: return NGX_DECLINED;
! 2206: }
! 2207:
! 2208:
! 2209: static ngx_int_t
! 2210: ngx_http_proxy_rewrite_complex_handler(ngx_http_request_t *r,
! 2211: ngx_table_elt_t *h, size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
! 2212: {
! 2213: ngx_str_t pattern, replacement;
! 2214:
! 2215: if (ngx_http_complex_value(r, &pr->pattern.complex, &pattern) != NGX_OK) {
! 2216: return NGX_ERROR;
! 2217: }
! 2218:
! 2219: if (pattern.len > len
! 2220: || ngx_rstrncmp(h->value.data + prefix, pattern.data,
! 2221: pattern.len) != 0)
! 2222: {
! 2223: return NGX_DECLINED;
! 2224: }
! 2225:
! 2226: if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
! 2227: return NGX_ERROR;
! 2228: }
! 2229:
! 2230: return ngx_http_proxy_rewrite(r, h, prefix, pattern.len, &replacement);
! 2231: }
! 2232:
! 2233:
! 2234: #if (NGX_PCRE)
! 2235:
! 2236: static ngx_int_t
! 2237: ngx_http_proxy_rewrite_regex_handler(ngx_http_request_t *r, ngx_table_elt_t *h,
! 2238: size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
! 2239: {
! 2240: ngx_str_t pattern, replacement;
! 2241:
! 2242: pattern.len = len;
! 2243: pattern.data = h->value.data + prefix;
! 2244:
! 2245: if (ngx_http_regex_exec(r, pr->pattern.regex, &pattern) != NGX_OK) {
! 2246: return NGX_DECLINED;
! 2247: }
! 2248:
! 2249: if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
! 2250: return NGX_ERROR;
! 2251: }
! 2252:
! 2253: if (prefix == 0 && h->value.len == len) {
! 2254: h->value = replacement;
! 2255: return NGX_OK;
! 2256: }
! 2257:
! 2258: return ngx_http_proxy_rewrite(r, h, prefix, len, &replacement);
! 2259: }
! 2260:
! 2261: #endif
! 2262:
! 2263:
! 2264: static ngx_int_t
! 2265: ngx_http_proxy_rewrite_domain_handler(ngx_http_request_t *r,
! 2266: ngx_table_elt_t *h, size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
! 2267: {
! 2268: u_char *p;
! 2269: ngx_str_t pattern, replacement;
! 2270:
! 2271: if (ngx_http_complex_value(r, &pr->pattern.complex, &pattern) != NGX_OK) {
! 2272: return NGX_ERROR;
! 2273: }
! 2274:
! 2275: p = h->value.data + prefix;
! 2276:
! 2277: if (p[0] == '.') {
! 2278: p++;
! 2279: prefix++;
! 2280: len--;
! 2281: }
! 2282:
! 2283: if (pattern.len != len || ngx_rstrncasecmp(pattern.data, p, len) != 0) {
! 2284: return NGX_DECLINED;
! 2285: }
! 2286:
! 2287: if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
! 2288: return NGX_ERROR;
! 2289: }
! 2290:
! 2291: return ngx_http_proxy_rewrite(r, h, prefix, len, &replacement);
! 2292: }
! 2293:
! 2294:
! 2295: static ngx_int_t
! 2296: ngx_http_proxy_rewrite(ngx_http_request_t *r, ngx_table_elt_t *h, size_t prefix,
! 2297: size_t len, ngx_str_t *replacement)
! 2298: {
! 2299: u_char *p, *data;
! 2300: size_t new_len;
! 2301:
! 2302: new_len = replacement->len + h->value.len - len;
! 2303:
! 2304: if (replacement->len > len) {
! 2305:
! 2306: data = ngx_pnalloc(r->pool, new_len);
! 2307: if (data == NULL) {
! 2308: return NGX_ERROR;
! 2309: }
! 2310:
! 2311: p = ngx_copy(data, h->value.data, prefix);
! 2312: p = ngx_copy(p, replacement->data, replacement->len);
! 2313:
! 2314: ngx_memcpy(p, h->value.data + prefix + len,
! 2315: h->value.len - len - prefix);
! 2316:
! 2317: h->value.data = data;
! 2318:
! 2319: } else {
! 2320: p = ngx_copy(h->value.data + prefix, replacement->data,
! 2321: replacement->len);
! 2322:
! 2323: ngx_memmove(p, h->value.data + prefix + len,
! 2324: h->value.len - len - prefix);
! 2325: }
! 2326:
! 2327: h->value.len = new_len;
! 2328:
! 2329: return NGX_OK;
! 2330: }
! 2331:
! 2332:
! 2333: static ngx_int_t
! 2334: ngx_http_proxy_add_variables(ngx_conf_t *cf)
! 2335: {
! 2336: ngx_http_variable_t *var, *v;
! 2337:
! 2338: for (v = ngx_http_proxy_vars; v->name.len; v++) {
! 2339: var = ngx_http_add_variable(cf, &v->name, v->flags);
! 2340: if (var == NULL) {
! 2341: return NGX_ERROR;
! 2342: }
! 2343:
! 2344: var->get_handler = v->get_handler;
! 2345: var->data = v->data;
! 2346: }
! 2347:
! 2348: return NGX_OK;
! 2349: }
! 2350:
! 2351:
! 2352: static void *
! 2353: ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
! 2354: {
! 2355: ngx_http_proxy_loc_conf_t *conf;
! 2356:
! 2357: conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_loc_conf_t));
! 2358: if (conf == NULL) {
! 2359: return NULL;
! 2360: }
! 2361:
! 2362: /*
! 2363: * set by ngx_pcalloc():
! 2364: *
! 2365: * conf->upstream.bufs.num = 0;
! 2366: * conf->upstream.ignore_headers = 0;
! 2367: * conf->upstream.next_upstream = 0;
! 2368: * conf->upstream.cache_use_stale = 0;
! 2369: * conf->upstream.cache_methods = 0;
! 2370: * conf->upstream.temp_path = NULL;
! 2371: * conf->upstream.hide_headers_hash = { NULL, 0 };
! 2372: * conf->upstream.uri = { 0, NULL };
! 2373: * conf->upstream.location = NULL;
! 2374: * conf->upstream.store_lengths = NULL;
! 2375: * conf->upstream.store_values = NULL;
! 2376: *
! 2377: * conf->method = { 0, NULL };
! 2378: * conf->headers_source = NULL;
! 2379: * conf->headers_set_len = NULL;
! 2380: * conf->headers_set = NULL;
! 2381: * conf->headers_set_hash = NULL;
! 2382: * conf->body_set_len = NULL;
! 2383: * conf->body_set = NULL;
! 2384: * conf->body_source = { 0, NULL };
! 2385: * conf->redirects = NULL;
! 2386: */
! 2387:
! 2388: conf->upstream.store = NGX_CONF_UNSET;
! 2389: conf->upstream.store_access = NGX_CONF_UNSET_UINT;
! 2390: conf->upstream.buffering = NGX_CONF_UNSET;
! 2391: conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
! 2392:
! 2393: conf->upstream.local = NGX_CONF_UNSET_PTR;
! 2394:
! 2395: conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
! 2396: conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
! 2397: conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
! 2398:
! 2399: conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
! 2400: conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
! 2401:
! 2402: conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE;
! 2403: conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
! 2404: conf->upstream.temp_file_write_size_conf = NGX_CONF_UNSET_SIZE;
! 2405:
! 2406: conf->upstream.pass_request_headers = NGX_CONF_UNSET;
! 2407: conf->upstream.pass_request_body = NGX_CONF_UNSET;
! 2408:
! 2409: #if (NGX_HTTP_CACHE)
! 2410: conf->upstream.cache = NGX_CONF_UNSET_PTR;
! 2411: conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
! 2412: conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
! 2413: conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
! 2414: conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
! 2415: conf->upstream.cache_lock = NGX_CONF_UNSET;
! 2416: conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
! 2417: #endif
! 2418:
! 2419: conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
! 2420: conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;
! 2421:
! 2422: conf->upstream.intercept_errors = NGX_CONF_UNSET;
! 2423: #if (NGX_HTTP_SSL)
! 2424: conf->upstream.ssl_session_reuse = NGX_CONF_UNSET;
! 2425: #endif
! 2426:
! 2427: /* "proxy_cyclic_temp_file" is disabled */
! 2428: conf->upstream.cyclic_temp_file = 0;
! 2429:
! 2430: conf->redirect = NGX_CONF_UNSET;
! 2431: conf->upstream.change_buffering = 1;
! 2432:
! 2433: conf->cookie_domains = NGX_CONF_UNSET_PTR;
! 2434: conf->cookie_paths = NGX_CONF_UNSET_PTR;
! 2435:
! 2436: conf->http_version = NGX_CONF_UNSET_UINT;
! 2437:
! 2438: conf->headers_hash_max_size = NGX_CONF_UNSET_UINT;
! 2439: conf->headers_hash_bucket_size = NGX_CONF_UNSET_UINT;
! 2440:
! 2441: ngx_str_set(&conf->upstream.module, "proxy");
! 2442:
! 2443: return conf;
! 2444: }
! 2445:
! 2446:
! 2447: static char *
! 2448: ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
! 2449: {
! 2450: ngx_http_proxy_loc_conf_t *prev = parent;
! 2451: ngx_http_proxy_loc_conf_t *conf = child;
! 2452:
! 2453: u_char *p;
! 2454: size_t size;
! 2455: ngx_hash_init_t hash;
! 2456: ngx_http_core_loc_conf_t *clcf;
! 2457: ngx_http_proxy_rewrite_t *pr;
! 2458: ngx_http_script_compile_t sc;
! 2459:
! 2460: if (conf->upstream.store != 0) {
! 2461: ngx_conf_merge_value(conf->upstream.store,
! 2462: prev->upstream.store, 0);
! 2463:
! 2464: if (conf->upstream.store_lengths == NULL) {
! 2465: conf->upstream.store_lengths = prev->upstream.store_lengths;
! 2466: conf->upstream.store_values = prev->upstream.store_values;
! 2467: }
! 2468: }
! 2469:
! 2470: ngx_conf_merge_uint_value(conf->upstream.store_access,
! 2471: prev->upstream.store_access, 0600);
! 2472:
! 2473: ngx_conf_merge_value(conf->upstream.buffering,
! 2474: prev->upstream.buffering, 1);
! 2475:
! 2476: ngx_conf_merge_value(conf->upstream.ignore_client_abort,
! 2477: prev->upstream.ignore_client_abort, 0);
! 2478:
! 2479: ngx_conf_merge_ptr_value(conf->upstream.local,
! 2480: prev->upstream.local, NULL);
! 2481:
! 2482: ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
! 2483: prev->upstream.connect_timeout, 60000);
! 2484:
! 2485: ngx_conf_merge_msec_value(conf->upstream.send_timeout,
! 2486: prev->upstream.send_timeout, 60000);
! 2487:
! 2488: ngx_conf_merge_msec_value(conf->upstream.read_timeout,
! 2489: prev->upstream.read_timeout, 60000);
! 2490:
! 2491: ngx_conf_merge_size_value(conf->upstream.send_lowat,
! 2492: prev->upstream.send_lowat, 0);
! 2493:
! 2494: ngx_conf_merge_size_value(conf->upstream.buffer_size,
! 2495: prev->upstream.buffer_size,
! 2496: (size_t) ngx_pagesize);
! 2497:
! 2498: ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
! 2499: 8, ngx_pagesize);
! 2500:
! 2501: if (conf->upstream.bufs.num < 2) {
! 2502: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 2503: "there must be at least 2 \"proxy_buffers\"");
! 2504: return NGX_CONF_ERROR;
! 2505: }
! 2506:
! 2507:
! 2508: size = conf->upstream.buffer_size;
! 2509: if (size < conf->upstream.bufs.size) {
! 2510: size = conf->upstream.bufs.size;
! 2511: }
! 2512:
! 2513:
! 2514: ngx_conf_merge_size_value(conf->upstream.busy_buffers_size_conf,
! 2515: prev->upstream.busy_buffers_size_conf,
! 2516: NGX_CONF_UNSET_SIZE);
! 2517:
! 2518: if (conf->upstream.busy_buffers_size_conf == NGX_CONF_UNSET_SIZE) {
! 2519: conf->upstream.busy_buffers_size = 2 * size;
! 2520: } else {
! 2521: conf->upstream.busy_buffers_size =
! 2522: conf->upstream.busy_buffers_size_conf;
! 2523: }
! 2524:
! 2525: if (conf->upstream.busy_buffers_size < size) {
! 2526: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 2527: "\"proxy_busy_buffers_size\" must be equal to or greater than "
! 2528: "the maximum of the value of \"proxy_buffer_size\" and "
! 2529: "one of the \"proxy_buffers\"");
! 2530:
! 2531: return NGX_CONF_ERROR;
! 2532: }
! 2533:
! 2534: if (conf->upstream.busy_buffers_size
! 2535: > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size)
! 2536: {
! 2537: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 2538: "\"proxy_busy_buffers_size\" must be less than "
! 2539: "the size of all \"proxy_buffers\" minus one buffer");
! 2540:
! 2541: return NGX_CONF_ERROR;
! 2542: }
! 2543:
! 2544:
! 2545: ngx_conf_merge_size_value(conf->upstream.temp_file_write_size_conf,
! 2546: prev->upstream.temp_file_write_size_conf,
! 2547: NGX_CONF_UNSET_SIZE);
! 2548:
! 2549: if (conf->upstream.temp_file_write_size_conf == NGX_CONF_UNSET_SIZE) {
! 2550: conf->upstream.temp_file_write_size = 2 * size;
! 2551: } else {
! 2552: conf->upstream.temp_file_write_size =
! 2553: conf->upstream.temp_file_write_size_conf;
! 2554: }
! 2555:
! 2556: if (conf->upstream.temp_file_write_size < size) {
! 2557: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 2558: "\"proxy_temp_file_write_size\" must be equal to or greater "
! 2559: "than the maximum of the value of \"proxy_buffer_size\" and "
! 2560: "one of the \"proxy_buffers\"");
! 2561:
! 2562: return NGX_CONF_ERROR;
! 2563: }
! 2564:
! 2565: ngx_conf_merge_size_value(conf->upstream.max_temp_file_size_conf,
! 2566: prev->upstream.max_temp_file_size_conf,
! 2567: NGX_CONF_UNSET_SIZE);
! 2568:
! 2569: if (conf->upstream.max_temp_file_size_conf == NGX_CONF_UNSET_SIZE) {
! 2570: conf->upstream.max_temp_file_size = 1024 * 1024 * 1024;
! 2571: } else {
! 2572: conf->upstream.max_temp_file_size =
! 2573: conf->upstream.max_temp_file_size_conf;
! 2574: }
! 2575:
! 2576: if (conf->upstream.max_temp_file_size != 0
! 2577: && conf->upstream.max_temp_file_size < size)
! 2578: {
! 2579: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 2580: "\"proxy_max_temp_file_size\" must be equal to zero to disable "
! 2581: "temporary files usage or must be equal to or greater than "
! 2582: "the maximum of the value of \"proxy_buffer_size\" and "
! 2583: "one of the \"proxy_buffers\"");
! 2584:
! 2585: return NGX_CONF_ERROR;
! 2586: }
! 2587:
! 2588:
! 2589: ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers,
! 2590: prev->upstream.ignore_headers,
! 2591: NGX_CONF_BITMASK_SET);
! 2592:
! 2593:
! 2594: ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
! 2595: prev->upstream.next_upstream,
! 2596: (NGX_CONF_BITMASK_SET
! 2597: |NGX_HTTP_UPSTREAM_FT_ERROR
! 2598: |NGX_HTTP_UPSTREAM_FT_TIMEOUT));
! 2599:
! 2600: if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) {
! 2601: conf->upstream.next_upstream = NGX_CONF_BITMASK_SET
! 2602: |NGX_HTTP_UPSTREAM_FT_OFF;
! 2603: }
! 2604:
! 2605: if (ngx_conf_merge_path_value(cf, &conf->upstream.temp_path,
! 2606: prev->upstream.temp_path,
! 2607: &ngx_http_proxy_temp_path)
! 2608: != NGX_OK)
! 2609: {
! 2610: return NGX_CONF_ERROR;
! 2611: }
! 2612:
! 2613:
! 2614: #if (NGX_HTTP_CACHE)
! 2615:
! 2616: ngx_conf_merge_ptr_value(conf->upstream.cache,
! 2617: prev->upstream.cache, NULL);
! 2618:
! 2619: if (conf->upstream.cache && conf->upstream.cache->data == NULL) {
! 2620: ngx_shm_zone_t *shm_zone;
! 2621:
! 2622: shm_zone = conf->upstream.cache;
! 2623:
! 2624: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 2625: "\"proxy_cache\" zone \"%V\" is unknown",
! 2626: &shm_zone->shm.name);
! 2627:
! 2628: return NGX_CONF_ERROR;
! 2629: }
! 2630:
! 2631: ngx_conf_merge_uint_value(conf->upstream.cache_min_uses,
! 2632: prev->upstream.cache_min_uses, 1);
! 2633:
! 2634: ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale,
! 2635: prev->upstream.cache_use_stale,
! 2636: (NGX_CONF_BITMASK_SET
! 2637: |NGX_HTTP_UPSTREAM_FT_OFF));
! 2638:
! 2639: if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_OFF) {
! 2640: conf->upstream.cache_use_stale = NGX_CONF_BITMASK_SET
! 2641: |NGX_HTTP_UPSTREAM_FT_OFF;
! 2642: }
! 2643:
! 2644: if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_ERROR) {
! 2645: conf->upstream.cache_use_stale |= NGX_HTTP_UPSTREAM_FT_NOLIVE;
! 2646: }
! 2647:
! 2648: if (conf->upstream.cache_methods == 0) {
! 2649: conf->upstream.cache_methods = prev->upstream.cache_methods;
! 2650: }
! 2651:
! 2652: conf->upstream.cache_methods |= NGX_HTTP_GET|NGX_HTTP_HEAD;
! 2653:
! 2654: ngx_conf_merge_ptr_value(conf->upstream.cache_bypass,
! 2655: prev->upstream.cache_bypass, NULL);
! 2656:
! 2657: ngx_conf_merge_ptr_value(conf->upstream.no_cache,
! 2658: prev->upstream.no_cache, NULL);
! 2659:
! 2660: if (conf->upstream.no_cache && conf->upstream.cache_bypass == NULL) {
! 2661: ngx_log_error(NGX_LOG_WARN, cf->log, 0,
! 2662: "\"proxy_no_cache\" functionality has been changed in 0.8.46, "
! 2663: "now it should be used together with \"proxy_cache_bypass\"");
! 2664: }
! 2665:
! 2666: ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
! 2667: prev->upstream.cache_valid, NULL);
! 2668:
! 2669: if (conf->cache_key.value.data == NULL) {
! 2670: conf->cache_key = prev->cache_key;
! 2671: }
! 2672:
! 2673: ngx_conf_merge_value(conf->upstream.cache_lock,
! 2674: prev->upstream.cache_lock, 0);
! 2675:
! 2676: ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
! 2677: prev->upstream.cache_lock_timeout, 5000);
! 2678:
! 2679: #endif
! 2680:
! 2681: ngx_conf_merge_str_value(conf->method, prev->method, "");
! 2682:
! 2683: if (conf->method.len
! 2684: && conf->method.data[conf->method.len - 1] != ' ')
! 2685: {
! 2686: conf->method.data[conf->method.len] = ' ';
! 2687: conf->method.len++;
! 2688: }
! 2689:
! 2690: ngx_conf_merge_value(conf->upstream.pass_request_headers,
! 2691: prev->upstream.pass_request_headers, 1);
! 2692: ngx_conf_merge_value(conf->upstream.pass_request_body,
! 2693: prev->upstream.pass_request_body, 1);
! 2694:
! 2695: ngx_conf_merge_value(conf->upstream.intercept_errors,
! 2696: prev->upstream.intercept_errors, 0);
! 2697:
! 2698: #if (NGX_HTTP_SSL)
! 2699: ngx_conf_merge_value(conf->upstream.ssl_session_reuse,
! 2700: prev->upstream.ssl_session_reuse, 1);
! 2701: #endif
! 2702:
! 2703: ngx_conf_merge_value(conf->redirect, prev->redirect, 1);
! 2704:
! 2705: if (conf->redirect) {
! 2706:
! 2707: if (conf->redirects == NULL) {
! 2708: conf->redirects = prev->redirects;
! 2709: }
! 2710:
! 2711: if (conf->redirects == NULL && conf->url.data) {
! 2712:
! 2713: conf->redirects = ngx_array_create(cf->pool, 1,
! 2714: sizeof(ngx_http_proxy_rewrite_t));
! 2715: if (conf->redirects == NULL) {
! 2716: return NGX_CONF_ERROR;
! 2717: }
! 2718:
! 2719: pr = ngx_array_push(conf->redirects);
! 2720: if (pr == NULL) {
! 2721: return NGX_CONF_ERROR;
! 2722: }
! 2723:
! 2724: ngx_memzero(&pr->pattern.complex,
! 2725: sizeof(ngx_http_complex_value_t));
! 2726:
! 2727: ngx_memzero(&pr->replacement, sizeof(ngx_http_complex_value_t));
! 2728:
! 2729: pr->handler = ngx_http_proxy_rewrite_complex_handler;
! 2730:
! 2731: if (conf->vars.uri.len) {
! 2732: pr->pattern.complex.value = conf->url;
! 2733: pr->replacement.value = conf->location;
! 2734:
! 2735: } else {
! 2736: pr->pattern.complex.value.len = conf->url.len
! 2737: + sizeof("/") - 1;
! 2738:
! 2739: p = ngx_pnalloc(cf->pool, pr->pattern.complex.value.len);
! 2740: if (p == NULL) {
! 2741: return NGX_CONF_ERROR;
! 2742: }
! 2743:
! 2744: pr->pattern.complex.value.data = p;
! 2745:
! 2746: p = ngx_cpymem(p, conf->url.data, conf->url.len);
! 2747: *p = '/';
! 2748:
! 2749: ngx_str_set(&pr->replacement.value, "/");
! 2750: }
! 2751: }
! 2752: }
! 2753:
! 2754: ngx_conf_merge_ptr_value(conf->cookie_domains, prev->cookie_domains, NULL);
! 2755:
! 2756: ngx_conf_merge_ptr_value(conf->cookie_paths, prev->cookie_paths, NULL);
! 2757:
! 2758: #if (NGX_HTTP_SSL)
! 2759: if (conf->upstream.ssl == NULL) {
! 2760: conf->upstream.ssl = prev->upstream.ssl;
! 2761: }
! 2762: #endif
! 2763:
! 2764: ngx_conf_merge_uint_value(conf->http_version, prev->http_version,
! 2765: NGX_HTTP_VERSION_10);
! 2766:
! 2767: ngx_conf_merge_uint_value(conf->headers_hash_max_size,
! 2768: prev->headers_hash_max_size, 512);
! 2769:
! 2770: ngx_conf_merge_uint_value(conf->headers_hash_bucket_size,
! 2771: prev->headers_hash_bucket_size, 64);
! 2772:
! 2773: conf->headers_hash_bucket_size = ngx_align(conf->headers_hash_bucket_size,
! 2774: ngx_cacheline_size);
! 2775:
! 2776: hash.max_size = conf->headers_hash_max_size;
! 2777: hash.bucket_size = conf->headers_hash_bucket_size;
! 2778: hash.name = "proxy_headers_hash";
! 2779:
! 2780: if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream,
! 2781: &prev->upstream, ngx_http_proxy_hide_headers, &hash)
! 2782: != NGX_OK)
! 2783: {
! 2784: return NGX_CONF_ERROR;
! 2785: }
! 2786:
! 2787: if (conf->upstream.upstream == NULL) {
! 2788: conf->upstream.upstream = prev->upstream.upstream;
! 2789: conf->vars = prev->vars;
! 2790: }
! 2791:
! 2792: if (conf->proxy_lengths == NULL) {
! 2793: conf->proxy_lengths = prev->proxy_lengths;
! 2794: conf->proxy_values = prev->proxy_values;
! 2795: }
! 2796:
! 2797: if (conf->upstream.upstream || conf->proxy_lengths) {
! 2798: clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
! 2799: if (clcf->handler == NULL && clcf->lmt_excpt) {
! 2800: clcf->handler = ngx_http_proxy_handler;
! 2801: conf->location = prev->location;
! 2802: }
! 2803: }
! 2804:
! 2805: if (conf->body_source.data == NULL) {
! 2806: conf->body_source = prev->body_source;
! 2807: conf->body_set_len = prev->body_set_len;
! 2808: conf->body_set = prev->body_set;
! 2809: }
! 2810:
! 2811: if (conf->body_source.data && conf->body_set_len == NULL) {
! 2812:
! 2813: ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
! 2814:
! 2815: sc.cf = cf;
! 2816: sc.source = &conf->body_source;
! 2817: sc.flushes = &conf->flushes;
! 2818: sc.lengths = &conf->body_set_len;
! 2819: sc.values = &conf->body_set;
! 2820: sc.complete_lengths = 1;
! 2821: sc.complete_values = 1;
! 2822:
! 2823: if (ngx_http_script_compile(&sc) != NGX_OK) {
! 2824: return NGX_CONF_ERROR;
! 2825: }
! 2826: }
! 2827:
! 2828: if (ngx_http_proxy_merge_headers(cf, conf, prev) != NGX_OK) {
! 2829: return NGX_CONF_ERROR;
! 2830: }
! 2831:
! 2832: return NGX_CONF_OK;
! 2833: }
! 2834:
! 2835:
! 2836: static ngx_int_t
! 2837: ngx_http_proxy_merge_headers(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf,
! 2838: ngx_http_proxy_loc_conf_t *prev)
! 2839: {
! 2840: u_char *p;
! 2841: size_t size;
! 2842: uintptr_t *code;
! 2843: ngx_uint_t i;
! 2844: ngx_array_t headers_names, headers_merged;
! 2845: ngx_keyval_t *src, *s, *h;
! 2846: ngx_hash_key_t *hk;
! 2847: ngx_hash_init_t hash;
! 2848: ngx_http_script_compile_t sc;
! 2849: ngx_http_script_copy_code_t *copy;
! 2850:
! 2851: if (conf->headers_source == NULL) {
! 2852: conf->flushes = prev->flushes;
! 2853: conf->headers_set_len = prev->headers_set_len;
! 2854: conf->headers_set = prev->headers_set;
! 2855: conf->headers_set_hash = prev->headers_set_hash;
! 2856: conf->headers_source = prev->headers_source;
! 2857: }
! 2858:
! 2859: if (conf->headers_set_hash.buckets
! 2860: #if (NGX_HTTP_CACHE)
! 2861: && ((conf->upstream.cache == NULL) == (prev->upstream.cache == NULL))
! 2862: #endif
! 2863: )
! 2864: {
! 2865: return NGX_OK;
! 2866: }
! 2867:
! 2868:
! 2869: if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
! 2870: != NGX_OK)
! 2871: {
! 2872: return NGX_ERROR;
! 2873: }
! 2874:
! 2875: if (ngx_array_init(&headers_merged, cf->temp_pool, 4, sizeof(ngx_keyval_t))
! 2876: != NGX_OK)
! 2877: {
! 2878: return NGX_ERROR;
! 2879: }
! 2880:
! 2881: if (conf->headers_source == NULL) {
! 2882: conf->headers_source = ngx_array_create(cf->pool, 4,
! 2883: sizeof(ngx_keyval_t));
! 2884: if (conf->headers_source == NULL) {
! 2885: return NGX_ERROR;
! 2886: }
! 2887: }
! 2888:
! 2889: conf->headers_set_len = ngx_array_create(cf->pool, 64, 1);
! 2890: if (conf->headers_set_len == NULL) {
! 2891: return NGX_ERROR;
! 2892: }
! 2893:
! 2894: conf->headers_set = ngx_array_create(cf->pool, 512, 1);
! 2895: if (conf->headers_set == NULL) {
! 2896: return NGX_ERROR;
! 2897: }
! 2898:
! 2899:
! 2900: #if (NGX_HTTP_CACHE)
! 2901:
! 2902: h = conf->upstream.cache ? ngx_http_proxy_cache_headers:
! 2903: ngx_http_proxy_headers;
! 2904: #else
! 2905:
! 2906: h = ngx_http_proxy_headers;
! 2907:
! 2908: #endif
! 2909:
! 2910: src = conf->headers_source->elts;
! 2911: for (i = 0; i < conf->headers_source->nelts; i++) {
! 2912:
! 2913: s = ngx_array_push(&headers_merged);
! 2914: if (s == NULL) {
! 2915: return NGX_ERROR;
! 2916: }
! 2917:
! 2918: *s = src[i];
! 2919: }
! 2920:
! 2921: while (h->key.len) {
! 2922:
! 2923: src = headers_merged.elts;
! 2924: for (i = 0; i < headers_merged.nelts; i++) {
! 2925: if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
! 2926: goto next;
! 2927: }
! 2928: }
! 2929:
! 2930: s = ngx_array_push(&headers_merged);
! 2931: if (s == NULL) {
! 2932: return NGX_ERROR;
! 2933: }
! 2934:
! 2935: *s = *h;
! 2936:
! 2937: next:
! 2938:
! 2939: h++;
! 2940: }
! 2941:
! 2942:
! 2943: src = headers_merged.elts;
! 2944: for (i = 0; i < headers_merged.nelts; i++) {
! 2945:
! 2946: hk = ngx_array_push(&headers_names);
! 2947: if (hk == NULL) {
! 2948: return NGX_ERROR;
! 2949: }
! 2950:
! 2951: hk->key = src[i].key;
! 2952: hk->key_hash = ngx_hash_key_lc(src[i].key.data, src[i].key.len);
! 2953: hk->value = (void *) 1;
! 2954:
! 2955: if (src[i].value.len == 0) {
! 2956: continue;
! 2957: }
! 2958:
! 2959: if (ngx_http_script_variables_count(&src[i].value) == 0) {
! 2960: copy = ngx_array_push_n(conf->headers_set_len,
! 2961: sizeof(ngx_http_script_copy_code_t));
! 2962: if (copy == NULL) {
! 2963: return NGX_ERROR;
! 2964: }
! 2965:
! 2966: copy->code = (ngx_http_script_code_pt)
! 2967: ngx_http_script_copy_len_code;
! 2968: copy->len = src[i].key.len + sizeof(": ") - 1
! 2969: + src[i].value.len + sizeof(CRLF) - 1;
! 2970:
! 2971:
! 2972: size = (sizeof(ngx_http_script_copy_code_t)
! 2973: + src[i].key.len + sizeof(": ") - 1
! 2974: + src[i].value.len + sizeof(CRLF) - 1
! 2975: + sizeof(uintptr_t) - 1)
! 2976: & ~(sizeof(uintptr_t) - 1);
! 2977:
! 2978: copy = ngx_array_push_n(conf->headers_set, size);
! 2979: if (copy == NULL) {
! 2980: return NGX_ERROR;
! 2981: }
! 2982:
! 2983: copy->code = ngx_http_script_copy_code;
! 2984: copy->len = src[i].key.len + sizeof(": ") - 1
! 2985: + src[i].value.len + sizeof(CRLF) - 1;
! 2986:
! 2987: p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
! 2988:
! 2989: p = ngx_cpymem(p, src[i].key.data, src[i].key.len);
! 2990: *p++ = ':'; *p++ = ' ';
! 2991: p = ngx_cpymem(p, src[i].value.data, src[i].value.len);
! 2992: *p++ = CR; *p = LF;
! 2993:
! 2994: } else {
! 2995: copy = ngx_array_push_n(conf->headers_set_len,
! 2996: sizeof(ngx_http_script_copy_code_t));
! 2997: if (copy == NULL) {
! 2998: return NGX_ERROR;
! 2999: }
! 3000:
! 3001: copy->code = (ngx_http_script_code_pt)
! 3002: ngx_http_script_copy_len_code;
! 3003: copy->len = src[i].key.len + sizeof(": ") - 1;
! 3004:
! 3005:
! 3006: size = (sizeof(ngx_http_script_copy_code_t)
! 3007: + src[i].key.len + sizeof(": ") - 1 + sizeof(uintptr_t) - 1)
! 3008: & ~(sizeof(uintptr_t) - 1);
! 3009:
! 3010: copy = ngx_array_push_n(conf->headers_set, size);
! 3011: if (copy == NULL) {
! 3012: return NGX_ERROR;
! 3013: }
! 3014:
! 3015: copy->code = ngx_http_script_copy_code;
! 3016: copy->len = src[i].key.len + sizeof(": ") - 1;
! 3017:
! 3018: p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
! 3019: p = ngx_cpymem(p, src[i].key.data, src[i].key.len);
! 3020: *p++ = ':'; *p = ' ';
! 3021:
! 3022:
! 3023: ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
! 3024:
! 3025: sc.cf = cf;
! 3026: sc.source = &src[i].value;
! 3027: sc.flushes = &conf->flushes;
! 3028: sc.lengths = &conf->headers_set_len;
! 3029: sc.values = &conf->headers_set;
! 3030:
! 3031: if (ngx_http_script_compile(&sc) != NGX_OK) {
! 3032: return NGX_ERROR;
! 3033: }
! 3034:
! 3035:
! 3036: copy = ngx_array_push_n(conf->headers_set_len,
! 3037: sizeof(ngx_http_script_copy_code_t));
! 3038: if (copy == NULL) {
! 3039: return NGX_ERROR;
! 3040: }
! 3041:
! 3042: copy->code = (ngx_http_script_code_pt)
! 3043: ngx_http_script_copy_len_code;
! 3044: copy->len = sizeof(CRLF) - 1;
! 3045:
! 3046:
! 3047: size = (sizeof(ngx_http_script_copy_code_t)
! 3048: + sizeof(CRLF) - 1 + sizeof(uintptr_t) - 1)
! 3049: & ~(sizeof(uintptr_t) - 1);
! 3050:
! 3051: copy = ngx_array_push_n(conf->headers_set, size);
! 3052: if (copy == NULL) {
! 3053: return NGX_ERROR;
! 3054: }
! 3055:
! 3056: copy->code = ngx_http_script_copy_code;
! 3057: copy->len = sizeof(CRLF) - 1;
! 3058:
! 3059: p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
! 3060: *p++ = CR; *p = LF;
! 3061: }
! 3062:
! 3063: code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t));
! 3064: if (code == NULL) {
! 3065: return NGX_ERROR;
! 3066: }
! 3067:
! 3068: *code = (uintptr_t) NULL;
! 3069:
! 3070: code = ngx_array_push_n(conf->headers_set, sizeof(uintptr_t));
! 3071: if (code == NULL) {
! 3072: return NGX_ERROR;
! 3073: }
! 3074:
! 3075: *code = (uintptr_t) NULL;
! 3076: }
! 3077:
! 3078: code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t));
! 3079: if (code == NULL) {
! 3080: return NGX_ERROR;
! 3081: }
! 3082:
! 3083: *code = (uintptr_t) NULL;
! 3084:
! 3085:
! 3086: hash.hash = &conf->headers_set_hash;
! 3087: hash.key = ngx_hash_key_lc;
! 3088: hash.max_size = conf->headers_hash_max_size;
! 3089: hash.bucket_size = conf->headers_hash_bucket_size;
! 3090: hash.name = "proxy_headers_hash";
! 3091: hash.pool = cf->pool;
! 3092: hash.temp_pool = NULL;
! 3093:
! 3094: return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts);
! 3095: }
! 3096:
! 3097:
! 3098: static char *
! 3099: ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
! 3100: {
! 3101: ngx_http_proxy_loc_conf_t *plcf = conf;
! 3102:
! 3103: size_t add;
! 3104: u_short port;
! 3105: ngx_str_t *value, *url;
! 3106: ngx_url_t u;
! 3107: ngx_uint_t n;
! 3108: ngx_http_core_loc_conf_t *clcf;
! 3109: ngx_http_script_compile_t sc;
! 3110:
! 3111: if (plcf->upstream.upstream || plcf->proxy_lengths) {
! 3112: return "is duplicate";
! 3113: }
! 3114:
! 3115: clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
! 3116:
! 3117: clcf->handler = ngx_http_proxy_handler;
! 3118:
! 3119: if (clcf->name.data[clcf->name.len - 1] == '/') {
! 3120: clcf->auto_redirect = 1;
! 3121: }
! 3122:
! 3123: value = cf->args->elts;
! 3124:
! 3125: url = &value[1];
! 3126:
! 3127: n = ngx_http_script_variables_count(url);
! 3128:
! 3129: if (n) {
! 3130:
! 3131: ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
! 3132:
! 3133: sc.cf = cf;
! 3134: sc.source = url;
! 3135: sc.lengths = &plcf->proxy_lengths;
! 3136: sc.values = &plcf->proxy_values;
! 3137: sc.variables = n;
! 3138: sc.complete_lengths = 1;
! 3139: sc.complete_values = 1;
! 3140:
! 3141: if (ngx_http_script_compile(&sc) != NGX_OK) {
! 3142: return NGX_CONF_ERROR;
! 3143: }
! 3144:
! 3145: #if (NGX_HTTP_SSL)
! 3146: if (ngx_http_proxy_set_ssl(cf, plcf) != NGX_OK) {
! 3147: return NGX_CONF_ERROR;
! 3148: }
! 3149: #endif
! 3150:
! 3151: return NGX_CONF_OK;
! 3152: }
! 3153:
! 3154: if (ngx_strncasecmp(url->data, (u_char *) "http://", 7) == 0) {
! 3155: add = 7;
! 3156: port = 80;
! 3157:
! 3158: } else if (ngx_strncasecmp(url->data, (u_char *) "https://", 8) == 0) {
! 3159:
! 3160: #if (NGX_HTTP_SSL)
! 3161: if (ngx_http_proxy_set_ssl(cf, plcf) != NGX_OK) {
! 3162: return NGX_CONF_ERROR;
! 3163: }
! 3164:
! 3165: add = 8;
! 3166: port = 443;
! 3167: #else
! 3168: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 3169: "https protocol requires SSL support");
! 3170: return NGX_CONF_ERROR;
! 3171: #endif
! 3172:
! 3173: } else {
! 3174: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid URL prefix");
! 3175: return NGX_CONF_ERROR;
! 3176: }
! 3177:
! 3178: ngx_memzero(&u, sizeof(ngx_url_t));
! 3179:
! 3180: u.url.len = url->len - add;
! 3181: u.url.data = url->data + add;
! 3182: u.default_port = port;
! 3183: u.uri_part = 1;
! 3184: u.no_resolve = 1;
! 3185:
! 3186: plcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
! 3187: if (plcf->upstream.upstream == NULL) {
! 3188: return NGX_CONF_ERROR;
! 3189: }
! 3190:
! 3191: plcf->vars.schema.len = add;
! 3192: plcf->vars.schema.data = url->data;
! 3193: plcf->vars.key_start = plcf->vars.schema;
! 3194:
! 3195: ngx_http_proxy_set_vars(&u, &plcf->vars);
! 3196:
! 3197: plcf->location = clcf->name;
! 3198:
! 3199: if (clcf->named
! 3200: #if (NGX_PCRE)
! 3201: || clcf->regex
! 3202: #endif
! 3203: || clcf->noname)
! 3204: {
! 3205: if (plcf->vars.uri.len) {
! 3206: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 3207: "\"proxy_pass\" cannot have URI part in "
! 3208: "location given by regular expression, "
! 3209: "or inside named location, "
! 3210: "or inside \"if\" statement, "
! 3211: "or inside \"limit_except\" block");
! 3212: return NGX_CONF_ERROR;
! 3213: }
! 3214:
! 3215: plcf->location.len = 0;
! 3216: }
! 3217:
! 3218: plcf->url = *url;
! 3219:
! 3220: return NGX_CONF_OK;
! 3221: }
! 3222:
! 3223:
! 3224: static char *
! 3225: ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
! 3226: {
! 3227: ngx_http_proxy_loc_conf_t *plcf = conf;
! 3228:
! 3229: u_char *p;
! 3230: ngx_str_t *value;
! 3231: ngx_http_proxy_rewrite_t *pr;
! 3232: ngx_http_compile_complex_value_t ccv;
! 3233:
! 3234: if (plcf->redirect == 0) {
! 3235: return NGX_CONF_OK;
! 3236: }
! 3237:
! 3238: plcf->redirect = 1;
! 3239:
! 3240: value = cf->args->elts;
! 3241:
! 3242: if (cf->args->nelts == 2) {
! 3243: if (ngx_strcmp(value[1].data, "off") == 0) {
! 3244: plcf->redirect = 0;
! 3245: plcf->redirects = NULL;
! 3246: return NGX_CONF_OK;
! 3247: }
! 3248:
! 3249: if (ngx_strcmp(value[1].data, "false") == 0) {
! 3250: ngx_conf_log_error(NGX_LOG_ERR, cf, 0,
! 3251: "invalid parameter \"false\", use \"off\" instead");
! 3252: plcf->redirect = 0;
! 3253: plcf->redirects = NULL;
! 3254: return NGX_CONF_OK;
! 3255: }
! 3256:
! 3257: if (ngx_strcmp(value[1].data, "default") != 0) {
! 3258: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 3259: "invalid parameter \"%V\"", &value[1]);
! 3260: return NGX_CONF_ERROR;
! 3261: }
! 3262: }
! 3263:
! 3264: if (plcf->redirects == NULL) {
! 3265: plcf->redirects = ngx_array_create(cf->pool, 1,
! 3266: sizeof(ngx_http_proxy_rewrite_t));
! 3267: if (plcf->redirects == NULL) {
! 3268: return NGX_CONF_ERROR;
! 3269: }
! 3270: }
! 3271:
! 3272: pr = ngx_array_push(plcf->redirects);
! 3273: if (pr == NULL) {
! 3274: return NGX_CONF_ERROR;
! 3275: }
! 3276:
! 3277: if (ngx_strcmp(value[1].data, "default") == 0) {
! 3278: if (plcf->proxy_lengths) {
! 3279: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 3280: "\"proxy_redirect default\" cannot be used "
! 3281: "with \"proxy_pass\" directive with variables");
! 3282: return NGX_CONF_ERROR;
! 3283: }
! 3284:
! 3285: if (plcf->url.data == NULL) {
! 3286: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 3287: "\"proxy_redirect default\" should be placed "
! 3288: "after the \"proxy_pass\" directive");
! 3289: return NGX_CONF_ERROR;
! 3290: }
! 3291:
! 3292: pr->handler = ngx_http_proxy_rewrite_complex_handler;
! 3293:
! 3294: ngx_memzero(&pr->pattern.complex, sizeof(ngx_http_complex_value_t));
! 3295:
! 3296: ngx_memzero(&pr->replacement, sizeof(ngx_http_complex_value_t));
! 3297:
! 3298: if (plcf->vars.uri.len) {
! 3299: pr->pattern.complex.value = plcf->url;
! 3300: pr->replacement.value = plcf->location;
! 3301:
! 3302: } else {
! 3303: pr->pattern.complex.value.len = plcf->url.len + sizeof("/") - 1;
! 3304:
! 3305: p = ngx_pnalloc(cf->pool, pr->pattern.complex.value.len);
! 3306: if (p == NULL) {
! 3307: return NGX_CONF_ERROR;
! 3308: }
! 3309:
! 3310: pr->pattern.complex.value.data = p;
! 3311:
! 3312: p = ngx_cpymem(p, plcf->url.data, plcf->url.len);
! 3313: *p = '/';
! 3314:
! 3315: ngx_str_set(&pr->replacement.value, "/");
! 3316: }
! 3317:
! 3318: return NGX_CONF_OK;
! 3319: }
! 3320:
! 3321:
! 3322: if (value[1].data[0] == '~') {
! 3323: value[1].len--;
! 3324: value[1].data++;
! 3325:
! 3326: if (value[1].data[0] == '*') {
! 3327: value[1].len--;
! 3328: value[1].data++;
! 3329:
! 3330: if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) {
! 3331: return NGX_CONF_ERROR;
! 3332: }
! 3333:
! 3334: } else {
! 3335: if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 0) != NGX_OK) {
! 3336: return NGX_CONF_ERROR;
! 3337: }
! 3338: }
! 3339:
! 3340: } else {
! 3341:
! 3342: ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
! 3343:
! 3344: ccv.cf = cf;
! 3345: ccv.value = &value[1];
! 3346: ccv.complex_value = &pr->pattern.complex;
! 3347:
! 3348: if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
! 3349: return NGX_CONF_ERROR;
! 3350: }
! 3351:
! 3352: pr->handler = ngx_http_proxy_rewrite_complex_handler;
! 3353: }
! 3354:
! 3355:
! 3356: ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
! 3357:
! 3358: ccv.cf = cf;
! 3359: ccv.value = &value[2];
! 3360: ccv.complex_value = &pr->replacement;
! 3361:
! 3362: if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
! 3363: return NGX_CONF_ERROR;
! 3364: }
! 3365:
! 3366: return NGX_CONF_OK;
! 3367: }
! 3368:
! 3369:
! 3370: static char *
! 3371: ngx_http_proxy_cookie_domain(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
! 3372: {
! 3373: ngx_http_proxy_loc_conf_t *plcf = conf;
! 3374:
! 3375: ngx_str_t *value;
! 3376: ngx_http_proxy_rewrite_t *pr;
! 3377: ngx_http_compile_complex_value_t ccv;
! 3378:
! 3379: if (plcf->cookie_domains == NULL) {
! 3380: return NGX_CONF_OK;
! 3381: }
! 3382:
! 3383: value = cf->args->elts;
! 3384:
! 3385: if (cf->args->nelts == 2) {
! 3386:
! 3387: if (ngx_strcmp(value[1].data, "off") == 0) {
! 3388: plcf->cookie_domains = NULL;
! 3389: return NGX_CONF_OK;
! 3390: }
! 3391:
! 3392: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 3393: "invalid parameter \"%V\"", &value[1]);
! 3394: return NGX_CONF_ERROR;
! 3395: }
! 3396:
! 3397: if (plcf->cookie_domains == NGX_CONF_UNSET_PTR) {
! 3398: plcf->cookie_domains = ngx_array_create(cf->pool, 1,
! 3399: sizeof(ngx_http_proxy_rewrite_t));
! 3400: if (plcf->cookie_domains == NULL) {
! 3401: return NGX_CONF_ERROR;
! 3402: }
! 3403: }
! 3404:
! 3405: pr = ngx_array_push(plcf->cookie_domains);
! 3406: if (pr == NULL) {
! 3407: return NGX_CONF_ERROR;
! 3408: }
! 3409:
! 3410: if (value[1].data[0] == '~') {
! 3411: value[1].len--;
! 3412: value[1].data++;
! 3413:
! 3414: if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) {
! 3415: return NGX_CONF_ERROR;
! 3416: }
! 3417:
! 3418: } else {
! 3419:
! 3420: if (value[1].data[0] == '.') {
! 3421: value[1].len--;
! 3422: value[1].data++;
! 3423: }
! 3424:
! 3425: ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
! 3426:
! 3427: ccv.cf = cf;
! 3428: ccv.value = &value[1];
! 3429: ccv.complex_value = &pr->pattern.complex;
! 3430:
! 3431: if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
! 3432: return NGX_CONF_ERROR;
! 3433: }
! 3434:
! 3435: pr->handler = ngx_http_proxy_rewrite_domain_handler;
! 3436:
! 3437: if (value[2].data[0] == '.') {
! 3438: value[2].len--;
! 3439: value[2].data++;
! 3440: }
! 3441: }
! 3442:
! 3443: ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
! 3444:
! 3445: ccv.cf = cf;
! 3446: ccv.value = &value[2];
! 3447: ccv.complex_value = &pr->replacement;
! 3448:
! 3449: if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
! 3450: return NGX_CONF_ERROR;
! 3451: }
! 3452:
! 3453: return NGX_CONF_OK;
! 3454: }
! 3455:
! 3456:
! 3457: static char *
! 3458: ngx_http_proxy_cookie_path(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
! 3459: {
! 3460: ngx_http_proxy_loc_conf_t *plcf = conf;
! 3461:
! 3462: ngx_str_t *value;
! 3463: ngx_http_proxy_rewrite_t *pr;
! 3464: ngx_http_compile_complex_value_t ccv;
! 3465:
! 3466: if (plcf->cookie_paths == NULL) {
! 3467: return NGX_CONF_OK;
! 3468: }
! 3469:
! 3470: value = cf->args->elts;
! 3471:
! 3472: if (cf->args->nelts == 2) {
! 3473:
! 3474: if (ngx_strcmp(value[1].data, "off") == 0) {
! 3475: plcf->cookie_paths = NULL;
! 3476: return NGX_CONF_OK;
! 3477: }
! 3478:
! 3479: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 3480: "invalid parameter \"%V\"", &value[1]);
! 3481: return NGX_CONF_ERROR;
! 3482: }
! 3483:
! 3484: if (plcf->cookie_paths == NGX_CONF_UNSET_PTR) {
! 3485: plcf->cookie_paths = ngx_array_create(cf->pool, 1,
! 3486: sizeof(ngx_http_proxy_rewrite_t));
! 3487: if (plcf->cookie_paths == NULL) {
! 3488: return NGX_CONF_ERROR;
! 3489: }
! 3490: }
! 3491:
! 3492: pr = ngx_array_push(plcf->cookie_paths);
! 3493: if (pr == NULL) {
! 3494: return NGX_CONF_ERROR;
! 3495: }
! 3496:
! 3497: if (value[1].data[0] == '~') {
! 3498: value[1].len--;
! 3499: value[1].data++;
! 3500:
! 3501: if (value[1].data[0] == '*') {
! 3502: value[1].len--;
! 3503: value[1].data++;
! 3504:
! 3505: if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) {
! 3506: return NGX_CONF_ERROR;
! 3507: }
! 3508:
! 3509: } else {
! 3510: if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 0) != NGX_OK) {
! 3511: return NGX_CONF_ERROR;
! 3512: }
! 3513: }
! 3514:
! 3515: } else {
! 3516:
! 3517: ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
! 3518:
! 3519: ccv.cf = cf;
! 3520: ccv.value = &value[1];
! 3521: ccv.complex_value = &pr->pattern.complex;
! 3522:
! 3523: if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
! 3524: return NGX_CONF_ERROR;
! 3525: }
! 3526:
! 3527: pr->handler = ngx_http_proxy_rewrite_complex_handler;
! 3528: }
! 3529:
! 3530: ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
! 3531:
! 3532: ccv.cf = cf;
! 3533: ccv.value = &value[2];
! 3534: ccv.complex_value = &pr->replacement;
! 3535:
! 3536: if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
! 3537: return NGX_CONF_ERROR;
! 3538: }
! 3539:
! 3540: return NGX_CONF_OK;
! 3541: }
! 3542:
! 3543:
! 3544: static ngx_int_t
! 3545: ngx_http_proxy_rewrite_regex(ngx_conf_t *cf, ngx_http_proxy_rewrite_t *pr,
! 3546: ngx_str_t *regex, ngx_uint_t caseless)
! 3547: {
! 3548: #if (NGX_PCRE)
! 3549: u_char errstr[NGX_MAX_CONF_ERRSTR];
! 3550: ngx_regex_compile_t rc;
! 3551:
! 3552: ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
! 3553:
! 3554: rc.pattern = *regex;
! 3555: rc.err.len = NGX_MAX_CONF_ERRSTR;
! 3556: rc.err.data = errstr;
! 3557:
! 3558: if (caseless) {
! 3559: rc.options = NGX_REGEX_CASELESS;
! 3560: }
! 3561:
! 3562: pr->pattern.regex = ngx_http_regex_compile(cf, &rc);
! 3563: if (pr->pattern.regex == NULL) {
! 3564: return NGX_ERROR;
! 3565: }
! 3566:
! 3567: pr->handler = ngx_http_proxy_rewrite_regex_handler;
! 3568:
! 3569: return NGX_OK;
! 3570:
! 3571: #else
! 3572:
! 3573: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 3574: "using regex \"%V\" requires PCRE library", regex);
! 3575: return NGX_ERROR;
! 3576:
! 3577: #endif
! 3578: }
! 3579:
! 3580:
! 3581: static char *
! 3582: ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
! 3583: {
! 3584: ngx_http_proxy_loc_conf_t *plcf = conf;
! 3585:
! 3586: ngx_str_t *value;
! 3587: ngx_http_script_compile_t sc;
! 3588:
! 3589: if (plcf->upstream.store != NGX_CONF_UNSET
! 3590: || plcf->upstream.store_lengths)
! 3591: {
! 3592: return "is duplicate";
! 3593: }
! 3594:
! 3595: value = cf->args->elts;
! 3596:
! 3597: if (ngx_strcmp(value[1].data, "off") == 0) {
! 3598: plcf->upstream.store = 0;
! 3599: return NGX_CONF_OK;
! 3600: }
! 3601:
! 3602: #if (NGX_HTTP_CACHE)
! 3603:
! 3604: if (plcf->upstream.cache != NGX_CONF_UNSET_PTR
! 3605: && plcf->upstream.cache != NULL)
! 3606: {
! 3607: return "is incompatible with \"proxy_cache\"";
! 3608: }
! 3609:
! 3610: #endif
! 3611:
! 3612: if (ngx_strcmp(value[1].data, "on") == 0) {
! 3613: plcf->upstream.store = 1;
! 3614: return NGX_CONF_OK;
! 3615: }
! 3616:
! 3617: /* include the terminating '\0' into script */
! 3618: value[1].len++;
! 3619:
! 3620: ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
! 3621:
! 3622: sc.cf = cf;
! 3623: sc.source = &value[1];
! 3624: sc.lengths = &plcf->upstream.store_lengths;
! 3625: sc.values = &plcf->upstream.store_values;
! 3626: sc.variables = ngx_http_script_variables_count(&value[1]);
! 3627: sc.complete_lengths = 1;
! 3628: sc.complete_values = 1;
! 3629:
! 3630: if (ngx_http_script_compile(&sc) != NGX_OK) {
! 3631: return NGX_CONF_ERROR;
! 3632: }
! 3633:
! 3634: return NGX_CONF_OK;
! 3635: }
! 3636:
! 3637:
! 3638: #if (NGX_HTTP_CACHE)
! 3639:
! 3640: static char *
! 3641: ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
! 3642: {
! 3643: ngx_http_proxy_loc_conf_t *plcf = conf;
! 3644:
! 3645: ngx_str_t *value;
! 3646:
! 3647: value = cf->args->elts;
! 3648:
! 3649: if (plcf->upstream.cache != NGX_CONF_UNSET_PTR) {
! 3650: return "is duplicate";
! 3651: }
! 3652:
! 3653: if (ngx_strcmp(value[1].data, "off") == 0) {
! 3654: plcf->upstream.cache = NULL;
! 3655: return NGX_CONF_OK;
! 3656: }
! 3657:
! 3658: if (plcf->upstream.store > 0 || plcf->upstream.store_lengths) {
! 3659: return "is incompatible with \"proxy_store\"";
! 3660: }
! 3661:
! 3662: plcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0,
! 3663: &ngx_http_proxy_module);
! 3664: if (plcf->upstream.cache == NULL) {
! 3665: return NGX_CONF_ERROR;
! 3666: }
! 3667:
! 3668: return NGX_CONF_OK;
! 3669: }
! 3670:
! 3671:
! 3672: static char *
! 3673: ngx_http_proxy_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
! 3674: {
! 3675: ngx_http_proxy_loc_conf_t *plcf = conf;
! 3676:
! 3677: ngx_str_t *value;
! 3678: ngx_http_compile_complex_value_t ccv;
! 3679:
! 3680: value = cf->args->elts;
! 3681:
! 3682: if (plcf->cache_key.value.data) {
! 3683: return "is duplicate";
! 3684: }
! 3685:
! 3686: ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
! 3687:
! 3688: ccv.cf = cf;
! 3689: ccv.value = &value[1];
! 3690: ccv.complex_value = &plcf->cache_key;
! 3691:
! 3692: if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
! 3693: return NGX_CONF_ERROR;
! 3694: }
! 3695:
! 3696: return NGX_CONF_OK;
! 3697: }
! 3698:
! 3699: #endif
! 3700:
! 3701:
! 3702: static char *
! 3703: ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data)
! 3704: {
! 3705: #if (NGX_FREEBSD)
! 3706: ssize_t *np = data;
! 3707:
! 3708: if ((u_long) *np >= ngx_freebsd_net_inet_tcp_sendspace) {
! 3709: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 3710: "\"proxy_send_lowat\" must be less than %d "
! 3711: "(sysctl net.inet.tcp.sendspace)",
! 3712: ngx_freebsd_net_inet_tcp_sendspace);
! 3713:
! 3714: return NGX_CONF_ERROR;
! 3715: }
! 3716:
! 3717: #elif !(NGX_HAVE_SO_SNDLOWAT)
! 3718: ssize_t *np = data;
! 3719:
! 3720: ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
! 3721: "\"proxy_send_lowat\" is not supported, ignored");
! 3722:
! 3723: *np = 0;
! 3724:
! 3725: #endif
! 3726:
! 3727: return NGX_CONF_OK;
! 3728: }
! 3729:
! 3730:
! 3731: #if (NGX_HTTP_SSL)
! 3732:
! 3733: static ngx_int_t
! 3734: ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf)
! 3735: {
! 3736: ngx_pool_cleanup_t *cln;
! 3737:
! 3738: plcf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t));
! 3739: if (plcf->upstream.ssl == NULL) {
! 3740: return NGX_ERROR;
! 3741: }
! 3742:
! 3743: plcf->upstream.ssl->log = cf->log;
! 3744:
! 3745: if (ngx_ssl_create(plcf->upstream.ssl,
! 3746: NGX_SSL_SSLv2|NGX_SSL_SSLv3|NGX_SSL_TLSv1
! 3747: |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2,
! 3748: NULL)
! 3749: != NGX_OK)
! 3750: {
! 3751: return NGX_ERROR;
! 3752: }
! 3753:
! 3754: cln = ngx_pool_cleanup_add(cf->pool, 0);
! 3755: if (cln == NULL) {
! 3756: return NGX_ERROR;
! 3757: }
! 3758:
! 3759: cln->handler = ngx_ssl_cleanup_ctx;
! 3760: cln->data = plcf->upstream.ssl;
! 3761:
! 3762: return NGX_OK;
! 3763: }
! 3764:
! 3765: #endif
! 3766:
! 3767:
! 3768: static void
! 3769: ngx_http_proxy_set_vars(ngx_url_t *u, ngx_http_proxy_vars_t *v)
! 3770: {
! 3771: if (u->family != AF_UNIX) {
! 3772:
! 3773: if (u->no_port || u->port == u->default_port) {
! 3774:
! 3775: v->host_header = u->host;
! 3776:
! 3777: if (u->default_port == 80) {
! 3778: ngx_str_set(&v->port, "80");
! 3779:
! 3780: } else {
! 3781: ngx_str_set(&v->port, "443");
! 3782: }
! 3783:
! 3784: } else {
! 3785: v->host_header.len = u->host.len + 1 + u->port_text.len;
! 3786: v->host_header.data = u->host.data;
! 3787: v->port = u->port_text;
! 3788: }
! 3789:
! 3790: v->key_start.len += v->host_header.len;
! 3791:
! 3792: } else {
! 3793: ngx_str_set(&v->host_header, "localhost");
! 3794: ngx_str_null(&v->port);
! 3795: v->key_start.len += sizeof("unix:") - 1 + u->host.len + 1;
! 3796: }
! 3797:
! 3798: v->uri = u->uri;
! 3799: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>