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 #define NGX_HTTP_PROXY_COOKIE_SECURE 0x0001 14 #define NGX_HTTP_PROXY_COOKIE_SECURE_ON 0x0002 15 #define NGX_HTTP_PROXY_COOKIE_SECURE_OFF 0x0004 16 #define NGX_HTTP_PROXY_COOKIE_HTTPONLY 0x0008 17 #define NGX_HTTP_PROXY_COOKIE_HTTPONLY_ON 0x0010 18 #define NGX_HTTP_PROXY_COOKIE_HTTPONLY_OFF 0x0020 19 #define NGX_HTTP_PROXY_COOKIE_SAMESITE 0x0040 20 #define NGX_HTTP_PROXY_COOKIE_SAMESITE_STRICT 0x0080 21 #define NGX_HTTP_PROXY_COOKIE_SAMESITE_LAX 0x0100 22 #define NGX_HTTP_PROXY_COOKIE_SAMESITE_NONE 0x0200 23 #define NGX_HTTP_PROXY_COOKIE_SAMESITE_OFF 0x0400 24 25 26 typedef struct { 27 ngx_array_t caches; /* ngx_http_file_cache_t * */ 28 } ngx_http_proxy_main_conf_t; 29 30 31 typedef struct ngx_http_proxy_rewrite_s ngx_http_proxy_rewrite_t; 32 33 typedef ngx_int_t (*ngx_http_proxy_rewrite_pt)(ngx_http_request_t *r, 34 ngx_str_t *value, size_t prefix, size_t len, 35 ngx_http_proxy_rewrite_t *pr); 36 37 struct ngx_http_proxy_rewrite_s { 38 ngx_http_proxy_rewrite_pt handler; 39 40 union { 41 ngx_http_complex_value_t complex; 42 #if (NGX_PCRE) 43 ngx_http_regex_t *regex; 44 #endif 45 } pattern; 46 47 ngx_http_complex_value_t replacement; 48 }; 49 50 51 typedef struct { 52 union { 53 ngx_http_complex_value_t complex; 54 #if (NGX_PCRE) 55 ngx_http_regex_t *regex; 56 #endif 57 } cookie; 58 59 ngx_array_t flags_values; 60 ngx_uint_t regex; 61 } ngx_http_proxy_cookie_flags_t; 62 63 64 typedef struct { 65 ngx_str_t key_start; 66 ngx_str_t schema; 67 ngx_str_t host_header; 68 ngx_str_t port; 69 ngx_str_t uri; 70 } ngx_http_proxy_vars_t; 71 72 73 typedef struct { 74 ngx_array_t *flushes; 75 ngx_array_t *lengths; 76 ngx_array_t *values; 77 ngx_hash_t hash; 78 } ngx_http_proxy_headers_t; 79 80 81 typedef struct { 82 ngx_http_upstream_conf_t upstream; 83 84 ngx_array_t *body_flushes; 85 ngx_array_t *body_lengths; 86 ngx_array_t *body_values; 87 ngx_str_t body_source; 88 89 ngx_http_proxy_headers_t headers; 90 #if (NGX_HTTP_CACHE) 91 ngx_http_proxy_headers_t headers_cache; 92 #endif 93 ngx_array_t *headers_source; 94 95 ngx_array_t *proxy_lengths; 96 ngx_array_t *proxy_values; 97 98 ngx_array_t *redirects; 99 ngx_array_t *cookie_domains; 100 ngx_array_t *cookie_paths; 101 ngx_array_t *cookie_flags; 102 103 ngx_http_complex_value_t *method; 104 ngx_str_t location; 105 ngx_str_t url; 106 107 #if (NGX_HTTP_CACHE) 108 ngx_http_complex_value_t cache_key; 109 #endif 110 111 ngx_http_proxy_vars_t vars; 112 113 ngx_flag_t redirect; 114 115 ngx_uint_t http_version; 116 117 ngx_uint_t headers_hash_max_size; 118 ngx_uint_t headers_hash_bucket_size; 119 120 #if (NGX_HTTP_SSL) 121 ngx_uint_t ssl; 122 ngx_uint_t ssl_protocols; 123 ngx_str_t ssl_ciphers; 124 ngx_uint_t ssl_verify_depth; 125 ngx_str_t ssl_trusted_certificate; 126 ngx_str_t ssl_crl; 127 ngx_array_t *ssl_conf_commands; 128 #endif 129 } ngx_http_proxy_loc_conf_t; 130 131 132 typedef struct { 133 ngx_http_status_t status; 134 ngx_http_chunked_t chunked; 135 ngx_http_proxy_vars_t vars; 136 off_t internal_body_length; 137 138 ngx_chain_t *free; 139 ngx_chain_t *busy; 140 141 unsigned head:1; 142 unsigned internal_chunked:1; 143 unsigned header_sent:1; 144 } ngx_http_proxy_ctx_t; 145 146 147 static ngx_int_t ngx_http_proxy_eval(ngx_http_request_t *r, 148 ngx_http_proxy_ctx_t *ctx, ngx_http_proxy_loc_conf_t *plcf); 149 #if (NGX_HTTP_CACHE) 150 static ngx_int_t ngx_http_proxy_create_key(ngx_http_request_t *r); 151 #endif 152 static ngx_int_t ngx_http_proxy_create_request(ngx_http_request_t *r); 153 static ngx_int_t ngx_http_proxy_reinit_request(ngx_http_request_t *r); 154 static ngx_int_t ngx_http_proxy_body_output_filter(void *data, ngx_chain_t *in); 155 static ngx_int_t ngx_http_proxy_process_status_line(ngx_http_request_t *r); 156 static ngx_int_t ngx_http_proxy_process_header(ngx_http_request_t *r); 157 static ngx_int_t ngx_http_proxy_input_filter_init(void *data); 158 static ngx_int_t ngx_http_proxy_copy_filter(ngx_event_pipe_t *p, 159 ngx_buf_t *buf); 160 static ngx_int_t ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, 161 ngx_buf_t *buf); 162 static ngx_int_t ngx_http_proxy_non_buffered_copy_filter(void *data, 163 ssize_t bytes); 164 static ngx_int_t ngx_http_proxy_non_buffered_chunked_filter(void *data, 165 ssize_t bytes); 166 static void ngx_http_proxy_abort_request(ngx_http_request_t *r); 167 static void ngx_http_proxy_finalize_request(ngx_http_request_t *r, 168 ngx_int_t rc); 169 170 static ngx_int_t ngx_http_proxy_host_variable(ngx_http_request_t *r, 171 ngx_http_variable_value_t *v, uintptr_t data); 172 static ngx_int_t ngx_http_proxy_port_variable(ngx_http_request_t *r, 173 ngx_http_variable_value_t *v, uintptr_t data); 174 static ngx_int_t 175 ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r, 176 ngx_http_variable_value_t *v, uintptr_t data); 177 static ngx_int_t 178 ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r, 179 ngx_http_variable_value_t *v, uintptr_t data); 180 static ngx_int_t ngx_http_proxy_internal_chunked_variable(ngx_http_request_t *r, 181 ngx_http_variable_value_t *v, uintptr_t data); 182 static ngx_int_t ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, 183 ngx_table_elt_t *h, size_t prefix); 184 static ngx_int_t ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r, 185 ngx_table_elt_t *h); 186 static ngx_int_t ngx_http_proxy_parse_cookie(ngx_str_t *value, 187 ngx_array_t *attrs); 188 static ngx_int_t ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r, 189 ngx_str_t *value, ngx_array_t *rewrites); 190 static ngx_int_t ngx_http_proxy_rewrite_cookie_flags(ngx_http_request_t *r, 191 ngx_array_t *attrs, ngx_array_t *flags); 192 static ngx_int_t ngx_http_proxy_edit_cookie_flags(ngx_http_request_t *r, 193 ngx_array_t *attrs, ngx_uint_t flags); 194 static ngx_int_t ngx_http_proxy_rewrite(ngx_http_request_t *r, 195 ngx_str_t *value, size_t prefix, size_t len, ngx_str_t *replacement); 196 197 static ngx_int_t ngx_http_proxy_add_variables(ngx_conf_t *cf); 198 static void *ngx_http_proxy_create_main_conf(ngx_conf_t *cf); 199 static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf); 200 static char *ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, 201 void *parent, void *child); 202 static ngx_int_t ngx_http_proxy_init_headers(ngx_conf_t *cf, 203 ngx_http_proxy_loc_conf_t *conf, ngx_http_proxy_headers_t *headers, 204 ngx_keyval_t *default_headers); 205 206 static char *ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, 207 void *conf); 208 static char *ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, 209 void *conf); 210 static char *ngx_http_proxy_cookie_domain(ngx_conf_t *cf, ngx_command_t *cmd, 211 void *conf); 212 static char *ngx_http_proxy_cookie_path(ngx_conf_t *cf, ngx_command_t *cmd, 213 void *conf); 214 static char *ngx_http_proxy_cookie_flags(ngx_conf_t *cf, ngx_command_t *cmd, 215 void *conf); 216 static char *ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd, 217 void *conf); 218 #if (NGX_HTTP_CACHE) 219 static char *ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd, 220 void *conf); 221 static char *ngx_http_proxy_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, 222 void *conf); 223 #endif 224 #if (NGX_HTTP_SSL) 225 static char *ngx_http_proxy_ssl_password_file(ngx_conf_t *cf, 226 ngx_command_t *cmd, void *conf); 227 #endif 228 229 static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data); 230 #if (NGX_HTTP_SSL) 231 static char *ngx_http_proxy_ssl_conf_command_check(ngx_conf_t *cf, void *post, 232 void *data); 233 #endif 234 235 static ngx_int_t ngx_http_proxy_rewrite_regex(ngx_conf_t *cf, 236 ngx_http_proxy_rewrite_t *pr, ngx_str_t *regex, ngx_uint_t caseless); 237 238 #if (NGX_HTTP_SSL) 239 static ngx_int_t ngx_http_proxy_set_ssl(ngx_conf_t *cf, 240 ngx_http_proxy_loc_conf_t *plcf); 241 #endif 242 static void ngx_http_proxy_set_vars(ngx_url_t *u, ngx_http_proxy_vars_t *v); 243 244 245 static ngx_conf_post_t ngx_http_proxy_lowat_post = 246 { ngx_http_proxy_lowat_check }; 247 248 249 static ngx_conf_bitmask_t ngx_http_proxy_next_upstream_masks[] = { 250 { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR }, 251 { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT }, 252 { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER }, 253 { ngx_string("non_idempotent"), NGX_HTTP_UPSTREAM_FT_NON_IDEMPOTENT }, 254 { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 }, 255 { ngx_string("http_502"), NGX_HTTP_UPSTREAM_FT_HTTP_502 }, 256 { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 }, 257 { ngx_string("http_504"), NGX_HTTP_UPSTREAM_FT_HTTP_504 }, 258 { ngx_string("http_403"), NGX_HTTP_UPSTREAM_FT_HTTP_403 }, 259 { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 }, 260 { ngx_string("http_429"), NGX_HTTP_UPSTREAM_FT_HTTP_429 }, 261 { ngx_string("updating"), NGX_HTTP_UPSTREAM_FT_UPDATING }, 262 { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF }, 263 { ngx_null_string, 0 } 264 }; 265 266 267 #if (NGX_HTTP_SSL) 268 269 static ngx_conf_bitmask_t ngx_http_proxy_ssl_protocols[] = { 270 { ngx_string("SSLv2"), NGX_SSL_SSLv2 }, 271 { ngx_string("SSLv3"), NGX_SSL_SSLv3 }, 272 { ngx_string("TLSv1"), NGX_SSL_TLSv1 }, 273 { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 }, 274 { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 }, 275 { ngx_string("TLSv1.3"), NGX_SSL_TLSv1_3 }, 276 { ngx_null_string, 0 } 277 }; 278 279 static ngx_conf_post_t ngx_http_proxy_ssl_conf_command_post = 280 { ngx_http_proxy_ssl_conf_command_check }; 281 282 #endif 283 284 285 static ngx_conf_enum_t ngx_http_proxy_http_version[] = { 286 { ngx_string("1.0"), NGX_HTTP_VERSION_10 }, 287 { ngx_string("1.1"), NGX_HTTP_VERSION_11 }, 288 { ngx_null_string, 0 } 289 }; 290 291 292 ngx_module_t ngx_http_proxy_module; 293 294 295 static ngx_command_t ngx_http_proxy_commands[] = { 296 297 { ngx_string("proxy_pass"), 298 NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_HTTP_LMT_CONF|NGX_CONF_TAKE1, 299 ngx_http_proxy_pass, 300 NGX_HTTP_LOC_CONF_OFFSET, 301 0, 302 NULL }, 303 304 { ngx_string("proxy_redirect"), 305 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12, 306 ngx_http_proxy_redirect, 307 NGX_HTTP_LOC_CONF_OFFSET, 308 0, 309 NULL }, 310 311 { ngx_string("proxy_cookie_domain"), 312 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12, 313 ngx_http_proxy_cookie_domain, 314 NGX_HTTP_LOC_CONF_OFFSET, 315 0, 316 NULL }, 317 318 { ngx_string("proxy_cookie_path"), 319 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12, 320 ngx_http_proxy_cookie_path, 321 NGX_HTTP_LOC_CONF_OFFSET, 322 0, 323 NULL }, 324 325 { ngx_string("proxy_cookie_flags"), 326 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234, 327 ngx_http_proxy_cookie_flags, 328 NGX_HTTP_LOC_CONF_OFFSET, 329 0, 330 NULL }, 331 332 { ngx_string("proxy_store"), 333 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 334 ngx_http_proxy_store, 335 NGX_HTTP_LOC_CONF_OFFSET, 336 0, 337 NULL }, 338 339 { ngx_string("proxy_store_access"), 340 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123, 341 ngx_conf_set_access_slot, 342 NGX_HTTP_LOC_CONF_OFFSET, 343 offsetof(ngx_http_proxy_loc_conf_t, upstream.store_access), 344 NULL }, 345 346 { ngx_string("proxy_buffering"), 347 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, 348 ngx_conf_set_flag_slot, 349 NGX_HTTP_LOC_CONF_OFFSET, 350 offsetof(ngx_http_proxy_loc_conf_t, upstream.buffering), 351 NULL }, 352 353 { ngx_string("proxy_request_buffering"), 354 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, 355 ngx_conf_set_flag_slot, 356 NGX_HTTP_LOC_CONF_OFFSET, 357 offsetof(ngx_http_proxy_loc_conf_t, upstream.request_buffering), 358 NULL }, 359 360 { ngx_string("proxy_ignore_client_abort"), 361 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, 362 ngx_conf_set_flag_slot, 363 NGX_HTTP_LOC_CONF_OFFSET, 364 offsetof(ngx_http_proxy_loc_conf_t, upstream.ignore_client_abort), 365 NULL }, 366 367 { ngx_string("proxy_bind"), 368 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12, 369 ngx_http_upstream_bind_set_slot, 370 NGX_HTTP_LOC_CONF_OFFSET, 371 offsetof(ngx_http_proxy_loc_conf_t, upstream.local), 372 NULL }, 373 374 { ngx_string("proxy_socket_keepalive"), 375 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, 376 ngx_conf_set_flag_slot, 377 NGX_HTTP_LOC_CONF_OFFSET, 378 offsetof(ngx_http_proxy_loc_conf_t, upstream.socket_keepalive), 379 NULL }, 380 381 { ngx_string("proxy_connect_timeout"), 382 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 383 ngx_conf_set_msec_slot, 384 NGX_HTTP_LOC_CONF_OFFSET, 385 offsetof(ngx_http_proxy_loc_conf_t, upstream.connect_timeout), 386 NULL }, 387 388 { ngx_string("proxy_send_timeout"), 389 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 390 ngx_conf_set_msec_slot, 391 NGX_HTTP_LOC_CONF_OFFSET, 392 offsetof(ngx_http_proxy_loc_conf_t, upstream.send_timeout), 393 NULL }, 394 395 { ngx_string("proxy_send_lowat"), 396 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 397 ngx_conf_set_size_slot, 398 NGX_HTTP_LOC_CONF_OFFSET, 399 offsetof(ngx_http_proxy_loc_conf_t, upstream.send_lowat), 400 &ngx_http_proxy_lowat_post }, 401 402 { ngx_string("proxy_intercept_errors"), 403 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, 404 ngx_conf_set_flag_slot, 405 NGX_HTTP_LOC_CONF_OFFSET, 406 offsetof(ngx_http_proxy_loc_conf_t, upstream.intercept_errors), 407 NULL }, 408 409 { ngx_string("proxy_set_header"), 410 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, 411 ngx_conf_set_keyval_slot, 412 NGX_HTTP_LOC_CONF_OFFSET, 413 offsetof(ngx_http_proxy_loc_conf_t, headers_source), 414 NULL }, 415 416 { ngx_string("proxy_headers_hash_max_size"), 417 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 418 ngx_conf_set_num_slot, 419 NGX_HTTP_LOC_CONF_OFFSET, 420 offsetof(ngx_http_proxy_loc_conf_t, headers_hash_max_size), 421 NULL }, 422 423 { ngx_string("proxy_headers_hash_bucket_size"), 424 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 425 ngx_conf_set_num_slot, 426 NGX_HTTP_LOC_CONF_OFFSET, 427 offsetof(ngx_http_proxy_loc_conf_t, headers_hash_bucket_size), 428 NULL }, 429 430 { ngx_string("proxy_set_body"), 431 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 432 ngx_conf_set_str_slot, 433 NGX_HTTP_LOC_CONF_OFFSET, 434 offsetof(ngx_http_proxy_loc_conf_t, body_source), 435 NULL }, 436 437 { ngx_string("proxy_method"), 438 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 439 ngx_http_set_complex_value_slot, 440 NGX_HTTP_LOC_CONF_OFFSET, 441 offsetof(ngx_http_proxy_loc_conf_t, method), 442 NULL }, 443 444 { ngx_string("proxy_pass_request_headers"), 445 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, 446 ngx_conf_set_flag_slot, 447 NGX_HTTP_LOC_CONF_OFFSET, 448 offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_headers), 449 NULL }, 450 451 { ngx_string("proxy_pass_request_body"), 452 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, 453 ngx_conf_set_flag_slot, 454 NGX_HTTP_LOC_CONF_OFFSET, 455 offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_body), 456 NULL }, 457 458 { ngx_string("proxy_buffer_size"), 459 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 460 ngx_conf_set_size_slot, 461 NGX_HTTP_LOC_CONF_OFFSET, 462 offsetof(ngx_http_proxy_loc_conf_t, upstream.buffer_size), 463 NULL }, 464 465 { ngx_string("proxy_read_timeout"), 466 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 467 ngx_conf_set_msec_slot, 468 NGX_HTTP_LOC_CONF_OFFSET, 469 offsetof(ngx_http_proxy_loc_conf_t, upstream.read_timeout), 470 NULL }, 471 472 { ngx_string("proxy_buffers"), 473 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, 474 ngx_conf_set_bufs_slot, 475 NGX_HTTP_LOC_CONF_OFFSET, 476 offsetof(ngx_http_proxy_loc_conf_t, upstream.bufs), 477 NULL }, 478 479 { ngx_string("proxy_busy_buffers_size"), 480 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 481 ngx_conf_set_size_slot, 482 NGX_HTTP_LOC_CONF_OFFSET, 483 offsetof(ngx_http_proxy_loc_conf_t, upstream.busy_buffers_size_conf), 484 NULL }, 485 486 { ngx_string("proxy_force_ranges"), 487 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, 488 ngx_conf_set_flag_slot, 489 NGX_HTTP_LOC_CONF_OFFSET, 490 offsetof(ngx_http_proxy_loc_conf_t, upstream.force_ranges), 491 NULL }, 492 493 { ngx_string("proxy_limit_rate"), 494 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 495 ngx_conf_set_size_slot, 496 NGX_HTTP_LOC_CONF_OFFSET, 497 offsetof(ngx_http_proxy_loc_conf_t, upstream.limit_rate), 498 NULL }, 499 500 #if (NGX_HTTP_CACHE) 501 502 { ngx_string("proxy_cache"), 503 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 504 ngx_http_proxy_cache, 505 NGX_HTTP_LOC_CONF_OFFSET, 506 0, 507 NULL }, 508 509 { ngx_string("proxy_cache_key"), 510 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 511 ngx_http_proxy_cache_key, 512 NGX_HTTP_LOC_CONF_OFFSET, 513 0, 514 NULL }, 515 516 { ngx_string("proxy_cache_path"), 517 NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE, 518 ngx_http_file_cache_set_slot, 519 NGX_HTTP_MAIN_CONF_OFFSET, 520 offsetof(ngx_http_proxy_main_conf_t, caches), 521 &ngx_http_proxy_module }, 522 523 { ngx_string("proxy_cache_bypass"), 524 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, 525 ngx_http_set_predicate_slot, 526 NGX_HTTP_LOC_CONF_OFFSET, 527 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_bypass), 528 NULL }, 529 530 { ngx_string("proxy_no_cache"), 531 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, 532 ngx_http_set_predicate_slot, 533 NGX_HTTP_LOC_CONF_OFFSET, 534 offsetof(ngx_http_proxy_loc_conf_t, upstream.no_cache), 535 NULL }, 536 537 { ngx_string("proxy_cache_valid"), 538 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, 539 ngx_http_file_cache_valid_set_slot, 540 NGX_HTTP_LOC_CONF_OFFSET, 541 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_valid), 542 NULL }, 543 544 { ngx_string("proxy_cache_min_uses"), 545 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 546 ngx_conf_set_num_slot, 547 NGX_HTTP_LOC_CONF_OFFSET, 548 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_min_uses), 549 NULL }, 550 551 { ngx_string("proxy_cache_max_range_offset"), 552 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 553 ngx_conf_set_off_slot, 554 NGX_HTTP_LOC_CONF_OFFSET, 555 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_max_range_offset), 556 NULL }, 557 558 { ngx_string("proxy_cache_use_stale"), 559 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, 560 ngx_conf_set_bitmask_slot, 561 NGX_HTTP_LOC_CONF_OFFSET, 562 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_use_stale), 563 &ngx_http_proxy_next_upstream_masks }, 564 565 { ngx_string("proxy_cache_methods"), 566 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, 567 ngx_conf_set_bitmask_slot, 568 NGX_HTTP_LOC_CONF_OFFSET, 569 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_methods), 570 &ngx_http_upstream_cache_method_mask }, 571 572 { ngx_string("proxy_cache_lock"), 573 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, 574 ngx_conf_set_flag_slot, 575 NGX_HTTP_LOC_CONF_OFFSET, 576 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_lock), 577 NULL }, 578 579 { ngx_string("proxy_cache_lock_timeout"), 580 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 581 ngx_conf_set_msec_slot, 582 NGX_HTTP_LOC_CONF_OFFSET, 583 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_lock_timeout), 584 NULL }, 585 586 { ngx_string("proxy_cache_lock_age"), 587 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 588 ngx_conf_set_msec_slot, 589 NGX_HTTP_LOC_CONF_OFFSET, 590 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_lock_age), 591 NULL }, 592 593 { ngx_string("proxy_cache_revalidate"), 594 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, 595 ngx_conf_set_flag_slot, 596 NGX_HTTP_LOC_CONF_OFFSET, 597 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_revalidate), 598 NULL }, 599 600 { ngx_string("proxy_cache_convert_head"), 601 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, 602 ngx_conf_set_flag_slot, 603 NGX_HTTP_LOC_CONF_OFFSET, 604 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_convert_head), 605 NULL }, 606 607 { ngx_string("proxy_cache_background_update"), 608 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, 609 ngx_conf_set_flag_slot, 610 NGX_HTTP_LOC_CONF_OFFSET, 611 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_background_update), 612 NULL }, 613 614 #endif 615 616 { ngx_string("proxy_temp_path"), 617 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234, 618 ngx_conf_set_path_slot, 619 NGX_HTTP_LOC_CONF_OFFSET, 620 offsetof(ngx_http_proxy_loc_conf_t, upstream.temp_path), 621 NULL }, 622 623 { ngx_string("proxy_max_temp_file_size"), 624 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 625 ngx_conf_set_size_slot, 626 NGX_HTTP_LOC_CONF_OFFSET, 627 offsetof(ngx_http_proxy_loc_conf_t, upstream.max_temp_file_size_conf), 628 NULL }, 629 630 { ngx_string("proxy_temp_file_write_size"), 631 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 632 ngx_conf_set_size_slot, 633 NGX_HTTP_LOC_CONF_OFFSET, 634 offsetof(ngx_http_proxy_loc_conf_t, upstream.temp_file_write_size_conf), 635 NULL }, 636 637 { ngx_string("proxy_next_upstream"), 638 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, 639 ngx_conf_set_bitmask_slot, 640 NGX_HTTP_LOC_CONF_OFFSET, 641 offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream), 642 &ngx_http_proxy_next_upstream_masks }, 643 644 { ngx_string("proxy_next_upstream_tries"), 645 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 646 ngx_conf_set_num_slot, 647 NGX_HTTP_LOC_CONF_OFFSET, 648 offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream_tries), 649 NULL }, 650 651 { ngx_string("proxy_next_upstream_timeout"), 652 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 653 ngx_conf_set_msec_slot, 654 NGX_HTTP_LOC_CONF_OFFSET, 655 offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream_timeout), 656 NULL }, 657 658 { ngx_string("proxy_pass_header"), 659 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 660 ngx_conf_set_str_array_slot, 661 NGX_HTTP_LOC_CONF_OFFSET, 662 offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_headers), 663 NULL }, 664 665 { ngx_string("proxy_hide_header"), 666 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 667 ngx_conf_set_str_array_slot, 668 NGX_HTTP_LOC_CONF_OFFSET, 669 offsetof(ngx_http_proxy_loc_conf_t, upstream.hide_headers), 670 NULL }, 671 672 { ngx_string("proxy_ignore_headers"), 673 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, 674 ngx_conf_set_bitmask_slot, 675 NGX_HTTP_LOC_CONF_OFFSET, 676 offsetof(ngx_http_proxy_loc_conf_t, upstream.ignore_headers), 677 &ngx_http_upstream_ignore_headers_masks }, 678 679 { ngx_string("proxy_http_version"), 680 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 681 ngx_conf_set_enum_slot, 682 NGX_HTTP_LOC_CONF_OFFSET, 683 offsetof(ngx_http_proxy_loc_conf_t, http_version), 684 &ngx_http_proxy_http_version }, 685 686 #if (NGX_HTTP_SSL) 687 688 { ngx_string("proxy_ssl_session_reuse"), 689 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, 690 ngx_conf_set_flag_slot, 691 NGX_HTTP_LOC_CONF_OFFSET, 692 offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_session_reuse), 693 NULL }, 694 695 { ngx_string("proxy_ssl_protocols"), 696 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, 697 ngx_conf_set_bitmask_slot, 698 NGX_HTTP_LOC_CONF_OFFSET, 699 offsetof(ngx_http_proxy_loc_conf_t, ssl_protocols), 700 &ngx_http_proxy_ssl_protocols }, 701 702 { ngx_string("proxy_ssl_ciphers"), 703 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 704 ngx_conf_set_str_slot, 705 NGX_HTTP_LOC_CONF_OFFSET, 706 offsetof(ngx_http_proxy_loc_conf_t, ssl_ciphers), 707 NULL }, 708 709 { ngx_string("proxy_ssl_name"), 710 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 711 ngx_http_set_complex_value_slot, 712 NGX_HTTP_LOC_CONF_OFFSET, 713 offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_name), 714 NULL }, 715 716 { ngx_string("proxy_ssl_server_name"), 717 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, 718 ngx_conf_set_flag_slot, 719 NGX_HTTP_LOC_CONF_OFFSET, 720 offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_server_name), 721 NULL }, 722 723 { ngx_string("proxy_ssl_verify"), 724 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, 725 ngx_conf_set_flag_slot, 726 NGX_HTTP_LOC_CONF_OFFSET, 727 offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_verify), 728 NULL }, 729 730 { ngx_string("proxy_ssl_verify_depth"), 731 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 732 ngx_conf_set_num_slot, 733 NGX_HTTP_LOC_CONF_OFFSET, 734 offsetof(ngx_http_proxy_loc_conf_t, ssl_verify_depth), 735 NULL }, 736 737 { ngx_string("proxy_ssl_trusted_certificate"), 738 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 739 ngx_conf_set_str_slot, 740 NGX_HTTP_LOC_CONF_OFFSET, 741 offsetof(ngx_http_proxy_loc_conf_t, ssl_trusted_certificate), 742 NULL }, 743 744 { ngx_string("proxy_ssl_crl"), 745 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 746 ngx_conf_set_str_slot, 747 NGX_HTTP_LOC_CONF_OFFSET, 748 offsetof(ngx_http_proxy_loc_conf_t, ssl_crl), 749 NULL }, 750 751 { ngx_string("proxy_ssl_certificate"), 752 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 753 ngx_http_set_complex_value_zero_slot, 754 NGX_HTTP_LOC_CONF_OFFSET, 755 offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_certificate), 756 NULL }, 757 758 { ngx_string("proxy_ssl_certificate_key"), 759 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 760 ngx_http_set_complex_value_zero_slot, 761 NGX_HTTP_LOC_CONF_OFFSET, 762 offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_certificate_key), 763 NULL }, 764 765 { ngx_string("proxy_ssl_password_file"), 766 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 767 ngx_http_proxy_ssl_password_file, 768 NGX_HTTP_LOC_CONF_OFFSET, 769 0, 770 NULL }, 771 772 { ngx_string("proxy_ssl_conf_command"), 773 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, 774 ngx_conf_set_keyval_slot, 775 NGX_HTTP_LOC_CONF_OFFSET, 776 offsetof(ngx_http_proxy_loc_conf_t, ssl_conf_commands), 777 &ngx_http_proxy_ssl_conf_command_post }, 778 779 #endif 780 781 ngx_null_command 782 }; 783 784 785 static ngx_http_module_t ngx_http_proxy_module_ctx = { 786 ngx_http_proxy_add_variables, /* preconfiguration */ 787 NULL, /* postconfiguration */ 788 789 ngx_http_proxy_create_main_conf, /* create main configuration */ 790 NULL, /* init main configuration */ 791 792 NULL, /* create server configuration */ 793 NULL, /* merge server configuration */ 794 795 ngx_http_proxy_create_loc_conf, /* create location configuration */ 796 ngx_http_proxy_merge_loc_conf /* merge location configuration */ 797 }; 798 799 800 ngx_module_t ngx_http_proxy_module = { 801 NGX_MODULE_V1, 802 &ngx_http_proxy_module_ctx, /* module context */ 803 ngx_http_proxy_commands, /* module directives */ 804 NGX_HTTP_MODULE, /* module type */ 805 NULL, /* init master */ 806 NULL, /* init module */ 807 NULL, /* init process */ 808 NULL, /* init thread */ 809 NULL, /* exit thread */ 810 NULL, /* exit process */ 811 NULL, /* exit master */ 812 NGX_MODULE_V1_PADDING 813 }; 814 815 816 static char ngx_http_proxy_version[] = " HTTP/1.0" CRLF; 817 static char ngx_http_proxy_version_11[] = " HTTP/1.1" CRLF; 818 819 820 static ngx_keyval_t ngx_http_proxy_headers[] = { 821 { ngx_string("Host"), ngx_string("$proxy_host") }, 822 { ngx_string("Connection"), ngx_string("close") }, 823 { ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") }, 824 { ngx_string("Transfer-Encoding"), ngx_string("$proxy_internal_chunked") }, 825 { ngx_string("TE"), ngx_string("") }, 826 { ngx_string("Keep-Alive"), ngx_string("") }, 827 { ngx_string("Expect"), ngx_string("") }, 828 { ngx_string("Upgrade"), ngx_string("") }, 829 { ngx_null_string, ngx_null_string } 830 }; 831 832 833 static ngx_str_t ngx_http_proxy_hide_headers[] = { 834 ngx_string("Date"), 835 ngx_string("Server"), 836 ngx_string("X-Pad"), 837 ngx_string("X-Accel-Expires"), 838 ngx_string("X-Accel-Redirect"), 839 ngx_string("X-Accel-Limit-Rate"), 840 ngx_string("X-Accel-Buffering"), 841 ngx_string("X-Accel-Charset"), 842 ngx_null_string 843 }; 844 845 846 #if (NGX_HTTP_CACHE) 847 848 static ngx_keyval_t ngx_http_proxy_cache_headers[] = { 849 { ngx_string("Host"), ngx_string("$proxy_host") }, 850 { ngx_string("Connection"), ngx_string("close") }, 851 { ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") }, 852 { ngx_string("Transfer-Encoding"), ngx_string("$proxy_internal_chunked") }, 853 { ngx_string("TE"), ngx_string("") }, 854 { ngx_string("Keep-Alive"), ngx_string("") }, 855 { ngx_string("Expect"), ngx_string("") }, 856 { ngx_string("Upgrade"), ngx_string("") }, 857 { ngx_string("If-Modified-Since"), 858 ngx_string("$upstream_cache_last_modified") }, 859 { ngx_string("If-Unmodified-Since"), ngx_string("") }, 860 { ngx_string("If-None-Match"), ngx_string("$upstream_cache_etag") }, 861 { ngx_string("If-Match"), ngx_string("") }, 862 { ngx_string("Range"), ngx_string("") }, 863 { ngx_string("If-Range"), ngx_string("") }, 864 { ngx_null_string, ngx_null_string } 865 }; 866 867 #endif 868 869 870 static ngx_http_variable_t ngx_http_proxy_vars[] = { 871 872 { ngx_string("proxy_host"), NULL, ngx_http_proxy_host_variable, 0, 873 NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, 874 875 { ngx_string("proxy_port"), NULL, ngx_http_proxy_port_variable, 0, 876 NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, 877 878 { ngx_string("proxy_add_x_forwarded_for"), NULL, 879 ngx_http_proxy_add_x_forwarded_for_variable, 0, NGX_HTTP_VAR_NOHASH, 0 }, 880 881 #if 0 882 { ngx_string("proxy_add_via"), NULL, NULL, 0, NGX_HTTP_VAR_NOHASH, 0 }, 883 #endif 884 885 { ngx_string("proxy_internal_body_length"), NULL, 886 ngx_http_proxy_internal_body_length_variable, 0, 887 NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, 888 889 { ngx_string("proxy_internal_chunked"), NULL, 890 ngx_http_proxy_internal_chunked_variable, 0, 891 NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, 892 893 ngx_http_null_variable 894 }; 895 896 897 static ngx_path_init_t ngx_http_proxy_temp_path = { 898 ngx_string(NGX_HTTP_PROXY_TEMP_PATH), { 1, 2, 0 } 899 }; 900 901 902 static ngx_conf_bitmask_t ngx_http_proxy_cookie_flags_masks[] = { 903 904 { ngx_string("secure"), 905 NGX_HTTP_PROXY_COOKIE_SECURE|NGX_HTTP_PROXY_COOKIE_SECURE_ON }, 906 907 { ngx_string("nosecure"), 908 NGX_HTTP_PROXY_COOKIE_SECURE|NGX_HTTP_PROXY_COOKIE_SECURE_OFF }, 909 910 { ngx_string("httponly"), 911 NGX_HTTP_PROXY_COOKIE_HTTPONLY|NGX_HTTP_PROXY_COOKIE_HTTPONLY_ON }, 912 913 { ngx_string("nohttponly"), 914 NGX_HTTP_PROXY_COOKIE_HTTPONLY|NGX_HTTP_PROXY_COOKIE_HTTPONLY_OFF }, 915 916 { ngx_string("samesite=strict"), 917 NGX_HTTP_PROXY_COOKIE_SAMESITE|NGX_HTTP_PROXY_COOKIE_SAMESITE_STRICT }, 918 919 { ngx_string("samesite=lax"), 920 NGX_HTTP_PROXY_COOKIE_SAMESITE|NGX_HTTP_PROXY_COOKIE_SAMESITE_LAX }, 921 922 { ngx_string("samesite=none"), 923 NGX_HTTP_PROXY_COOKIE_SAMESITE|NGX_HTTP_PROXY_COOKIE_SAMESITE_NONE }, 924 925 { ngx_string("nosamesite"), 926 NGX_HTTP_PROXY_COOKIE_SAMESITE|NGX_HTTP_PROXY_COOKIE_SAMESITE_OFF }, 927 928 { ngx_null_string, 0 } 929 }; 930 931 932 static ngx_int_t 933 ngx_http_proxy_handler(ngx_http_request_t *r) 934 { 935 ngx_int_t rc; 936 ngx_http_upstream_t *u; 937 ngx_http_proxy_ctx_t *ctx; 938 ngx_http_proxy_loc_conf_t *plcf; 939 #if (NGX_HTTP_CACHE) 940 ngx_http_proxy_main_conf_t *pmcf; 941 #endif 942 943 if (ngx_http_upstream_create(r) != NGX_OK) { 944 return NGX_HTTP_INTERNAL_SERVER_ERROR; 945 } 946 947 ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_ctx_t)); 948 if (ctx == NULL) { 949 return NGX_HTTP_INTERNAL_SERVER_ERROR; 950 } 951 952 ngx_http_set_ctx(r, ctx, ngx_http_proxy_module); 953 954 plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); 955 956 u = r->upstream; 957 958 if (plcf->proxy_lengths == NULL) { 959 ctx->vars = plcf->vars; 960 u->schema = plcf->vars.schema; 961 #if (NGX_HTTP_SSL) 962 u->ssl = (plcf->upstream.ssl != NULL); 963 #endif 964 965 } else { 966 if (ngx_http_proxy_eval(r, ctx, plcf) != NGX_OK) { 967 return NGX_HTTP_INTERNAL_SERVER_ERROR; 968 } 969 } 970 971 u->output.tag = (ngx_buf_tag_t) &ngx_http_proxy_module; 972 973 u->conf = &plcf->upstream; 974 975 #if (NGX_HTTP_CACHE) 976 pmcf = ngx_http_get_module_main_conf(r, ngx_http_proxy_module); 977 978 u->caches = &pmcf->caches; 979 u->create_key = ngx_http_proxy_create_key; 980 #endif 981 982 u->create_request = ngx_http_proxy_create_request; 983 u->reinit_request = ngx_http_proxy_reinit_request; 984 u->process_header = ngx_http_proxy_process_status_line; 985 u->abort_request = ngx_http_proxy_abort_request; 986 u->finalize_request = ngx_http_proxy_finalize_request; 987 r->state = 0; 988 989 if (plcf->redirects) { 990 u->rewrite_redirect = ngx_http_proxy_rewrite_redirect; 991 } 992 993 if (plcf->cookie_domains || plcf->cookie_paths || plcf->cookie_flags) { 994 u->rewrite_cookie = ngx_http_proxy_rewrite_cookie; 995 } 996 997 u->buffering = plcf->upstream.buffering; 998 999 u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t)); 1000 if (u->pipe == NULL) { 1001 return NGX_HTTP_INTERNAL_SERVER_ERROR; 1002 } 1003 1004 u->pipe->input_filter = ngx_http_proxy_copy_filter; 1005 u->pipe->input_ctx = r; 1006 1007 u->input_filter_init = ngx_http_proxy_input_filter_init; 1008 u->input_filter = ngx_http_proxy_non_buffered_copy_filter; 1009 u->input_filter_ctx = r; 1010 1011 u->accel = 1; 1012 1013 if (!plcf->upstream.request_buffering 1014 && plcf->body_values == NULL && plcf->upstream.pass_request_body 1015 && (!r->headers_in.chunked 1016 || plcf->http_version == NGX_HTTP_VERSION_11)) 1017 { 1018 r->request_body_no_buffering = 1; 1019 } 1020 1021 rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init); 1022 1023 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { 1024 return rc; 1025 } 1026 1027 return NGX_DONE; 1028 } 1029 1030 1031 static ngx_int_t 1032 ngx_http_proxy_eval(ngx_http_request_t *r, ngx_http_proxy_ctx_t *ctx, 1033 ngx_http_proxy_loc_conf_t *plcf) 1034 { 1035 u_char *p; 1036 size_t add; 1037 u_short port; 1038 ngx_str_t proxy; 1039 ngx_url_t url; 1040 ngx_http_upstream_t *u; 1041 1042 if (ngx_http_script_run(r, &proxy, plcf->proxy_lengths->elts, 0, 1043 plcf->proxy_values->elts) 1044 == NULL) 1045 { 1046 return NGX_ERROR; 1047 } 1048 1049 if (proxy.len > 7 1050 && ngx_strncasecmp(proxy.data, (u_char *) "http://", 7) == 0) 1051 { 1052 add = 7; 1053 port = 80; 1054 1055 #if (NGX_HTTP_SSL) 1056 1057 } else if (proxy.len > 8 1058 && ngx_strncasecmp(proxy.data, (u_char *) "https://", 8) == 0) 1059 { 1060 add = 8; 1061 port = 443; 1062 r->upstream->ssl = 1; 1063 1064 #endif 1065 1066 } else { 1067 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 1068 "invalid URL prefix in \"%V\"", &proxy); 1069 return NGX_ERROR; 1070 } 1071 1072 u = r->upstream; 1073 1074 u->schema.len = add; 1075 u->schema.data = proxy.data; 1076 1077 ngx_memzero(&url, sizeof(ngx_url_t)); 1078 1079 url.url.len = proxy.len - add; 1080 url.url.data = proxy.data + add; 1081 url.default_port = port; 1082 url.uri_part = 1; 1083 url.no_resolve = 1; 1084 1085 if (ngx_parse_url(r->pool, &url) != NGX_OK) { 1086 if (url.err) { 1087 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 1088 "%s in upstream \"%V\"", url.err, &url.url); 1089 } 1090 1091 return NGX_ERROR; 1092 } 1093 1094 if (url.uri.len) { 1095 if (url.uri.data[0] == '?') { 1096 p = ngx_pnalloc(r->pool, url.uri.len + 1); 1097 if (p == NULL) { 1098 return NGX_ERROR; 1099 } 1100 1101 *p++ = '/'; 1102 ngx_memcpy(p, url.uri.data, url.uri.len); 1103 1104 url.uri.len++; 1105 url.uri.data = p - 1; 1106 } 1107 } 1108 1109 ctx->vars.key_start = u->schema; 1110 1111 ngx_http_proxy_set_vars(&url, &ctx->vars); 1112 1113 u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t)); 1114 if (u->resolved == NULL) { 1115 return NGX_ERROR; 1116 } 1117 1118 if (url.addrs) { 1119 u->resolved->sockaddr = url.addrs[0].sockaddr; 1120 u->resolved->socklen = url.addrs[0].socklen; 1121 u->resolved->name = url.addrs[0].name; 1122 u->resolved->naddrs = 1; 1123 } 1124 1125 u->resolved->host = url.host; 1126 u->resolved->port = (in_port_t) (url.no_port ? port : url.port); 1127 u->resolved->no_port = url.no_port; 1128 1129 return NGX_OK; 1130 } 1131 1132 1133 #if (NGX_HTTP_CACHE) 1134 1135 static ngx_int_t 1136 ngx_http_proxy_create_key(ngx_http_request_t *r) 1137 { 1138 size_t len, loc_len; 1139 u_char *p; 1140 uintptr_t escape; 1141 ngx_str_t *key; 1142 ngx_http_upstream_t *u; 1143 ngx_http_proxy_ctx_t *ctx; 1144 ngx_http_proxy_loc_conf_t *plcf; 1145 1146 u = r->upstream; 1147 1148 plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); 1149 1150 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module); 1151 1152 key = ngx_array_push(&r->cache->keys); 1153 if (key == NULL) { 1154 return NGX_ERROR; 1155 } 1156 1157 if (plcf->cache_key.value.data) { 1158 1159 if (ngx_http_complex_value(r, &plcf->cache_key, key) != NGX_OK) { 1160 return NGX_ERROR; 1161 } 1162 1163 return NGX_OK; 1164 } 1165 1166 *key = ctx->vars.key_start; 1167 1168 key = ngx_array_push(&r->cache->keys); 1169 if (key == NULL) { 1170 return NGX_ERROR; 1171 } 1172 1173 if (plcf->proxy_lengths && ctx->vars.uri.len) { 1174 1175 *key = ctx->vars.uri; 1176 u->uri = ctx->vars.uri; 1177 1178 return NGX_OK; 1179 1180 } else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri) { 1181 *key = r->unparsed_uri; 1182 u->uri = r->unparsed_uri; 1183 1184 return NGX_OK; 1185 } 1186 1187 loc_len = (r->valid_location && ctx->vars.uri.len) ? plcf->location.len : 0; 1188 1189 if (r->quoted_uri || r->internal) { 1190 escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len, 1191 r->uri.len - loc_len, NGX_ESCAPE_URI); 1192 } else { 1193 escape = 0; 1194 } 1195 1196 len = ctx->vars.uri.len + r->uri.len - loc_len + escape 1197 + sizeof("?") - 1 + r->args.len; 1198 1199 p = ngx_pnalloc(r->pool, len); 1200 if (p == NULL) { 1201 return NGX_ERROR; 1202 } 1203 1204 key->data = p; 1205 1206 if (r->valid_location) { 1207 p = ngx_copy(p, ctx->vars.uri.data, ctx->vars.uri.len); 1208 } 1209 1210 if (escape) { 1211 ngx_escape_uri(p, r->uri.data + loc_len, 1212 r->uri.len - loc_len, NGX_ESCAPE_URI); 1213 p += r->uri.len - loc_len + escape; 1214 1215 } else { 1216 p = ngx_copy(p, r->uri.data + loc_len, r->uri.len - loc_len); 1217 } 1218 1219 if (r->args.len > 0) { 1220 *p++ = '?'; 1221 p = ngx_copy(p, r->args.data, r->args.len); 1222 } 1223 1224 key->len = p - key->data; 1225 u->uri = *key; 1226 1227 return NGX_OK; 1228 } 1229 1230 #endif 1231 1232 1233 static ngx_int_t 1234 ngx_http_proxy_create_request(ngx_http_request_t *r) 1235 { 1236 size_t len, uri_len, loc_len, body_len, 1237 key_len, val_len; 1238 uintptr_t escape; 1239 ngx_buf_t *b; 1240 ngx_str_t method; 1241 ngx_uint_t i, unparsed_uri; 1242 ngx_chain_t *cl, *body; 1243 ngx_list_part_t *part; 1244 ngx_table_elt_t *header; 1245 ngx_http_upstream_t *u; 1246 ngx_http_proxy_ctx_t *ctx; 1247 ngx_http_script_code_pt code; 1248 ngx_http_proxy_headers_t *headers; 1249 ngx_http_script_engine_t e, le; 1250 ngx_http_proxy_loc_conf_t *plcf; 1251 ngx_http_script_len_code_pt lcode; 1252 1253 u = r->upstream; 1254 1255 plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); 1256 1257 #if (NGX_HTTP_CACHE) 1258 headers = u->cacheable ? &plcf->headers_cache : &plcf->headers; 1259 #else 1260 headers = &plcf->headers; 1261 #endif 1262 1263 if (u->method.len) { 1264 /* HEAD was changed to GET to cache response */ 1265 method = u->method; 1266 1267 } else if (plcf->method) { 1268 if (ngx_http_complex_value(r, plcf->method, &method) != NGX_OK) { 1269 return NGX_ERROR; 1270 } 1271 1272 } else { 1273 method = r->method_name; 1274 } 1275 1276 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module); 1277 1278 if (method.len == 4 1279 && ngx_strncasecmp(method.data, (u_char *) "HEAD", 4) == 0) 1280 { 1281 ctx->head = 1; 1282 } 1283 1284 len = method.len + 1 + sizeof(ngx_http_proxy_version) - 1 1285 + sizeof(CRLF) - 1; 1286 1287 escape = 0; 1288 loc_len = 0; 1289 unparsed_uri = 0; 1290 1291 if (plcf->proxy_lengths && ctx->vars.uri.len) { 1292 uri_len = ctx->vars.uri.len; 1293 1294 } else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri) { 1295 unparsed_uri = 1; 1296 uri_len = r->unparsed_uri.len; 1297 1298 } else { 1299 loc_len = (r->valid_location && ctx->vars.uri.len) ? 1300 plcf->location.len : 0; 1301 1302 if (r->quoted_uri || r->internal) { 1303 escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len, 1304 r->uri.len - loc_len, NGX_ESCAPE_URI); 1305 } 1306 1307 uri_len = ctx->vars.uri.len + r->uri.len - loc_len + escape 1308 + sizeof("?") - 1 + r->args.len; 1309 } 1310 1311 if (uri_len == 0) { 1312 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 1313 "zero length URI to proxy"); 1314 return NGX_ERROR; 1315 } 1316 1317 len += uri_len; 1318 1319 ngx_memzero(&le, sizeof(ngx_http_script_engine_t)); 1320 1321 ngx_http_script_flush_no_cacheable_variables(r, plcf->body_flushes); 1322 ngx_http_script_flush_no_cacheable_variables(r, headers->flushes); 1323 1324 if (plcf->body_lengths) { 1325 le.ip = plcf->body_lengths->elts; 1326 le.request = r; 1327 le.flushed = 1; 1328 body_len = 0; 1329 1330 while (*(uintptr_t *) le.ip) { 1331 lcode = *(ngx_http_script_len_code_pt *) le.ip; 1332 body_len += lcode(&le); 1333 } 1334 1335 ctx->internal_body_length = body_len; 1336 len += body_len; 1337 1338 } else if (r->headers_in.chunked && r->reading_body) { 1339 ctx->internal_body_length = -1; 1340 ctx->internal_chunked = 1; 1341 1342 } else { 1343 ctx->internal_body_length = r->headers_in.content_length_n; 1344 } 1345 1346 le.ip = headers->lengths->elts; 1347 le.request = r; 1348 le.flushed = 1; 1349 1350 while (*(uintptr_t *) le.ip) { 1351 1352 lcode = *(ngx_http_script_len_code_pt *) le.ip; 1353 key_len = lcode(&le); 1354 1355 for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) { 1356 lcode = *(ngx_http_script_len_code_pt *) le.ip; 1357 } 1358 le.ip += sizeof(uintptr_t); 1359 1360 if (val_len == 0) { 1361 continue; 1362 } 1363 1364 len += key_len + sizeof(": ") - 1 + val_len + sizeof(CRLF) - 1; 1365 } 1366 1367 1368 if (plcf->upstream.pass_request_headers) { 1369 part = &r->headers_in.headers.part; 1370 header = part->elts; 1371 1372 for (i = 0; /* void */; i++) { 1373 1374 if (i >= part->nelts) { 1375 if (part->next == NULL) { 1376 break; 1377 } 1378 1379 part = part->next; 1380 header = part->elts; 1381 i = 0; 1382 } 1383 1384 if (ngx_hash_find(&headers->hash, header[i].hash, 1385 header[i].lowcase_key, header[i].key.len)) 1386 { 1387 continue; 1388 } 1389 1390 len += header[i].key.len + sizeof(": ") - 1 1391 + header[i].value.len + sizeof(CRLF) - 1; 1392 } 1393 } 1394 1395 1396 b = ngx_create_temp_buf(r->pool, len); 1397 if (b == NULL) { 1398 return NGX_ERROR; 1399 } 1400 1401 cl = ngx_alloc_chain_link(r->pool); 1402 if (cl == NULL) { 1403 return NGX_ERROR; 1404 } 1405 1406 cl->buf = b; 1407 1408 1409 /* the request line */ 1410 1411 b->last = ngx_copy(b->last, method.data, method.len); 1412 *b->last++ = ' '; 1413 1414 u->uri.data = b->last; 1415 1416 if (plcf->proxy_lengths && ctx->vars.uri.len) { 1417 b->last = ngx_copy(b->last, ctx->vars.uri.data, ctx->vars.uri.len); 1418 1419 } else if (unparsed_uri) { 1420 b->last = ngx_copy(b->last, r->unparsed_uri.data, r->unparsed_uri.len); 1421 1422 } else { 1423 if (r->valid_location) { 1424 b->last = ngx_copy(b->last, ctx->vars.uri.data, ctx->vars.uri.len); 1425 } 1426 1427 if (escape) { 1428 ngx_escape_uri(b->last, r->uri.data + loc_len, 1429 r->uri.len - loc_len, NGX_ESCAPE_URI); 1430 b->last += r->uri.len - loc_len + escape; 1431 1432 } else { 1433 b->last = ngx_copy(b->last, r->uri.data + loc_len, 1434 r->uri.len - loc_len); 1435 } 1436 1437 if (r->args.len > 0) { 1438 *b->last++ = '?'; 1439 b->last = ngx_copy(b->last, r->args.data, r->args.len); 1440 } 1441 } 1442 1443 u->uri.len = b->last - u->uri.data; 1444 1445 if (plcf->http_version == NGX_HTTP_VERSION_11) { 1446 b->last = ngx_cpymem(b->last, ngx_http_proxy_version_11, 1447 sizeof(ngx_http_proxy_version_11) - 1); 1448 1449 } else { 1450 b->last = ngx_cpymem(b->last, ngx_http_proxy_version, 1451 sizeof(ngx_http_proxy_version) - 1); 1452 } 1453 1454 ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); 1455 1456 e.ip = headers->values->elts; 1457 e.pos = b->last; 1458 e.request = r; 1459 e.flushed = 1; 1460 1461 le.ip = headers->lengths->elts; 1462 1463 while (*(uintptr_t *) le.ip) { 1464 1465 lcode = *(ngx_http_script_len_code_pt *) le.ip; 1466 (void) lcode(&le); 1467 1468 for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) { 1469 lcode = *(ngx_http_script_len_code_pt *) le.ip; 1470 } 1471 le.ip += sizeof(uintptr_t); 1472 1473 if (val_len == 0) { 1474 e.skip = 1; 1475 1476 while (*(uintptr_t *) e.ip) { 1477 code = *(ngx_http_script_code_pt *) e.ip; 1478 code((ngx_http_script_engine_t *) &e); 1479 } 1480 e.ip += sizeof(uintptr_t); 1481 1482 e.skip = 0; 1483 1484 continue; 1485 } 1486 1487 code = *(ngx_http_script_code_pt *) e.ip; 1488 code((ngx_http_script_engine_t *) &e); 1489 1490 *e.pos++ = ':'; *e.pos++ = ' '; 1491 1492 while (*(uintptr_t *) e.ip) { 1493 code = *(ngx_http_script_code_pt *) e.ip; 1494 code((ngx_http_script_engine_t *) &e); 1495 } 1496 e.ip += sizeof(uintptr_t); 1497 1498 *e.pos++ = CR; *e.pos++ = LF; 1499 } 1500 1501 b->last = e.pos; 1502 1503 1504 if (plcf->upstream.pass_request_headers) { 1505 part = &r->headers_in.headers.part; 1506 header = part->elts; 1507 1508 for (i = 0; /* void */; i++) { 1509 1510 if (i >= part->nelts) { 1511 if (part->next == NULL) { 1512 break; 1513 } 1514 1515 part = part->next; 1516 header = part->elts; 1517 i = 0; 1518 } 1519 1520 if (ngx_hash_find(&headers->hash, header[i].hash, 1521 header[i].lowcase_key, header[i].key.len)) 1522 { 1523 continue; 1524 } 1525 1526 b->last = ngx_copy(b->last, header[i].key.data, header[i].key.len); 1527 1528 *b->last++ = ':'; *b->last++ = ' '; 1529 1530 b->last = ngx_copy(b->last, header[i].value.data, 1531 header[i].value.len); 1532 1533 *b->last++ = CR; *b->last++ = LF; 1534 1535 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 1536 "http proxy header: \"%V: %V\"", 1537 &header[i].key, &header[i].value); 1538 } 1539 } 1540 1541 1542 /* add "\r\n" at the header end */ 1543 *b->last++ = CR; *b->last++ = LF; 1544 1545 if (plcf->body_values) { 1546 e.ip = plcf->body_values->elts; 1547 e.pos = b->last; 1548 e.skip = 0; 1549 1550 while (*(uintptr_t *) e.ip) { 1551 code = *(ngx_http_script_code_pt *) e.ip; 1552 code((ngx_http_script_engine_t *) &e); 1553 } 1554 1555 b->last = e.pos; 1556 } 1557 1558 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 1559 "http proxy header:%N\"%*s\"", 1560 (size_t) (b->last - b->pos), b->pos); 1561 1562 if (r->request_body_no_buffering) { 1563 1564 u->request_bufs = cl; 1565 1566 if (ctx->internal_chunked) { 1567 u->output.output_filter = ngx_http_proxy_body_output_filter; 1568 u->output.filter_ctx = r; 1569 } 1570 1571 } else if (plcf->body_values == NULL && plcf->upstream.pass_request_body) { 1572 1573 body = u->request_bufs; 1574 u->request_bufs = cl; 1575 1576 while (body) { 1577 b = ngx_alloc_buf(r->pool); 1578 if (b == NULL) { 1579 return NGX_ERROR; 1580 } 1581 1582 ngx_memcpy(b, body->buf, sizeof(ngx_buf_t)); 1583 1584 cl->next = ngx_alloc_chain_link(r->pool); 1585 if (cl->next == NULL) { 1586 return NGX_ERROR; 1587 } 1588 1589 cl = cl->next; 1590 cl->buf = b; 1591 1592 body = body->next; 1593 } 1594 1595 } else { 1596 u->request_bufs = cl; 1597 } 1598 1599 b->flush = 1; 1600 cl->next = NULL; 1601 1602 return NGX_OK; 1603 } 1604 1605 1606 static ngx_int_t 1607 ngx_http_proxy_reinit_request(ngx_http_request_t *r) 1608 { 1609 ngx_http_proxy_ctx_t *ctx; 1610 1611 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module); 1612 1613 if (ctx == NULL) { 1614 return NGX_OK; 1615 } 1616 1617 ctx->status.code = 0; 1618 ctx->status.count = 0; 1619 ctx->status.start = NULL; 1620 ctx->status.end = NULL; 1621 ctx->chunked.state = 0; 1622 1623 r->upstream->process_header = ngx_http_proxy_process_status_line; 1624 r->upstream->pipe->input_filter = ngx_http_proxy_copy_filter; 1625 r->upstream->input_filter = ngx_http_proxy_non_buffered_copy_filter; 1626 r->state = 0; 1627 1628 return NGX_OK; 1629 } 1630 1631 1632 static ngx_int_t 1633 ngx_http_proxy_body_output_filter(void *data, ngx_chain_t *in) 1634 { 1635 ngx_http_request_t *r = data; 1636 1637 off_t size; 1638 u_char *chunk; 1639 ngx_int_t rc; 1640 ngx_buf_t *b; 1641 ngx_chain_t *out, *cl, *tl, **ll, **fl; 1642 ngx_http_proxy_ctx_t *ctx; 1643 1644 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 1645 "proxy output filter"); 1646 1647 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module); 1648 1649 if (in == NULL) { 1650 out = in; 1651 goto out; 1652 } 1653 1654 out = NULL; 1655 ll = &out; 1656 1657 if (!ctx->header_sent) { 1658 /* first buffer contains headers, pass it unmodified */ 1659 1660 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 1661 "proxy output header"); 1662 1663 ctx->header_sent = 1; 1664 1665 tl = ngx_alloc_chain_link(r->pool); 1666 if (tl == NULL) { 1667 return NGX_ERROR; 1668 } 1669 1670 tl->buf = in->buf; 1671 *ll = tl; 1672 ll = &tl->next; 1673 1674 in = in->next; 1675 1676 if (in == NULL) { 1677 tl->next = NULL; 1678 goto out; 1679 } 1680 } 1681 1682 size = 0; 1683 cl = in; 1684 fl = ll; 1685 1686 for ( ;; ) { 1687 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 1688 "proxy output chunk: %O", ngx_buf_size(cl->buf)); 1689 1690 size += ngx_buf_size(cl->buf); 1691 1692 if (cl->buf->flush 1693 || cl->buf->sync 1694 || ngx_buf_in_memory(cl->buf) 1695 || cl->buf->in_file) 1696 { 1697 tl = ngx_alloc_chain_link(r->pool); 1698 if (tl == NULL) { 1699 return NGX_ERROR; 1700 } 1701 1702 tl->buf = cl->buf; 1703 *ll = tl; 1704 ll = &tl->next; 1705 } 1706 1707 if (cl->next == NULL) { 1708 break; 1709 } 1710 1711 cl = cl->next; 1712 } 1713 1714 if (size) { 1715 tl = ngx_chain_get_free_buf(r->pool, &ctx->free); 1716 if (tl == NULL) { 1717 return NGX_ERROR; 1718 } 1719 1720 b = tl->buf; 1721 chunk = b->start; 1722 1723 if (chunk == NULL) { 1724 /* the "0000000000000000" is 64-bit hexadecimal string */ 1725 1726 chunk = ngx_palloc(r->pool, sizeof("0000000000000000" CRLF) - 1); 1727 if (chunk == NULL) { 1728 return NGX_ERROR; 1729 } 1730 1731 b->start = chunk; 1732 b->end = chunk + sizeof("0000000000000000" CRLF) - 1; 1733 } 1734 1735 b->tag = (ngx_buf_tag_t) &ngx_http_proxy_body_output_filter; 1736 b->memory = 0; 1737 b->temporary = 1; 1738 b->pos = chunk; 1739 b->last = ngx_sprintf(chunk, "%xO" CRLF, size); 1740 1741 tl->next = *fl; 1742 *fl = tl; 1743 } 1744 1745 if (cl->buf->last_buf) { 1746 tl = ngx_chain_get_free_buf(r->pool, &ctx->free); 1747 if (tl == NULL) { 1748 return NGX_ERROR; 1749 } 1750 1751 b = tl->buf; 1752 1753 b->tag = (ngx_buf_tag_t) &ngx_http_proxy_body_output_filter; 1754 b->temporary = 0; 1755 b->memory = 1; 1756 b->last_buf = 1; 1757 b->pos = (u_char *) CRLF "0" CRLF CRLF; 1758 b->last = b->pos + 7; 1759 1760 cl->buf->last_buf = 0; 1761 1762 *ll = tl; 1763 1764 if (size == 0) { 1765 b->pos += 2; 1766 } 1767 1768 } else if (size > 0) { 1769 tl = ngx_chain_get_free_buf(r->pool, &ctx->free); 1770 if (tl == NULL) { 1771 return NGX_ERROR; 1772 } 1773 1774 b = tl->buf; 1775 1776 b->tag = (ngx_buf_tag_t) &ngx_http_proxy_body_output_filter; 1777 b->temporary = 0; 1778 b->memory = 1; 1779 b->pos = (u_char *) CRLF; 1780 b->last = b->pos + 2; 1781 1782 *ll = tl; 1783 1784 } else { 1785 *ll = NULL; 1786 } 1787 1788 out: 1789 1790 rc = ngx_chain_writer(&r->upstream->writer, out); 1791 1792 ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &out, 1793 (ngx_buf_tag_t) &ngx_http_proxy_body_output_filter); 1794 1795 return rc; 1796 } 1797 1798 1799 static ngx_int_t 1800 ngx_http_proxy_process_status_line(ngx_http_request_t *r) 1801 { 1802 size_t len; 1803 ngx_int_t rc; 1804 ngx_http_upstream_t *u; 1805 ngx_http_proxy_ctx_t *ctx; 1806 1807 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module); 1808 1809 if (ctx == NULL) { 1810 return NGX_ERROR; 1811 } 1812 1813 u = r->upstream; 1814 1815 rc = ngx_http_parse_status_line(r, &u->buffer, &ctx->status); 1816 1817 if (rc == NGX_AGAIN) { 1818 return rc; 1819 } 1820 1821 if (rc == NGX_ERROR) { 1822 1823 #if (NGX_HTTP_CACHE) 1824 1825 if (r->cache) { 1826 r->http_version = NGX_HTTP_VERSION_9; 1827 return NGX_OK; 1828 } 1829 1830 #endif 1831 1832 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 1833 "upstream sent no valid HTTP/1.0 header"); 1834 1835 #if 0 1836 if (u->accel) { 1837 return NGX_HTTP_UPSTREAM_INVALID_HEADER; 1838 } 1839 #endif 1840 1841 r->http_version = NGX_HTTP_VERSION_9; 1842 u->state->status = NGX_HTTP_OK; 1843 u->headers_in.connection_close = 1; 1844 1845 return NGX_OK; 1846 } 1847 1848 if (u->state && u->state->status == 0) { 1849 u->state->status = ctx->status.code; 1850 } 1851 1852 u->headers_in.status_n = ctx->status.code; 1853 1854 len = ctx->status.end - ctx->status.start; 1855 u->headers_in.status_line.len = len; 1856 1857 u->headers_in.status_line.data = ngx_pnalloc(r->pool, len); 1858 if (u->headers_in.status_line.data == NULL) { 1859 return NGX_ERROR; 1860 } 1861 1862 ngx_memcpy(u->headers_in.status_line.data, ctx->status.start, len); 1863 1864 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 1865 "http proxy status %ui \"%V\"", 1866 u->headers_in.status_n, &u->headers_in.status_line); 1867 1868 if (ctx->status.http_version < NGX_HTTP_VERSION_11) { 1869 u->headers_in.connection_close = 1; 1870 } 1871 1872 u->process_header = ngx_http_proxy_process_header; 1873 1874 return ngx_http_proxy_process_header(r); 1875 } 1876 1877 1878 static ngx_int_t 1879 ngx_http_proxy_process_header(ngx_http_request_t *r) 1880 { 1881 ngx_int_t rc; 1882 ngx_table_elt_t *h; 1883 ngx_http_upstream_t *u; 1884 ngx_http_proxy_ctx_t *ctx; 1885 ngx_http_upstream_header_t *hh; 1886 ngx_http_upstream_main_conf_t *umcf; 1887 1888 umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module); 1889 1890 for ( ;; ) { 1891 1892 rc = ngx_http_parse_header_line(r, &r->upstream->buffer, 1); 1893 1894 if (rc == NGX_OK) { 1895 1896 /* a header line has been parsed successfully */ 1897 1898 h = ngx_list_push(&r->upstream->headers_in.headers); 1899 if (h == NULL) { 1900 return NGX_ERROR; 1901 } 1902 1903 h->hash = r->header_hash; 1904 1905 h->key.len = r->header_name_end - r->header_name_start; 1906 h->value.len = r->header_end - r->header_start; 1907 1908 h->key.data = ngx_pnalloc(r->pool, 1909 h->key.len + 1 + h->value.len + 1 + h->key.len); 1910 if (h->key.data == NULL) { 1911 h->hash = 0; 1912 return NGX_ERROR; 1913 } 1914 1915 h->value.data = h->key.data + h->key.len + 1; 1916 h->lowcase_key = h->key.data + h->key.len + 1 + h->value.len + 1; 1917 1918 ngx_memcpy(h->key.data, r->header_name_start, h->key.len); 1919 h->key.data[h->key.len] = '\0'; 1920 ngx_memcpy(h->value.data, r->header_start, h->value.len); 1921 h->value.data[h->value.len] = '\0'; 1922 1923 if (h->key.len == r->lowcase_index) { 1924 ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len); 1925 1926 } else { 1927 ngx_strlow(h->lowcase_key, h->key.data, h->key.len); 1928 } 1929 1930 hh = ngx_hash_find(&umcf->headers_in_hash, h->hash, 1931 h->lowcase_key, h->key.len); 1932 1933 if (hh && hh->handler(r, h, hh->offset) != NGX_OK) { 1934 return NGX_ERROR; 1935 } 1936 1937 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 1938 "http proxy header: \"%V: %V\"", 1939 &h->key, &h->value); 1940 1941 continue; 1942 } 1943 1944 if (rc == NGX_HTTP_PARSE_HEADER_DONE) { 1945 1946 /* a whole header has been parsed successfully */ 1947 1948 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 1949 "http proxy header done"); 1950 1951 /* 1952 * if no "Server" and "Date" in header line, 1953 * then add the special empty headers 1954 */ 1955 1956 if (r->upstream->headers_in.server == NULL) { 1957 h = ngx_list_push(&r->upstream->headers_in.headers); 1958 if (h == NULL) { 1959 return NGX_ERROR; 1960 } 1961 1962 h->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash( 1963 ngx_hash('s', 'e'), 'r'), 'v'), 'e'), 'r'); 1964 1965 ngx_str_set(&h->key, "Server"); 1966 ngx_str_null(&h->value); 1967 h->lowcase_key = (u_char *) "server"; 1968 } 1969 1970 if (r->upstream->headers_in.date == NULL) { 1971 h = ngx_list_push(&r->upstream->headers_in.headers); 1972 if (h == NULL) { 1973 return NGX_ERROR; 1974 } 1975 1976 h->hash = ngx_hash(ngx_hash(ngx_hash('d', 'a'), 't'), 'e'); 1977 1978 ngx_str_set(&h->key, "Date"); 1979 ngx_str_null(&h->value); 1980 h->lowcase_key = (u_char *) "date"; 1981 } 1982 1983 /* clear content length if response is chunked */ 1984 1985 u = r->upstream; 1986 1987 if (u->headers_in.chunked) { 1988 u->headers_in.content_length_n = -1; 1989 } 1990 1991 /* 1992 * set u->keepalive if response has no body; this allows to keep 1993 * connections alive in case of r->header_only or X-Accel-Redirect 1994 */ 1995 1996 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module); 1997 1998 if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT 1999 || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED 2000 || ctx->head 2001 || (!u->headers_in.chunked 2002 && u->headers_in.content_length_n == 0)) 2003 { 2004 u->keepalive = !u->headers_in.connection_close; 2005 } 2006 2007 if (u->headers_in.status_n == NGX_HTTP_SWITCHING_PROTOCOLS) { 2008 u->keepalive = 0; 2009 2010 if (r->headers_in.upgrade) { 2011 u->upgrade = 1; 2012 } 2013 } 2014 2015 return NGX_OK; 2016 } 2017 2018 if (rc == NGX_AGAIN) { 2019 return NGX_AGAIN; 2020 } 2021 2022 /* rc == NGX_HTTP_PARSE_INVALID_HEADER */ 2023 2024 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 2025 "upstream sent invalid header: \"%*s\\x%02xd...\"", 2026 r->header_end - r->header_name_start, 2027 r->header_name_start, *r->header_end); 2028 2029 return NGX_HTTP_UPSTREAM_INVALID_HEADER; 2030 } 2031 } 2032 2033 2034 static ngx_int_t 2035 ngx_http_proxy_input_filter_init(void *data) 2036 { 2037 ngx_http_request_t *r = data; 2038 ngx_http_upstream_t *u; 2039 ngx_http_proxy_ctx_t *ctx; 2040 2041 u = r->upstream; 2042 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module); 2043 2044 if (ctx == NULL) { 2045 return NGX_ERROR; 2046 } 2047 2048 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 2049 "http proxy filter init s:%ui h:%d c:%d l:%O", 2050 u->headers_in.status_n, ctx->head, u->headers_in.chunked, 2051 u->headers_in.content_length_n); 2052 2053 /* as per RFC2616, 4.4 Message Length */ 2054 2055 if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT 2056 || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED 2057 || ctx->head) 2058 { 2059 /* 1xx, 204, and 304 and replies to HEAD requests */ 2060 /* no 1xx since we don't send Expect and Upgrade */ 2061 2062 u->pipe->length = 0; 2063 u->length = 0; 2064 u->keepalive = !u->headers_in.connection_close; 2065 2066 } else if (u->headers_in.chunked) { 2067 /* chunked */ 2068 2069 u->pipe->input_filter = ngx_http_proxy_chunked_filter; 2070 u->pipe->length = 3; /* "0" LF LF */ 2071 2072 u->input_filter = ngx_http_proxy_non_buffered_chunked_filter; 2073 u->length = 1; 2074 2075 } else if (u->headers_in.content_length_n == 0) { 2076 /* empty body: special case as filter won't be called */ 2077 2078 u->pipe->length = 0; 2079 u->length = 0; 2080 u->keepalive = !u->headers_in.connection_close; 2081 2082 } else { 2083 /* content length or connection close */ 2084 2085 u->pipe->length = u->headers_in.content_length_n; 2086 u->length = u->headers_in.content_length_n; 2087 } 2088 2089 return NGX_OK; 2090 } 2091 2092 2093 static ngx_int_t 2094 ngx_http_proxy_copy_filter(ngx_event_pipe_t *p, ngx_buf_t *buf) 2095 { 2096 ngx_buf_t *b; 2097 ngx_chain_t *cl; 2098 ngx_http_request_t *r; 2099 2100 if (buf->pos == buf->last) { 2101 return NGX_OK; 2102 } 2103 2104 if (p->upstream_done) { 2105 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0, 2106 "http proxy data after close"); 2107 return NGX_OK; 2108 } 2109 2110 if (p->length == 0) { 2111 2112 ngx_log_error(NGX_LOG_WARN, p->log, 0, 2113 "upstream sent more data than specified in " 2114 "\"Content-Length\" header"); 2115 2116 r = p->input_ctx; 2117 r->upstream->keepalive = 0; 2118 p->upstream_done = 1; 2119 2120 return NGX_OK; 2121 } 2122 2123 cl = ngx_chain_get_free_buf(p->pool, &p->free); 2124 if (cl == NULL) { 2125 return NGX_ERROR; 2126 } 2127 2128 b = cl->buf; 2129 2130 ngx_memcpy(b, buf, sizeof(ngx_buf_t)); 2131 b->shadow = buf; 2132 b->tag = p->tag; 2133 b->last_shadow = 1; 2134 b->recycled = 1; 2135 buf->shadow = b; 2136 2137 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "input buf #%d", b->num); 2138 2139 if (p->in) { 2140 *p->last_in = cl; 2141 } else { 2142 p->in = cl; 2143 } 2144 p->last_in = &cl->next; 2145 2146 if (p->length == -1) { 2147 return NGX_OK; 2148 } 2149 2150 if (b->last - b->pos > p->length) { 2151 2152 ngx_log_error(NGX_LOG_WARN, p->log, 0, 2153 "upstream sent more data than specified in " 2154 "\"Content-Length\" header"); 2155 2156 b->last = b->pos + p->length; 2157 p->upstream_done = 1; 2158 2159 return NGX_OK; 2160 } 2161 2162 p->length -= b->last - b->pos; 2163 2164 if (p->length == 0) { 2165 r = p->input_ctx; 2166 r->upstream->keepalive = !r->upstream->headers_in.connection_close; 2167 } 2168 2169 return NGX_OK; 2170 } 2171 2172 2173 static ngx_int_t 2174 ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf) 2175 { 2176 ngx_int_t rc; 2177 ngx_buf_t *b, **prev; 2178 ngx_chain_t *cl; 2179 ngx_http_request_t *r; 2180 ngx_http_proxy_ctx_t *ctx; 2181 2182 if (buf->pos == buf->last) { 2183 return NGX_OK; 2184 } 2185 2186 r = p->input_ctx; 2187 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module); 2188 2189 if (ctx == NULL) { 2190 return NGX_ERROR; 2191 } 2192 2193 if (p->upstream_done) { 2194 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0, 2195 "http proxy data after close"); 2196 return NGX_OK; 2197 } 2198 2199 if (p->length == 0) { 2200 2201 ngx_log_error(NGX_LOG_WARN, p->log, 0, 2202 "upstream sent data after final chunk"); 2203 2204 r->upstream->keepalive = 0; 2205 p->upstream_done = 1; 2206 2207 return NGX_OK; 2208 } 2209 2210 b = NULL; 2211 prev = &buf->shadow; 2212 2213 for ( ;; ) { 2214 2215 rc = ngx_http_parse_chunked(r, buf, &ctx->chunked); 2216 2217 if (rc == NGX_OK) { 2218 2219 /* a chunk has been parsed successfully */ 2220 2221 cl = ngx_chain_get_free_buf(p->pool, &p->free); 2222 if (cl == NULL) { 2223 return NGX_ERROR; 2224 } 2225 2226 b = cl->buf; 2227 2228 ngx_memzero(b, sizeof(ngx_buf_t)); 2229 2230 b->pos = buf->pos; 2231 b->start = buf->start; 2232 b->end = buf->end; 2233 b->tag = p->tag; 2234 b->temporary = 1; 2235 b->recycled = 1; 2236 2237 *prev = b; 2238 prev = &b->shadow; 2239 2240 if (p->in) { 2241 *p->last_in = cl; 2242 } else { 2243 p->in = cl; 2244 } 2245 p->last_in = &cl->next; 2246 2247 /* STUB */ b->num = buf->num; 2248 2249 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0, 2250 "input buf #%d %p", b->num, b->pos); 2251 2252 if (buf->last - buf->pos >= ctx->chunked.size) { 2253 2254 buf->pos += (size_t) ctx->chunked.size; 2255 b->last = buf->pos; 2256 ctx->chunked.size = 0; 2257 2258 continue; 2259 } 2260 2261 ctx->chunked.size -= buf->last - buf->pos; 2262 buf->pos = buf->last; 2263 b->last = buf->last; 2264 2265 continue; 2266 } 2267 2268 if (rc == NGX_DONE) { 2269 2270 /* a whole response has been parsed successfully */ 2271 2272 p->length = 0; 2273 r->upstream->keepalive = !r->upstream->headers_in.connection_close; 2274 2275 if (buf->pos != buf->last) { 2276 ngx_log_error(NGX_LOG_WARN, p->log, 0, 2277 "upstream sent data after final chunk"); 2278 r->upstream->keepalive = 0; 2279 } 2280 2281 break; 2282 } 2283 2284 if (rc == NGX_AGAIN) { 2285 2286 /* set p->length, minimal amount of data we want to see */ 2287 2288 p->length = ctx->chunked.length; 2289 2290 break; 2291 } 2292 2293 /* invalid response */ 2294 2295 ngx_log_error(NGX_LOG_ERR, p->log, 0, 2296 "upstream sent invalid chunked response"); 2297 2298 return NGX_ERROR; 2299 } 2300 2301 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, p->log, 0, 2302 "http proxy chunked state %ui, length %O", 2303 ctx->chunked.state, p->length); 2304 2305 if (b) { 2306 b->shadow = buf; 2307 b->last_shadow = 1; 2308 2309 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0, 2310 "input buf %p %z", b->pos, b->last - b->pos); 2311 2312 return NGX_OK; 2313 } 2314 2315 /* there is no data record in the buf, add it to free chain */ 2316 2317 if (ngx_event_pipe_add_free_buf(p, buf) != NGX_OK) { 2318 return NGX_ERROR; 2319 } 2320 2321 return NGX_OK; 2322 } 2323 2324 2325 static ngx_int_t 2326 ngx_http_proxy_non_buffered_copy_filter(void *data, ssize_t bytes) 2327 { 2328 ngx_http_request_t *r = data; 2329 2330 ngx_buf_t *b; 2331 ngx_chain_t *cl, **ll; 2332 ngx_http_upstream_t *u; 2333 2334 u = r->upstream; 2335 2336 if (u->length == 0) { 2337 ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, 2338 "upstream sent more data than specified in " 2339 "\"Content-Length\" header"); 2340 u->keepalive = 0; 2341 return NGX_OK; 2342 } 2343 2344 for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) { 2345 ll = &cl->next; 2346 } 2347 2348 cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs); 2349 if (cl == NULL) { 2350 return NGX_ERROR; 2351 } 2352 2353 *ll = cl; 2354 2355 cl->buf->flush = 1; 2356 cl->buf->memory = 1; 2357 2358 b = &u->buffer; 2359 2360 cl->buf->pos = b->last; 2361 b->last += bytes; 2362 cl->buf->last = b->last; 2363 cl->buf->tag = u->output.tag; 2364 2365 if (u->length == -1) { 2366 return NGX_OK; 2367 } 2368 2369 if (bytes > u->length) { 2370 2371 ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, 2372 "upstream sent more data than specified in " 2373 "\"Content-Length\" header"); 2374 2375 cl->buf->last = cl->buf->pos + u->length; 2376 u->length = 0; 2377 2378 return NGX_OK; 2379 } 2380 2381 u->length -= bytes; 2382 2383 if (u->length == 0) { 2384 u->keepalive = !u->headers_in.connection_close; 2385 } 2386 2387 return NGX_OK; 2388 } 2389 2390 2391 static ngx_int_t 2392 ngx_http_proxy_non_buffered_chunked_filter(void *data, ssize_t bytes) 2393 { 2394 ngx_http_request_t *r = data; 2395 2396 ngx_int_t rc; 2397 ngx_buf_t *b, *buf; 2398 ngx_chain_t *cl, **ll; 2399 ngx_http_upstream_t *u; 2400 ngx_http_proxy_ctx_t *ctx; 2401 2402 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module); 2403 2404 if (ctx == NULL) { 2405 return NGX_ERROR; 2406 } 2407 2408 u = r->upstream; 2409 buf = &u->buffer; 2410 2411 buf->pos = buf->last; 2412 buf->last += bytes; 2413 2414 for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) { 2415 ll = &cl->next; 2416 } 2417 2418 for ( ;; ) { 2419 2420 rc = ngx_http_parse_chunked(r, buf, &ctx->chunked); 2421 2422 if (rc == NGX_OK) { 2423 2424 /* a chunk has been parsed successfully */ 2425 2426 cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs); 2427 if (cl == NULL) { 2428 return NGX_ERROR; 2429 } 2430 2431 *ll = cl; 2432 ll = &cl->next; 2433 2434 b = cl->buf; 2435 2436 b->flush = 1; 2437 b->memory = 1; 2438 2439 b->pos = buf->pos; 2440 b->tag = u->output.tag; 2441 2442 if (buf->last - buf->pos >= ctx->chunked.size) { 2443 buf->pos += (size_t) ctx->chunked.size; 2444 b->last = buf->pos; 2445 ctx->chunked.size = 0; 2446 2447 } else { 2448 ctx->chunked.size -= buf->last - buf->pos; 2449 buf->pos = buf->last; 2450 b->last = buf->last; 2451 } 2452 2453 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 2454 "http proxy out buf %p %z", 2455 b->pos, b->last - b->pos); 2456 2457 continue; 2458 } 2459 2460 if (rc == NGX_DONE) { 2461 2462 /* a whole response has been parsed successfully */ 2463 2464 u->keepalive = !u->headers_in.connection_close; 2465 u->length = 0; 2466 2467 if (buf->pos != buf->last) { 2468 ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, 2469 "upstream sent data after final chunk"); 2470 u->keepalive = 0; 2471 } 2472 2473 break; 2474 } 2475 2476 if (rc == NGX_AGAIN) { 2477 break; 2478 } 2479 2480 /* invalid response */ 2481 2482 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 2483 "upstream sent invalid chunked response"); 2484 2485 return NGX_ERROR; 2486 } 2487 2488 return NGX_OK; 2489 } 2490 2491 2492 static void 2493 ngx_http_proxy_abort_request(ngx_http_request_t *r) 2494 { 2495 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 2496 "abort http proxy request"); 2497 2498 return; 2499 } 2500 2501 2502 static void 2503 ngx_http_proxy_finalize_request(ngx_http_request_t *r, ngx_int_t rc) 2504 { 2505 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 2506 "finalize http proxy request"); 2507 2508 return; 2509 } 2510 2511 2512 static ngx_int_t 2513 ngx_http_proxy_host_variable(ngx_http_request_t *r, 2514 ngx_http_variable_value_t *v, uintptr_t data) 2515 { 2516 ngx_http_proxy_ctx_t *ctx; 2517 2518 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module); 2519 2520 if (ctx == NULL) { 2521 v->not_found = 1; 2522 return NGX_OK; 2523 } 2524 2525 v->len = ctx->vars.host_header.len; 2526 v->valid = 1; 2527 v->no_cacheable = 0; 2528 v->not_found = 0; 2529 v->data = ctx->vars.host_header.data; 2530 2531 return NGX_OK; 2532 } 2533 2534 2535 static ngx_int_t 2536 ngx_http_proxy_port_variable(ngx_http_request_t *r, 2537 ngx_http_variable_value_t *v, uintptr_t data) 2538 { 2539 ngx_http_proxy_ctx_t *ctx; 2540 2541 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module); 2542 2543 if (ctx == NULL) { 2544 v->not_found = 1; 2545 return NGX_OK; 2546 } 2547 2548 v->len = ctx->vars.port.len; 2549 v->valid = 1; 2550 v->no_cacheable = 0; 2551 v->not_found = 0; 2552 v->data = ctx->vars.port.data; 2553 2554 return NGX_OK; 2555 } 2556 2557 2558 static ngx_int_t 2559 ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r, 2560 ngx_http_variable_value_t *v, uintptr_t data) 2561 { 2562 size_t len; 2563 u_char *p; 2564 ngx_uint_t i, n; 2565 ngx_table_elt_t **h; 2566 2567 v->valid = 1; 2568 v->no_cacheable = 0; 2569 v->not_found = 0; 2570 2571 n = r->headers_in.x_forwarded_for.nelts; 2572 h = r->headers_in.x_forwarded_for.elts; 2573 2574 len = 0; 2575 2576 for (i = 0; i < n; i++) { 2577 len += h[i]->value.len + sizeof(", ") - 1; 2578 } 2579 2580 if (len == 0) { 2581 v->len = r->connection->addr_text.len; 2582 v->data = r->connection->addr_text.data; 2583 return NGX_OK; 2584 } 2585 2586 len += r->connection->addr_text.len; 2587 2588 p = ngx_pnalloc(r->pool, len); 2589 if (p == NULL) { 2590 return NGX_ERROR; 2591 } 2592 2593 v->len = len; 2594 v->data = p; 2595 2596 for (i = 0; i < n; i++) { 2597 p = ngx_copy(p, h[i]->value.data, h[i]->value.len); 2598 *p++ = ','; *p++ = ' '; 2599 } 2600 2601 ngx_memcpy(p, r->connection->addr_text.data, r->connection->addr_text.len); 2602 2603 return NGX_OK; 2604 } 2605 2606 2607 static ngx_int_t 2608 ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r, 2609 ngx_http_variable_value_t *v, uintptr_t data) 2610 { 2611 ngx_http_proxy_ctx_t *ctx; 2612 2613 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module); 2614 2615 if (ctx == NULL || ctx->internal_body_length < 0) { 2616 v->not_found = 1; 2617 return NGX_OK; 2618 } 2619 2620 v->valid = 1; 2621 v->no_cacheable = 0; 2622 v->not_found = 0; 2623 2624 v->data = ngx_pnalloc(r->pool, NGX_OFF_T_LEN); 2625 2626 if (v->data == NULL) { 2627 return NGX_ERROR; 2628 } 2629 2630 v->len = ngx_sprintf(v->data, "%O", ctx->internal_body_length) - v->data; 2631 2632 return NGX_OK; 2633 } 2634 2635 2636 static ngx_int_t 2637 ngx_http_proxy_internal_chunked_variable(ngx_http_request_t *r, 2638 ngx_http_variable_value_t *v, uintptr_t data) 2639 { 2640 ngx_http_proxy_ctx_t *ctx; 2641 2642 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module); 2643 2644 if (ctx == NULL || !ctx->internal_chunked) { 2645 v->not_found = 1; 2646 return NGX_OK; 2647 } 2648 2649 v->valid = 1; 2650 v->no_cacheable = 0; 2651 v->not_found = 0; 2652 2653 v->data = (u_char *) "chunked"; 2654 v->len = sizeof("chunked") - 1; 2655 2656 return NGX_OK; 2657 } 2658 2659 2660 static ngx_int_t 2661 ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, ngx_table_elt_t *h, 2662 size_t prefix) 2663 { 2664 size_t len; 2665 ngx_int_t rc; 2666 ngx_uint_t i; 2667 ngx_http_proxy_rewrite_t *pr; 2668 ngx_http_proxy_loc_conf_t *plcf; 2669 2670 plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); 2671 2672 pr = plcf->redirects->elts; 2673 2674 if (pr == NULL) { 2675 return NGX_DECLINED; 2676 } 2677 2678 len = h->value.len - prefix; 2679 2680 for (i = 0; i < plcf->redirects->nelts; i++) { 2681 rc = pr[i].handler(r, &h->value, prefix, len, &pr[i]); 2682 2683 if (rc != NGX_DECLINED) { 2684 return rc; 2685 } 2686 } 2687 2688 return NGX_DECLINED; 2689 } 2690 2691 2692 static ngx_int_t 2693 ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r, ngx_table_elt_t *h) 2694 { 2695 u_char *p; 2696 size_t len; 2697 ngx_int_t rc, rv; 2698 ngx_str_t *key, *value; 2699 ngx_uint_t i; 2700 ngx_array_t attrs; 2701 ngx_keyval_t *attr; 2702 ngx_http_proxy_loc_conf_t *plcf; 2703 2704 if (ngx_array_init(&attrs, r->pool, 2, sizeof(ngx_keyval_t)) != NGX_OK) { 2705 return NGX_ERROR; 2706 } 2707 2708 if (ngx_http_proxy_parse_cookie(&h->value, &attrs) != NGX_OK) { 2709 return NGX_ERROR; 2710 } 2711 2712 attr = attrs.elts; 2713 2714 if (attr[0].value.data == NULL) { 2715 return NGX_DECLINED; 2716 } 2717 2718 rv = NGX_DECLINED; 2719 2720 plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); 2721 2722 for (i = 1; i < attrs.nelts; i++) { 2723 2724 key = &attr[i].key; 2725 value = &attr[i].value; 2726 2727 if (plcf->cookie_domains && key->len == 6 2728 && ngx_strncasecmp(key->data, (u_char *) "domain", 6) == 0 2729 && value->data) 2730 { 2731 rc = ngx_http_proxy_rewrite_cookie_value(r, value, 2732 plcf->cookie_domains); 2733 if (rc == NGX_ERROR) { 2734 return NGX_ERROR; 2735 } 2736 2737 if (rc != NGX_DECLINED) { 2738 rv = rc; 2739 } 2740 } 2741 2742 if (plcf->cookie_paths && key->len == 4 2743 && ngx_strncasecmp(key->data, (u_char *) "path", 4) == 0 2744 && value->data) 2745 { 2746 rc = ngx_http_proxy_rewrite_cookie_value(r, value, 2747 plcf->cookie_paths); 2748 if (rc == NGX_ERROR) { 2749 return NGX_ERROR; 2750 } 2751 2752 if (rc != NGX_DECLINED) { 2753 rv = rc; 2754 } 2755 } 2756 } 2757 2758 if (plcf->cookie_flags) { 2759 rc = ngx_http_proxy_rewrite_cookie_flags(r, &attrs, 2760 plcf->cookie_flags); 2761 if (rc == NGX_ERROR) { 2762 return NGX_ERROR; 2763 } 2764 2765 if (rc != NGX_DECLINED) { 2766 rv = rc; 2767 } 2768 2769 attr = attrs.elts; 2770 } 2771 2772 if (rv != NGX_OK) { 2773 return rv; 2774 } 2775 2776 len = 0; 2777 2778 for (i = 0; i < attrs.nelts; i++) { 2779 2780 if (attr[i].key.data == NULL) { 2781 continue; 2782 } 2783 2784 if (i > 0) { 2785 len += 2; 2786 } 2787 2788 len += attr[i].key.len; 2789 2790 if (attr[i].value.data) { 2791 len += 1 + attr[i].value.len; 2792 } 2793 } 2794 2795 p = ngx_pnalloc(r->pool, len + 1); 2796 if (p == NULL) { 2797 return NGX_ERROR; 2798 } 2799 2800 h->value.data = p; 2801 h->value.len = len; 2802 2803 for (i = 0; i < attrs.nelts; i++) { 2804 2805 if (attr[i].key.data == NULL) { 2806 continue; 2807 } 2808 2809 if (i > 0) { 2810 *p++ = ';'; 2811 *p++ = ' '; 2812 } 2813 2814 p = ngx_cpymem(p, attr[i].key.data, attr[i].key.len); 2815 2816 if (attr[i].value.data) { 2817 *p++ = '='; 2818 p = ngx_cpymem(p, attr[i].value.data, attr[i].value.len); 2819 } 2820 } 2821 2822 *p = '\0'; 2823 2824 return NGX_OK; 2825 } 2826 2827 2828 static ngx_int_t 2829 ngx_http_proxy_parse_cookie(ngx_str_t *value, ngx_array_t *attrs) 2830 { 2831 u_char *start, *end, *p, *last; 2832 ngx_str_t name, val; 2833 ngx_keyval_t *attr; 2834 2835 start = value->data; 2836 end = value->data + value->len; 2837 2838 for ( ;; ) { 2839 2840 last = (u_char *) ngx_strchr(start, ';'); 2841 2842 if (last == NULL) { 2843 last = end; 2844 } 2845 2846 while (start < last && *start == ' ') { start++; } 2847 2848 for (p = start; p < last && *p != '='; p++) { /* void */ } 2849 2850 name.data = start; 2851 name.len = p - start; 2852 2853 while (name.len && name.data[name.len - 1] == ' ') { 2854 name.len--; 2855 } 2856 2857 if (p < last) { 2858 2859 p++; 2860 2861 while (p < last && *p == ' ') { p++; } 2862 2863 val.data = p; 2864 val.len = last - val.data; 2865 2866 while (val.len && val.data[val.len - 1] == ' ') { 2867 val.len--; 2868 } 2869 2870 } else { 2871 ngx_str_null(&val); 2872 } 2873 2874 attr = ngx_array_push(attrs); 2875 if (attr == NULL) { 2876 return NGX_ERROR; 2877 } 2878 2879 attr->key = name; 2880 attr->value = val; 2881 2882 if (last == end) { 2883 break; 2884 } 2885 2886 start = last + 1; 2887 } 2888 2889 return NGX_OK; 2890 } 2891 2892 2893 static ngx_int_t 2894 ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r, ngx_str_t *value, 2895 ngx_array_t *rewrites) 2896 { 2897 ngx_int_t rc; 2898 ngx_uint_t i; 2899 ngx_http_proxy_rewrite_t *pr; 2900 2901 pr = rewrites->elts; 2902 2903 for (i = 0; i < rewrites->nelts; i++) { 2904 rc = pr[i].handler(r, value, 0, value->len, &pr[i]); 2905 2906 if (rc != NGX_DECLINED) { 2907 return rc; 2908 } 2909 } 2910 2911 return NGX_DECLINED; 2912 } 2913 2914 2915 static ngx_int_t 2916 ngx_http_proxy_rewrite_cookie_flags(ngx_http_request_t *r, ngx_array_t *attrs, 2917 ngx_array_t *flags) 2918 { 2919 ngx_str_t pattern, value; 2920 #if (NGX_PCRE) 2921 ngx_int_t rc; 2922 #endif 2923 ngx_uint_t i, m, f, nelts; 2924 ngx_keyval_t *attr; 2925 ngx_conf_bitmask_t *mask; 2926 ngx_http_complex_value_t *flags_values; 2927 ngx_http_proxy_cookie_flags_t *pcf; 2928 2929 attr = attrs->elts; 2930 pcf = flags->elts; 2931 2932 for (i = 0; i < flags->nelts; i++) { 2933 2934 #if (NGX_PCRE) 2935 if (pcf[i].regex) { 2936 rc = ngx_http_regex_exec(r, pcf[i].cookie.regex, &attr[0].key); 2937 2938 if (rc == NGX_ERROR) { 2939 return NGX_ERROR; 2940 } 2941 2942 if (rc == NGX_OK) { 2943 break; 2944 } 2945 2946 /* NGX_DECLINED */ 2947 2948 continue; 2949 } 2950 #endif 2951 2952 if (ngx_http_complex_value(r, &pcf[i].cookie.complex, &pattern) 2953 != NGX_OK) 2954 { 2955 return NGX_ERROR; 2956 } 2957 2958 if (pattern.len == attr[0].key.len 2959 && ngx_strncasecmp(attr[0].key.data, pattern.data, pattern.len) 2960 == 0) 2961 { 2962 break; 2963 } 2964 } 2965 2966 if (i == flags->nelts) { 2967 return NGX_DECLINED; 2968 } 2969 2970 nelts = pcf[i].flags_values.nelts; 2971 flags_values = pcf[i].flags_values.elts; 2972 2973 mask = ngx_http_proxy_cookie_flags_masks; 2974 f = 0; 2975 2976 for (i = 0; i < nelts; i++) { 2977 2978 if (ngx_http_complex_value(r, &flags_values[i], &value) != NGX_OK) { 2979 return NGX_ERROR; 2980 } 2981 2982 if (value.len == 0) { 2983 continue; 2984 } 2985 2986 for (m = 0; mask[m].name.len != 0; m++) { 2987 2988 if (mask[m].name.len != value.len 2989 || ngx_strncasecmp(mask[m].name.data, value.data, value.len) 2990 != 0) 2991 { 2992 continue; 2993 } 2994 2995 f |= mask[m].mask; 2996 2997 break; 2998 } 2999 3000 if (mask[m].name.len == 0) { 3001 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 3002 "invalid proxy_cookie_flags flag \"%V\"", &value); 3003 } 3004 } 3005 3006 if (f == 0) { 3007 return NGX_DECLINED; 3008 } 3009 3010 return ngx_http_proxy_edit_cookie_flags(r, attrs, f); 3011 } 3012 3013 3014 static ngx_int_t 3015 ngx_http_proxy_edit_cookie_flags(ngx_http_request_t *r, ngx_array_t *attrs, 3016 ngx_uint_t flags) 3017 { 3018 ngx_str_t *key, *value; 3019 ngx_uint_t i; 3020 ngx_keyval_t *attr; 3021 3022 attr = attrs->elts; 3023 3024 for (i = 1; i < attrs->nelts; i++) { 3025 key = &attr[i].key; 3026 3027 if (key->len == 6 3028 && ngx_strncasecmp(key->data, (u_char *) "secure", 6) == 0) 3029 { 3030 if (flags & NGX_HTTP_PROXY_COOKIE_SECURE_ON) { 3031 flags &= ~NGX_HTTP_PROXY_COOKIE_SECURE_ON; 3032 3033 } else if (flags & NGX_HTTP_PROXY_COOKIE_SECURE_OFF) { 3034 key->data = NULL; 3035 } 3036 3037 continue; 3038 } 3039 3040 if (key->len == 8 3041 && ngx_strncasecmp(key->data, (u_char *) "httponly", 8) == 0) 3042 { 3043 if (flags & NGX_HTTP_PROXY_COOKIE_HTTPONLY_ON) { 3044 flags &= ~NGX_HTTP_PROXY_COOKIE_HTTPONLY_ON; 3045 3046 } else if (flags & NGX_HTTP_PROXY_COOKIE_HTTPONLY_OFF) { 3047 key->data = NULL; 3048 } 3049 3050 continue; 3051 } 3052 3053 if (key->len == 8 3054 && ngx_strncasecmp(key->data, (u_char *) "samesite", 8) == 0) 3055 { 3056 value = &attr[i].value; 3057 3058 if (flags & NGX_HTTP_PROXY_COOKIE_SAMESITE_STRICT) { 3059 flags &= ~NGX_HTTP_PROXY_COOKIE_SAMESITE_STRICT; 3060 3061 if (value->len != 6 3062 || ngx_strncasecmp(value->data, (u_char *) "strict", 6) 3063 != 0) 3064 { 3065 ngx_str_set(key, "SameSite"); 3066 ngx_str_set(value, "Strict"); 3067 } 3068 3069 } else if (flags & NGX_HTTP_PROXY_COOKIE_SAMESITE_LAX) { 3070 flags &= ~NGX_HTTP_PROXY_COOKIE_SAMESITE_LAX; 3071 3072 if (value->len != 3 3073 || ngx_strncasecmp(value->data, (u_char *) "lax", 3) != 0) 3074 { 3075 ngx_str_set(key, "SameSite"); 3076 ngx_str_set(value, "Lax"); 3077 } 3078 3079 } else if (flags & NGX_HTTP_PROXY_COOKIE_SAMESITE_NONE) { 3080 flags &= ~NGX_HTTP_PROXY_COOKIE_SAMESITE_NONE; 3081 3082 if (value->len != 4 3083 || ngx_strncasecmp(value->data, (u_char *) "none", 4) != 0) 3084 { 3085 ngx_str_set(key, "SameSite"); 3086 ngx_str_set(value, "None"); 3087 } 3088 3089 } else if (flags & NGX_HTTP_PROXY_COOKIE_SAMESITE_OFF) { 3090 key->data = NULL; 3091 } 3092 3093 continue; 3094 } 3095 } 3096 3097 if (flags & NGX_HTTP_PROXY_COOKIE_SECURE_ON) { 3098 attr = ngx_array_push(attrs); 3099 if (attr == NULL) { 3100 return NGX_ERROR; 3101 } 3102 3103 ngx_str_set(&attr->key, "Secure"); 3104 ngx_str_null(&attr->value); 3105 } 3106 3107 if (flags & NGX_HTTP_PROXY_COOKIE_HTTPONLY_ON) { 3108 attr = ngx_array_push(attrs); 3109 if (attr == NULL) { 3110 return NGX_ERROR; 3111 } 3112 3113 ngx_str_set(&attr->key, "HttpOnly"); 3114 ngx_str_null(&attr->value); 3115 } 3116 3117 if (flags & (NGX_HTTP_PROXY_COOKIE_SAMESITE_STRICT 3118 |NGX_HTTP_PROXY_COOKIE_SAMESITE_LAX 3119 |NGX_HTTP_PROXY_COOKIE_SAMESITE_NONE)) 3120 { 3121 attr = ngx_array_push(attrs); 3122 if (attr == NULL) { 3123 return NGX_ERROR; 3124 } 3125 3126 ngx_str_set(&attr->key, "SameSite"); 3127 3128 if (flags & NGX_HTTP_PROXY_COOKIE_SAMESITE_STRICT) { 3129 ngx_str_set(&attr->value, "Strict"); 3130 3131 } else if (flags & NGX_HTTP_PROXY_COOKIE_SAMESITE_LAX) { 3132 ngx_str_set(&attr->value, "Lax"); 3133 3134 } else { 3135 ngx_str_set(&attr->value, "None"); 3136 } 3137 } 3138 3139 return NGX_OK; 3140 } 3141 3142 3143 static ngx_int_t 3144 ngx_http_proxy_rewrite_complex_handler(ngx_http_request_t *r, ngx_str_t *value, 3145 size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr) 3146 { 3147 ngx_str_t pattern, replacement; 3148 3149 if (ngx_http_complex_value(r, &pr->pattern.complex, &pattern) != NGX_OK) { 3150 return NGX_ERROR; 3151 } 3152 3153 if (pattern.len > len 3154 || ngx_rstrncmp(value->data + prefix, pattern.data, pattern.len) != 0) 3155 { 3156 return NGX_DECLINED; 3157 } 3158 3159 if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) { 3160 return NGX_ERROR; 3161 } 3162 3163 return ngx_http_proxy_rewrite(r, value, prefix, pattern.len, &replacement); 3164 } 3165 3166 3167 #if (NGX_PCRE) 3168 3169 static ngx_int_t 3170 ngx_http_proxy_rewrite_regex_handler(ngx_http_request_t *r, ngx_str_t *value, 3171 size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr) 3172 { 3173 ngx_str_t pattern, replacement; 3174 3175 pattern.len = len; 3176 pattern.data = value->data + prefix; 3177 3178 if (ngx_http_regex_exec(r, pr->pattern.regex, &pattern) != NGX_OK) { 3179 return NGX_DECLINED; 3180 } 3181 3182 if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) { 3183 return NGX_ERROR; 3184 } 3185 3186 return ngx_http_proxy_rewrite(r, value, prefix, len, &replacement); 3187 } 3188 3189 #endif 3190 3191 3192 static ngx_int_t 3193 ngx_http_proxy_rewrite_domain_handler(ngx_http_request_t *r, ngx_str_t *value, 3194 size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr) 3195 { 3196 u_char *p; 3197 ngx_str_t pattern, replacement; 3198 3199 if (ngx_http_complex_value(r, &pr->pattern.complex, &pattern) != NGX_OK) { 3200 return NGX_ERROR; 3201 } 3202 3203 p = value->data + prefix; 3204 3205 if (len && p[0] == '.') { 3206 p++; 3207 prefix++; 3208 len--; 3209 } 3210 3211 if (pattern.len != len || ngx_rstrncasecmp(pattern.data, p, len) != 0) { 3212 return NGX_DECLINED; 3213 } 3214 3215 if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) { 3216 return NGX_ERROR; 3217 } 3218 3219 return ngx_http_proxy_rewrite(r, value, prefix, len, &replacement); 3220 } 3221 3222 3223 static ngx_int_t 3224 ngx_http_proxy_rewrite(ngx_http_request_t *r, ngx_str_t *value, size_t prefix, 3225 size_t len, ngx_str_t *replacement) 3226 { 3227 u_char *p, *data; 3228 size_t new_len; 3229 3230 if (len == value->len) { 3231 *value = *replacement; 3232 return NGX_OK; 3233 } 3234 3235 new_len = replacement->len + value->len - len; 3236 3237 if (replacement->len > len) { 3238 3239 data = ngx_pnalloc(r->pool, new_len + 1); 3240 if (data == NULL) { 3241 return NGX_ERROR; 3242 } 3243 3244 p = ngx_copy(data, value->data, prefix); 3245 p = ngx_copy(p, replacement->data, replacement->len); 3246 3247 ngx_memcpy(p, value->data + prefix + len, 3248 value->len - len - prefix + 1); 3249 3250 value->data = data; 3251 3252 } else { 3253 p = ngx_copy(value->data + prefix, replacement->data, replacement->len); 3254 3255 ngx_memmove(p, value->data + prefix + len, 3256 value->len - len - prefix + 1); 3257 } 3258 3259 value->len = new_len; 3260 3261 return NGX_OK; 3262 } 3263 3264 3265 static ngx_int_t 3266 ngx_http_proxy_add_variables(ngx_conf_t *cf) 3267 { 3268 ngx_http_variable_t *var, *v; 3269 3270 for (v = ngx_http_proxy_vars; v->name.len; v++) { 3271 var = ngx_http_add_variable(cf, &v->name, v->flags); 3272 if (var == NULL) { 3273 return NGX_ERROR; 3274 } 3275 3276 var->get_handler = v->get_handler; 3277 var->data = v->data; 3278 } 3279 3280 return NGX_OK; 3281 } 3282 3283 3284 static void * 3285 ngx_http_proxy_create_main_conf(ngx_conf_t *cf) 3286 { 3287 ngx_http_proxy_main_conf_t *conf; 3288 3289 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_main_conf_t)); 3290 if (conf == NULL) { 3291 return NULL; 3292 } 3293 3294 #if (NGX_HTTP_CACHE) 3295 if (ngx_array_init(&conf->caches, cf->pool, 4, 3296 sizeof(ngx_http_file_cache_t *)) 3297 != NGX_OK) 3298 { 3299 return NULL; 3300 } 3301 #endif 3302 3303 return conf; 3304 } 3305 3306 3307 static void * 3308 ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) 3309 { 3310 ngx_http_proxy_loc_conf_t *conf; 3311 3312 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_loc_conf_t)); 3313 if (conf == NULL) { 3314 return NULL; 3315 } 3316 3317 /* 3318 * set by ngx_pcalloc(): 3319 * 3320 * conf->upstream.bufs.num = 0; 3321 * conf->upstream.ignore_headers = 0; 3322 * conf->upstream.next_upstream = 0; 3323 * conf->upstream.cache_zone = NULL; 3324 * conf->upstream.cache_use_stale = 0; 3325 * conf->upstream.cache_methods = 0; 3326 * conf->upstream.temp_path = NULL; 3327 * conf->upstream.hide_headers_hash = { NULL, 0 }; 3328 * conf->upstream.store_lengths = NULL; 3329 * conf->upstream.store_values = NULL; 3330 * 3331 * conf->location = NULL; 3332 * conf->url = { 0, NULL }; 3333 * conf->headers.lengths = NULL; 3334 * conf->headers.values = NULL; 3335 * conf->headers.hash = { NULL, 0 }; 3336 * conf->headers_cache.lengths = NULL; 3337 * conf->headers_cache.values = NULL; 3338 * conf->headers_cache.hash = { NULL, 0 }; 3339 * conf->body_lengths = NULL; 3340 * conf->body_values = NULL; 3341 * conf->body_source = { 0, NULL }; 3342 * conf->redirects = NULL; 3343 * conf->ssl = 0; 3344 * conf->ssl_protocols = 0; 3345 * conf->ssl_ciphers = { 0, NULL }; 3346 * conf->ssl_trusted_certificate = { 0, NULL }; 3347 * conf->ssl_crl = { 0, NULL }; 3348 */ 3349 3350 conf->upstream.store = NGX_CONF_UNSET; 3351 conf->upstream.store_access = NGX_CONF_UNSET_UINT; 3352 conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT; 3353 conf->upstream.buffering = NGX_CONF_UNSET; 3354 conf->upstream.request_buffering = NGX_CONF_UNSET; 3355 conf->upstream.ignore_client_abort = NGX_CONF_UNSET; 3356 conf->upstream.force_ranges = NGX_CONF_UNSET; 3357 3358 conf->upstream.local = NGX_CONF_UNSET_PTR; 3359 conf->upstream.socket_keepalive = NGX_CONF_UNSET; 3360 3361 conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC; 3362 conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC; 3363 conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC; 3364 conf->upstream.next_upstream_timeout = NGX_CONF_UNSET_MSEC; 3365 3366 conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE; 3367 conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE; 3368 conf->upstream.limit_rate = NGX_CONF_UNSET_SIZE; 3369 3370 conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE; 3371 conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE; 3372 conf->upstream.temp_file_write_size_conf = NGX_CONF_UNSET_SIZE; 3373 3374 conf->upstream.pass_request_headers = NGX_CONF_UNSET; 3375 conf->upstream.pass_request_body = NGX_CONF_UNSET; 3376 3377 #if (NGX_HTTP_CACHE) 3378 conf->upstream.cache = NGX_CONF_UNSET; 3379 conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT; 3380 conf->upstream.cache_max_range_offset = NGX_CONF_UNSET; 3381 conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR; 3382 conf->upstream.no_cache = NGX_CONF_UNSET_PTR; 3383 conf->upstream.cache_valid = NGX_CONF_UNSET_PTR; 3384 conf->upstream.cache_lock = NGX_CONF_UNSET; 3385 conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC; 3386 conf->upstream.cache_lock_age = NGX_CONF_UNSET_MSEC; 3387 conf->upstream.cache_revalidate = NGX_CONF_UNSET; 3388 conf->upstream.cache_convert_head = NGX_CONF_UNSET; 3389 conf->upstream.cache_background_update = NGX_CONF_UNSET; 3390 #endif 3391 3392 conf->upstream.hide_headers = NGX_CONF_UNSET_PTR; 3393 conf->upstream.pass_headers = NGX_CONF_UNSET_PTR; 3394 3395 conf->upstream.intercept_errors = NGX_CONF_UNSET; 3396 3397 #if (NGX_HTTP_SSL) 3398 conf->upstream.ssl_session_reuse = NGX_CONF_UNSET; 3399 conf->upstream.ssl_name = NGX_CONF_UNSET_PTR; 3400 conf->upstream.ssl_server_name = NGX_CONF_UNSET; 3401 conf->upstream.ssl_verify = NGX_CONF_UNSET; 3402 conf->upstream.ssl_certificate = NGX_CONF_UNSET_PTR; 3403 conf->upstream.ssl_certificate_key = NGX_CONF_UNSET_PTR; 3404 conf->upstream.ssl_passwords = NGX_CONF_UNSET_PTR; 3405 conf->ssl_verify_depth = NGX_CONF_UNSET_UINT; 3406 conf->ssl_conf_commands = NGX_CONF_UNSET_PTR; 3407 #endif 3408 3409 /* "proxy_cyclic_temp_file" is disabled */ 3410 conf->upstream.cyclic_temp_file = 0; 3411 3412 conf->upstream.change_buffering = 1; 3413 3414 conf->headers_source = NGX_CONF_UNSET_PTR; 3415 3416 conf->method = NGX_CONF_UNSET_PTR; 3417 3418 conf->redirect = NGX_CONF_UNSET; 3419 3420 conf->cookie_domains = NGX_CONF_UNSET_PTR; 3421 conf->cookie_paths = NGX_CONF_UNSET_PTR; 3422 conf->cookie_flags = NGX_CONF_UNSET_PTR; 3423 3424 conf->http_version = NGX_CONF_UNSET_UINT; 3425 3426 conf->headers_hash_max_size = NGX_CONF_UNSET_UINT; 3427 conf->headers_hash_bucket_size = NGX_CONF_UNSET_UINT; 3428 3429 ngx_str_set(&conf->upstream.module, "proxy"); 3430 3431 return conf; 3432 } 3433 3434 3435 static char * 3436 ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) 3437 { 3438 ngx_http_proxy_loc_conf_t *prev = parent; 3439 ngx_http_proxy_loc_conf_t *conf = child; 3440 3441 u_char *p; 3442 size_t size; 3443 ngx_int_t rc; 3444 ngx_hash_init_t hash; 3445 ngx_http_core_loc_conf_t *clcf; 3446 ngx_http_proxy_rewrite_t *pr; 3447 ngx_http_script_compile_t sc; 3448 3449 #if (NGX_HTTP_CACHE) 3450 3451 if (conf->upstream.store > 0) { 3452 conf->upstream.cache = 0; 3453 } 3454 3455 if (conf->upstream.cache > 0) { 3456 conf->upstream.store = 0; 3457 } 3458 3459 #endif 3460 3461 if (conf->upstream.store == NGX_CONF_UNSET) { 3462 ngx_conf_merge_value(conf->upstream.store, 3463 prev->upstream.store, 0); 3464 3465 conf->upstream.store_lengths = prev->upstream.store_lengths; 3466 conf->upstream.store_values = prev->upstream.store_values; 3467 } 3468 3469 ngx_conf_merge_uint_value(conf->upstream.store_access, 3470 prev->upstream.store_access, 0600); 3471 3472 ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries, 3473 prev->upstream.next_upstream_tries, 0); 3474 3475 ngx_conf_merge_value(conf->upstream.buffering, 3476 prev->upstream.buffering, 1); 3477 3478 ngx_conf_merge_value(conf->upstream.request_buffering, 3479 prev->upstream.request_buffering, 1); 3480 3481 ngx_conf_merge_value(conf->upstream.ignore_client_abort, 3482 prev->upstream.ignore_client_abort, 0); 3483 3484 ngx_conf_merge_value(conf->upstream.force_ranges, 3485 prev->upstream.force_ranges, 0); 3486 3487 ngx_conf_merge_ptr_value(conf->upstream.local, 3488 prev->upstream.local, NULL); 3489 3490 ngx_conf_merge_value(conf->upstream.socket_keepalive, 3491 prev->upstream.socket_keepalive, 0); 3492 3493 ngx_conf_merge_msec_value(conf->upstream.connect_timeout, 3494 prev->upstream.connect_timeout, 60000); 3495 3496 ngx_conf_merge_msec_value(conf->upstream.send_timeout, 3497 prev->upstream.send_timeout, 60000); 3498 3499 ngx_conf_merge_msec_value(conf->upstream.read_timeout, 3500 prev->upstream.read_timeout, 60000); 3501 3502 ngx_conf_merge_msec_value(conf->upstream.next_upstream_timeout, 3503 prev->upstream.next_upstream_timeout, 0); 3504 3505 ngx_conf_merge_size_value(conf->upstream.send_lowat, 3506 prev->upstream.send_lowat, 0); 3507 3508 ngx_conf_merge_size_value(conf->upstream.buffer_size, 3509 prev->upstream.buffer_size, 3510 (size_t) ngx_pagesize); 3511 3512 ngx_conf_merge_size_value(conf->upstream.limit_rate, 3513 prev->upstream.limit_rate, 0); 3514 3515 ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs, 3516 8, ngx_pagesize); 3517 3518 if (conf->upstream.bufs.num < 2) { 3519 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 3520 "there must be at least 2 \"proxy_buffers\""); 3521 return NGX_CONF_ERROR; 3522 } 3523 3524 3525 size = conf->upstream.buffer_size; 3526 if (size < conf->upstream.bufs.size) { 3527 size = conf->upstream.bufs.size; 3528 } 3529 3530 3531 ngx_conf_merge_size_value(conf->upstream.busy_buffers_size_conf, 3532 prev->upstream.busy_buffers_size_conf, 3533 NGX_CONF_UNSET_SIZE); 3534 3535 if (conf->upstream.busy_buffers_size_conf == NGX_CONF_UNSET_SIZE) { 3536 conf->upstream.busy_buffers_size = 2 * size; 3537 } else { 3538 conf->upstream.busy_buffers_size = 3539 conf->upstream.busy_buffers_size_conf; 3540 } 3541 3542 if (conf->upstream.busy_buffers_size < size) { 3543 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 3544 "\"proxy_busy_buffers_size\" must be equal to or greater than " 3545 "the maximum of the value of \"proxy_buffer_size\" and " 3546 "one of the \"proxy_buffers\""); 3547 3548 return NGX_CONF_ERROR; 3549 } 3550 3551 if (conf->upstream.busy_buffers_size 3552 > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size) 3553 { 3554 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 3555 "\"proxy_busy_buffers_size\" must be less than " 3556 "the size of all \"proxy_buffers\" minus one buffer"); 3557 3558 return NGX_CONF_ERROR; 3559 } 3560 3561 3562 ngx_conf_merge_size_value(conf->upstream.temp_file_write_size_conf, 3563 prev->upstream.temp_file_write_size_conf, 3564 NGX_CONF_UNSET_SIZE); 3565 3566 if (conf->upstream.temp_file_write_size_conf == NGX_CONF_UNSET_SIZE) { 3567 conf->upstream.temp_file_write_size = 2 * size; 3568 } else { 3569 conf->upstream.temp_file_write_size = 3570 conf->upstream.temp_file_write_size_conf; 3571 } 3572 3573 if (conf->upstream.temp_file_write_size < size) { 3574 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 3575 "\"proxy_temp_file_write_size\" must be equal to or greater " 3576 "than the maximum of the value of \"proxy_buffer_size\" and " 3577 "one of the \"proxy_buffers\""); 3578 3579 return NGX_CONF_ERROR; 3580 } 3581 3582 ngx_conf_merge_size_value(conf->upstream.max_temp_file_size_conf, 3583 prev->upstream.max_temp_file_size_conf, 3584 NGX_CONF_UNSET_SIZE); 3585 3586 if (conf->upstream.max_temp_file_size_conf == NGX_CONF_UNSET_SIZE) { 3587 conf->upstream.max_temp_file_size = 1024 * 1024 * 1024; 3588 } else { 3589 conf->upstream.max_temp_file_size = 3590 conf->upstream.max_temp_file_size_conf; 3591 } 3592 3593 if (conf->upstream.max_temp_file_size != 0 3594 && conf->upstream.max_temp_file_size < size) 3595 { 3596 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 3597 "\"proxy_max_temp_file_size\" must be equal to zero to disable " 3598 "temporary files usage or must be equal to or greater than " 3599 "the maximum of the value of \"proxy_buffer_size\" and " 3600 "one of the \"proxy_buffers\""); 3601 3602 return NGX_CONF_ERROR; 3603 } 3604 3605 3606 ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers, 3607 prev->upstream.ignore_headers, 3608 NGX_CONF_BITMASK_SET); 3609 3610 3611 ngx_conf_merge_bitmask_value(conf->upstream.next_upstream, 3612 prev->upstream.next_upstream, 3613 (NGX_CONF_BITMASK_SET 3614 |NGX_HTTP_UPSTREAM_FT_ERROR 3615 |NGX_HTTP_UPSTREAM_FT_TIMEOUT)); 3616 3617 if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) { 3618 conf->upstream.next_upstream = NGX_CONF_BITMASK_SET 3619 |NGX_HTTP_UPSTREAM_FT_OFF; 3620 } 3621 3622 if (ngx_conf_merge_path_value(cf, &conf->upstream.temp_path, 3623 prev->upstream.temp_path, 3624 &ngx_http_proxy_temp_path) 3625 != NGX_OK) 3626 { 3627 return NGX_CONF_ERROR; 3628 } 3629 3630 3631 #if (NGX_HTTP_CACHE) 3632 3633 if (conf->upstream.cache == NGX_CONF_UNSET) { 3634 ngx_conf_merge_value(conf->upstream.cache, 3635 prev->upstream.cache, 0); 3636 3637 conf->upstream.cache_zone = prev->upstream.cache_zone; 3638 conf->upstream.cache_value = prev->upstream.cache_value; 3639 } 3640 3641 if (conf->upstream.cache_zone && conf->upstream.cache_zone->data == NULL) { 3642 ngx_shm_zone_t *shm_zone; 3643 3644 shm_zone = conf->upstream.cache_zone; 3645 3646 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 3647 "\"proxy_cache\" zone \"%V\" is unknown", 3648 &shm_zone->shm.name); 3649 3650 return NGX_CONF_ERROR; 3651 } 3652 3653 ngx_conf_merge_uint_value(conf->upstream.cache_min_uses, 3654 prev->upstream.cache_min_uses, 1); 3655 3656 ngx_conf_merge_off_value(conf->upstream.cache_max_range_offset, 3657 prev->upstream.cache_max_range_offset, 3658 NGX_MAX_OFF_T_VALUE); 3659 3660 ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale, 3661 prev->upstream.cache_use_stale, 3662 (NGX_CONF_BITMASK_SET 3663 |NGX_HTTP_UPSTREAM_FT_OFF)); 3664 3665 if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_OFF) { 3666 conf->upstream.cache_use_stale = NGX_CONF_BITMASK_SET 3667 |NGX_HTTP_UPSTREAM_FT_OFF; 3668 } 3669 3670 if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_ERROR) { 3671 conf->upstream.cache_use_stale |= NGX_HTTP_UPSTREAM_FT_NOLIVE; 3672 } 3673 3674 if (conf->upstream.cache_methods == 0) { 3675 conf->upstream.cache_methods = prev->upstream.cache_methods; 3676 } 3677 3678 conf->upstream.cache_methods |= NGX_HTTP_GET|NGX_HTTP_HEAD; 3679 3680 ngx_conf_merge_ptr_value(conf->upstream.cache_bypass, 3681 prev->upstream.cache_bypass, NULL); 3682 3683 ngx_conf_merge_ptr_value(conf->upstream.no_cache, 3684 prev->upstream.no_cache, NULL); 3685 3686 ngx_conf_merge_ptr_value(conf->upstream.cache_valid, 3687 prev->upstream.cache_valid, NULL); 3688 3689 if (conf->cache_key.value.data == NULL) { 3690 conf->cache_key = prev->cache_key; 3691 } 3692 3693 ngx_conf_merge_value(conf->upstream.cache_lock, 3694 prev->upstream.cache_lock, 0); 3695 3696 ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout, 3697 prev->upstream.cache_lock_timeout, 5000); 3698 3699 ngx_conf_merge_msec_value(conf->upstream.cache_lock_age, 3700 prev->upstream.cache_lock_age, 5000); 3701 3702 ngx_conf_merge_value(conf->upstream.cache_revalidate, 3703 prev->upstream.cache_revalidate, 0); 3704 3705 ngx_conf_merge_value(conf->upstream.cache_convert_head, 3706 prev->upstream.cache_convert_head, 1); 3707 3708 ngx_conf_merge_value(conf->upstream.cache_background_update, 3709 prev->upstream.cache_background_update, 0); 3710 3711 #endif 3712 3713 ngx_conf_merge_value(conf->upstream.pass_request_headers, 3714 prev->upstream.pass_request_headers, 1); 3715 ngx_conf_merge_value(conf->upstream.pass_request_body, 3716 prev->upstream.pass_request_body, 1); 3717 3718 ngx_conf_merge_value(conf->upstream.intercept_errors, 3719 prev->upstream.intercept_errors, 0); 3720 3721 #if (NGX_HTTP_SSL) 3722 3723 ngx_conf_merge_value(conf->upstream.ssl_session_reuse, 3724 prev->upstream.ssl_session_reuse, 1); 3725 3726 ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols, 3727 (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1 3728 |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)); 3729 3730 ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, 3731 "DEFAULT"); 3732 3733 ngx_conf_merge_ptr_value(conf->upstream.ssl_name, 3734 prev->upstream.ssl_name, NULL); 3735 ngx_conf_merge_value(conf->upstream.ssl_server_name, 3736 prev->upstream.ssl_server_name, 0); 3737 ngx_conf_merge_value(conf->upstream.ssl_verify, 3738 prev->upstream.ssl_verify, 0); 3739 ngx_conf_merge_uint_value(conf->ssl_verify_depth, 3740 prev->ssl_verify_depth, 1); 3741 ngx_conf_merge_str_value(conf->ssl_trusted_certificate, 3742 prev->ssl_trusted_certificate, ""); 3743 ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, ""); 3744 3745 ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate, 3746 prev->upstream.ssl_certificate, NULL); 3747 ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate_key, 3748 prev->upstream.ssl_certificate_key, NULL); 3749 ngx_conf_merge_ptr_value(conf->upstream.ssl_passwords, 3750 prev->upstream.ssl_passwords, NULL); 3751 3752 ngx_conf_merge_ptr_value(conf->ssl_conf_commands, 3753 prev->ssl_conf_commands, NULL); 3754 3755 if (conf->ssl && ngx_http_proxy_set_ssl(cf, conf) != NGX_OK) { 3756 return NGX_CONF_ERROR; 3757 } 3758 3759 #endif 3760 3761 ngx_conf_merge_ptr_value(conf->method, prev->method, NULL); 3762 3763 ngx_conf_merge_value(conf->redirect, prev->redirect, 1); 3764 3765 if (conf->redirect) { 3766 3767 if (conf->redirects == NULL) { 3768 conf->redirects = prev->redirects; 3769 } 3770 3771 if (conf->redirects == NULL && conf->url.data) { 3772 3773 conf->redirects = ngx_array_create(cf->pool, 1, 3774 sizeof(ngx_http_proxy_rewrite_t)); 3775 if (conf->redirects == NULL) { 3776 return NGX_CONF_ERROR; 3777 } 3778 3779 pr = ngx_array_push(conf->redirects); 3780 if (pr == NULL) { 3781 return NGX_CONF_ERROR; 3782 } 3783 3784 ngx_memzero(&pr->pattern.complex, 3785 sizeof(ngx_http_complex_value_t)); 3786 3787 ngx_memzero(&pr->replacement, sizeof(ngx_http_complex_value_t)); 3788 3789 pr->handler = ngx_http_proxy_rewrite_complex_handler; 3790 3791 if (conf->vars.uri.len) { 3792 pr->pattern.complex.value = conf->url; 3793 pr->replacement.value = conf->location; 3794 3795 } else { 3796 pr->pattern.complex.value.len = conf->url.len 3797 + sizeof("/") - 1; 3798 3799 p = ngx_pnalloc(cf->pool, pr->pattern.complex.value.len); 3800 if (p == NULL) { 3801 return NGX_CONF_ERROR; 3802 } 3803 3804 pr->pattern.complex.value.data = p; 3805 3806 p = ngx_cpymem(p, conf->url.data, conf->url.len); 3807 *p = '/'; 3808 3809 ngx_str_set(&pr->replacement.value, "/"); 3810 } 3811 } 3812 } 3813 3814 ngx_conf_merge_ptr_value(conf->cookie_domains, prev->cookie_domains, NULL); 3815 3816 ngx_conf_merge_ptr_value(conf->cookie_paths, prev->cookie_paths, NULL); 3817 3818 ngx_conf_merge_ptr_value(conf->cookie_flags, prev->cookie_flags, NULL); 3819 3820 ngx_conf_merge_uint_value(conf->http_version, prev->http_version, 3821 NGX_HTTP_VERSION_10); 3822 3823 ngx_conf_merge_uint_value(conf->headers_hash_max_size, 3824 prev->headers_hash_max_size, 512); 3825 3826 ngx_conf_merge_uint_value(conf->headers_hash_bucket_size, 3827 prev->headers_hash_bucket_size, 64); 3828 3829 conf->headers_hash_bucket_size = ngx_align(conf->headers_hash_bucket_size, 3830 ngx_cacheline_size); 3831 3832 hash.max_size = conf->headers_hash_max_size; 3833 hash.bucket_size = conf->headers_hash_bucket_size; 3834 hash.name = "proxy_headers_hash"; 3835 3836 if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream, 3837 &prev->upstream, ngx_http_proxy_hide_headers, &hash) 3838 != NGX_OK) 3839 { 3840 return NGX_CONF_ERROR; 3841 } 3842 3843 clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); 3844 3845 if (clcf->noname 3846 && conf->upstream.upstream == NULL && conf->proxy_lengths == NULL) 3847 { 3848 conf->upstream.upstream = prev->upstream.upstream; 3849 conf->location = prev->location; 3850 conf->vars = prev->vars; 3851 3852 conf->proxy_lengths = prev->proxy_lengths; 3853 conf->proxy_values = prev->proxy_values; 3854 3855 #if (NGX_HTTP_SSL) 3856 conf->upstream.ssl = prev->upstream.ssl; 3857 #endif 3858 } 3859 3860 if (clcf->lmt_excpt && clcf->handler == NULL 3861 && (conf->upstream.upstream || conf->proxy_lengths)) 3862 { 3863 clcf->handler = ngx_http_proxy_handler; 3864 } 3865 3866 if (conf->body_source.data == NULL) { 3867 conf->body_flushes = prev->body_flushes; 3868 conf->body_source = prev->body_source; 3869 conf->body_lengths = prev->body_lengths; 3870 conf->body_values = prev->body_values; 3871 } 3872 3873 if (conf->body_source.data && conf->body_lengths == NULL) { 3874 3875 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); 3876 3877 sc.cf = cf; 3878 sc.source = &conf->body_source; 3879 sc.flushes = &conf->body_flushes; 3880 sc.lengths = &conf->body_lengths; 3881 sc.values = &conf->body_values; 3882 sc.complete_lengths = 1; 3883 sc.complete_values = 1; 3884 3885 if (ngx_http_script_compile(&sc) != NGX_OK) { 3886 return NGX_CONF_ERROR; 3887 } 3888 } 3889 3890 ngx_conf_merge_ptr_value(conf->headers_source, prev->headers_source, NULL); 3891 3892 if (conf->headers_source == prev->headers_source) { 3893 conf->headers = prev->headers; 3894 #if (NGX_HTTP_CACHE) 3895 conf->headers_cache = prev->headers_cache; 3896 #endif 3897 } 3898 3899 rc = ngx_http_proxy_init_headers(cf, conf, &conf->headers, 3900 ngx_http_proxy_headers); 3901 if (rc != NGX_OK) { 3902 return NGX_CONF_ERROR; 3903 } 3904 3905 #if (NGX_HTTP_CACHE) 3906 3907 if (conf->upstream.cache) { 3908 rc = ngx_http_proxy_init_headers(cf, conf, &conf->headers_cache, 3909 ngx_http_proxy_cache_headers); 3910 if (rc != NGX_OK) { 3911 return NGX_CONF_ERROR; 3912 } 3913 } 3914 3915 #endif 3916 3917 /* 3918 * special handling to preserve conf->headers in the "http" section 3919 * to inherit it to all servers 3920 */ 3921 3922 if (prev->headers.hash.buckets == NULL 3923 && conf->headers_source == prev->headers_source) 3924 { 3925 prev->headers = conf->headers; 3926 #if (NGX_HTTP_CACHE) 3927 prev->headers_cache = conf->headers_cache; 3928 #endif 3929 } 3930 3931 return NGX_CONF_OK; 3932 } 3933 3934 3935 static ngx_int_t 3936 ngx_http_proxy_init_headers(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf, 3937 ngx_http_proxy_headers_t *headers, ngx_keyval_t *default_headers) 3938 { 3939 u_char *p; 3940 size_t size; 3941 uintptr_t *code; 3942 ngx_uint_t i; 3943 ngx_array_t headers_names, headers_merged; 3944 ngx_keyval_t *src, *s, *h; 3945 ngx_hash_key_t *hk; 3946 ngx_hash_init_t hash; 3947 ngx_http_script_compile_t sc; 3948 ngx_http_script_copy_code_t *copy; 3949 3950 if (headers->hash.buckets) { 3951 return NGX_OK; 3952 } 3953 3954 if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t)) 3955 != NGX_OK) 3956 { 3957 return NGX_ERROR; 3958 } 3959 3960 if (ngx_array_init(&headers_merged, cf->temp_pool, 4, sizeof(ngx_keyval_t)) 3961 != NGX_OK) 3962 { 3963 return NGX_ERROR; 3964 } 3965 3966 headers->lengths = ngx_array_create(cf->pool, 64, 1); 3967 if (headers->lengths == NULL) { 3968 return NGX_ERROR; 3969 } 3970 3971 headers->values = ngx_array_create(cf->pool, 512, 1); 3972 if (headers->values == NULL) { 3973 return NGX_ERROR; 3974 } 3975 3976 if (conf->headers_source) { 3977 3978 src = conf->headers_source->elts; 3979 for (i = 0; i < conf->headers_source->nelts; i++) { 3980 3981 s = ngx_array_push(&headers_merged); 3982 if (s == NULL) { 3983 return NGX_ERROR; 3984 } 3985 3986 *s = src[i]; 3987 } 3988 } 3989 3990 h = default_headers; 3991 3992 while (h->key.len) { 3993 3994 src = headers_merged.elts; 3995 for (i = 0; i < headers_merged.nelts; i++) { 3996 if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) { 3997 goto next; 3998 } 3999 } 4000 4001 s = ngx_array_push(&headers_merged); 4002 if (s == NULL) { 4003 return NGX_ERROR; 4004 } 4005 4006 *s = *h; 4007 4008 next: 4009 4010 h++; 4011 } 4012 4013 4014 src = headers_merged.elts; 4015 for (i = 0; i < headers_merged.nelts; i++) { 4016 4017 hk = ngx_array_push(&headers_names); 4018 if (hk == NULL) { 4019 return NGX_ERROR; 4020 } 4021 4022 hk->key = src[i].key; 4023 hk->key_hash = ngx_hash_key_lc(src[i].key.data, src[i].key.len); 4024 hk->value = (void *) 1; 4025 4026 if (src[i].value.len == 0) { 4027 continue; 4028 } 4029 4030 copy = ngx_array_push_n(headers->lengths, 4031 sizeof(ngx_http_script_copy_code_t)); 4032 if (copy == NULL) { 4033 return NGX_ERROR; 4034 } 4035 4036 copy->code = (ngx_http_script_code_pt) (void *) 4037 ngx_http_script_copy_len_code; 4038 copy->len = src[i].key.len; 4039 4040 size = (sizeof(ngx_http_script_copy_code_t) 4041 + src[i].key.len + sizeof(uintptr_t) - 1) 4042 & ~(sizeof(uintptr_t) - 1); 4043 4044 copy = ngx_array_push_n(headers->values, size); 4045 if (copy == NULL) { 4046 return NGX_ERROR; 4047 } 4048 4049 copy->code = ngx_http_script_copy_code; 4050 copy->len = src[i].key.len; 4051 4052 p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t); 4053 ngx_memcpy(p, src[i].key.data, src[i].key.len); 4054 4055 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); 4056 4057 sc.cf = cf; 4058 sc.source = &src[i].value; 4059 sc.flushes = &headers->flushes; 4060 sc.lengths = &headers->lengths; 4061 sc.values = &headers->values; 4062 4063 if (ngx_http_script_compile(&sc) != NGX_OK) { 4064 return NGX_ERROR; 4065 } 4066 4067 code = ngx_array_push_n(headers->lengths, sizeof(uintptr_t)); 4068 if (code == NULL) { 4069 return NGX_ERROR; 4070 } 4071 4072 *code = (uintptr_t) NULL; 4073 4074 code = ngx_array_push_n(headers->values, sizeof(uintptr_t)); 4075 if (code == NULL) { 4076 return NGX_ERROR; 4077 } 4078 4079 *code = (uintptr_t) NULL; 4080 } 4081 4082 code = ngx_array_push_n(headers->lengths, sizeof(uintptr_t)); 4083 if (code == NULL) { 4084 return NGX_ERROR; 4085 } 4086 4087 *code = (uintptr_t) NULL; 4088 4089 4090 hash.hash = &headers->hash; 4091 hash.key = ngx_hash_key_lc; 4092 hash.max_size = conf->headers_hash_max_size; 4093 hash.bucket_size = conf->headers_hash_bucket_size; 4094 hash.name = "proxy_headers_hash"; 4095 hash.pool = cf->pool; 4096 hash.temp_pool = NULL; 4097 4098 return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts); 4099 } 4100 4101 4102 static char * 4103 ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 4104 { 4105 ngx_http_proxy_loc_conf_t *plcf = conf; 4106 4107 size_t add; 4108 u_short port; 4109 ngx_str_t *value, *url; 4110 ngx_url_t u; 4111 ngx_uint_t n; 4112 ngx_http_core_loc_conf_t *clcf; 4113 ngx_http_script_compile_t sc; 4114 4115 if (plcf->upstream.upstream || plcf->proxy_lengths) { 4116 return "is duplicate"; 4117 } 4118 4119 clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); 4120 4121 clcf->handler = ngx_http_proxy_handler; 4122 4123 if (clcf->name.len && clcf->name.data[clcf->name.len - 1] == '/') { 4124 clcf->auto_redirect = 1; 4125 } 4126 4127 value = cf->args->elts; 4128 4129 url = &value[1]; 4130 4131 n = ngx_http_script_variables_count(url); 4132 4133 if (n) { 4134 4135 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); 4136 4137 sc.cf = cf; 4138 sc.source = url; 4139 sc.lengths = &plcf->proxy_lengths; 4140 sc.values = &plcf->proxy_values; 4141 sc.variables = n; 4142 sc.complete_lengths = 1; 4143 sc.complete_values = 1; 4144 4145 if (ngx_http_script_compile(&sc) != NGX_OK) { 4146 return NGX_CONF_ERROR; 4147 } 4148 4149 #if (NGX_HTTP_SSL) 4150 plcf->ssl = 1; 4151 #endif 4152 4153 return NGX_CONF_OK; 4154 } 4155 4156 if (ngx_strncasecmp(url->data, (u_char *) "http://", 7) == 0) { 4157 add = 7; 4158 port = 80; 4159 4160 } else if (ngx_strncasecmp(url->data, (u_char *) "https://", 8) == 0) { 4161 4162 #if (NGX_HTTP_SSL) 4163 plcf->ssl = 1; 4164 4165 add = 8; 4166 port = 443; 4167 #else 4168 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 4169 "https protocol requires SSL support"); 4170 return NGX_CONF_ERROR; 4171 #endif 4172 4173 } else { 4174 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid URL prefix"); 4175 return NGX_CONF_ERROR; 4176 } 4177 4178 ngx_memzero(&u, sizeof(ngx_url_t)); 4179 4180 u.url.len = url->len - add; 4181 u.url.data = url->data + add; 4182 u.default_port = port; 4183 u.uri_part = 1; 4184 u.no_resolve = 1; 4185 4186 plcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0); 4187 if (plcf->upstream.upstream == NULL) { 4188 return NGX_CONF_ERROR; 4189 } 4190 4191 plcf->vars.schema.len = add; 4192 plcf->vars.schema.data = url->data; 4193 plcf->vars.key_start = plcf->vars.schema; 4194 4195 ngx_http_proxy_set_vars(&u, &plcf->vars); 4196 4197 plcf->location = clcf->name; 4198 4199 if (clcf->named 4200 #if (NGX_PCRE) 4201 || clcf->regex 4202 #endif 4203 || clcf->noname) 4204 { 4205 if (plcf->vars.uri.len) { 4206 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 4207 "\"proxy_pass\" cannot have URI part in " 4208 "location given by regular expression, " 4209 "or inside named location, " 4210 "or inside \"if\" statement, " 4211 "or inside \"limit_except\" block"); 4212 return NGX_CONF_ERROR; 4213 } 4214 4215 plcf->location.len = 0; 4216 } 4217 4218 plcf->url = *url; 4219 4220 return NGX_CONF_OK; 4221 } 4222 4223 4224 static char * 4225 ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 4226 { 4227 ngx_http_proxy_loc_conf_t *plcf = conf; 4228 4229 u_char *p; 4230 ngx_str_t *value; 4231 ngx_http_proxy_rewrite_t *pr; 4232 ngx_http_compile_complex_value_t ccv; 4233 4234 if (plcf->redirect == 0) { 4235 return "is duplicate"; 4236 } 4237 4238 plcf->redirect = 1; 4239 4240 value = cf->args->elts; 4241 4242 if (cf->args->nelts == 2) { 4243 if (ngx_strcmp(value[1].data, "off") == 0) { 4244 4245 if (plcf->redirects) { 4246 return "is duplicate"; 4247 } 4248 4249 plcf->redirect = 0; 4250 return NGX_CONF_OK; 4251 } 4252 4253 if (ngx_strcmp(value[1].data, "default") != 0) { 4254 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 4255 "invalid parameter \"%V\"", &value[1]); 4256 return NGX_CONF_ERROR; 4257 } 4258 } 4259 4260 if (plcf->redirects == NULL) { 4261 plcf->redirects = ngx_array_create(cf->pool, 1, 4262 sizeof(ngx_http_proxy_rewrite_t)); 4263 if (plcf->redirects == NULL) { 4264 return NGX_CONF_ERROR; 4265 } 4266 } 4267 4268 pr = ngx_array_push(plcf->redirects); 4269 if (pr == NULL) { 4270 return NGX_CONF_ERROR; 4271 } 4272 4273 if (cf->args->nelts == 2 4274 && ngx_strcmp(value[1].data, "default") == 0) 4275 { 4276 if (plcf->proxy_lengths) { 4277 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 4278 "\"proxy_redirect default\" cannot be used " 4279 "with \"proxy_pass\" directive with variables"); 4280 return NGX_CONF_ERROR; 4281 } 4282 4283 if (plcf->url.data == NULL) { 4284 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 4285 "\"proxy_redirect default\" should be placed " 4286 "after the \"proxy_pass\" directive"); 4287 return NGX_CONF_ERROR; 4288 } 4289 4290 pr->handler = ngx_http_proxy_rewrite_complex_handler; 4291 4292 ngx_memzero(&pr->pattern.complex, sizeof(ngx_http_complex_value_t)); 4293 4294 ngx_memzero(&pr->replacement, sizeof(ngx_http_complex_value_t)); 4295 4296 if (plcf->vars.uri.len) { 4297 pr->pattern.complex.value = plcf->url; 4298 pr->replacement.value = plcf->location; 4299 4300 } else { 4301 pr->pattern.complex.value.len = plcf->url.len + sizeof("/") - 1; 4302 4303 p = ngx_pnalloc(cf->pool, pr->pattern.complex.value.len); 4304 if (p == NULL) { 4305 return NGX_CONF_ERROR; 4306 } 4307 4308 pr->pattern.complex.value.data = p; 4309 4310 p = ngx_cpymem(p, plcf->url.data, plcf->url.len); 4311 *p = '/'; 4312 4313 ngx_str_set(&pr->replacement.value, "/"); 4314 } 4315 4316 return NGX_CONF_OK; 4317 } 4318 4319 4320 if (value[1].data[0] == '~') { 4321 value[1].len--; 4322 value[1].data++; 4323 4324 if (value[1].data[0] == '*') { 4325 value[1].len--; 4326 value[1].data++; 4327 4328 if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) { 4329 return NGX_CONF_ERROR; 4330 } 4331 4332 } else { 4333 if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 0) != NGX_OK) { 4334 return NGX_CONF_ERROR; 4335 } 4336 } 4337 4338 } else { 4339 4340 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); 4341 4342 ccv.cf = cf; 4343 ccv.value = &value[1]; 4344 ccv.complex_value = &pr->pattern.complex; 4345 4346 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { 4347 return NGX_CONF_ERROR; 4348 } 4349 4350 pr->handler = ngx_http_proxy_rewrite_complex_handler; 4351 } 4352 4353 4354 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); 4355 4356 ccv.cf = cf; 4357 ccv.value = &value[2]; 4358 ccv.complex_value = &pr->replacement; 4359 4360 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { 4361 return NGX_CONF_ERROR; 4362 } 4363 4364 return NGX_CONF_OK; 4365 } 4366 4367 4368 static char * 4369 ngx_http_proxy_cookie_domain(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 4370 { 4371 ngx_http_proxy_loc_conf_t *plcf = conf; 4372 4373 ngx_str_t *value; 4374 ngx_http_proxy_rewrite_t *pr; 4375 ngx_http_compile_complex_value_t ccv; 4376 4377 if (plcf->cookie_domains == NULL) { 4378 return "is duplicate"; 4379 } 4380 4381 value = cf->args->elts; 4382 4383 if (cf->args->nelts == 2) { 4384 4385 if (ngx_strcmp(value[1].data, "off") == 0) { 4386 4387 if (plcf->cookie_domains != NGX_CONF_UNSET_PTR) { 4388 return "is duplicate"; 4389 } 4390 4391 plcf->cookie_domains = NULL; 4392 return NGX_CONF_OK; 4393 } 4394 4395 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 4396 "invalid parameter \"%V\"", &value[1]); 4397 return NGX_CONF_ERROR; 4398 } 4399 4400 if (plcf->cookie_domains == NGX_CONF_UNSET_PTR) { 4401 plcf->cookie_domains = ngx_array_create(cf->pool, 1, 4402 sizeof(ngx_http_proxy_rewrite_t)); 4403 if (plcf->cookie_domains == NULL) { 4404 return NGX_CONF_ERROR; 4405 } 4406 } 4407 4408 pr = ngx_array_push(plcf->cookie_domains); 4409 if (pr == NULL) { 4410 return NGX_CONF_ERROR; 4411 } 4412 4413 if (value[1].data[0] == '~') { 4414 value[1].len--; 4415 value[1].data++; 4416 4417 if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) { 4418 return NGX_CONF_ERROR; 4419 } 4420 4421 } else { 4422 4423 if (value[1].data[0] == '.') { 4424 value[1].len--; 4425 value[1].data++; 4426 } 4427 4428 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); 4429 4430 ccv.cf = cf; 4431 ccv.value = &value[1]; 4432 ccv.complex_value = &pr->pattern.complex; 4433 4434 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { 4435 return NGX_CONF_ERROR; 4436 } 4437 4438 pr->handler = ngx_http_proxy_rewrite_domain_handler; 4439 4440 if (value[2].data[0] == '.') { 4441 value[2].len--; 4442 value[2].data++; 4443 } 4444 } 4445 4446 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); 4447 4448 ccv.cf = cf; 4449 ccv.value = &value[2]; 4450 ccv.complex_value = &pr->replacement; 4451 4452 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { 4453 return NGX_CONF_ERROR; 4454 } 4455 4456 return NGX_CONF_OK; 4457 } 4458 4459 4460 static char * 4461 ngx_http_proxy_cookie_path(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 4462 { 4463 ngx_http_proxy_loc_conf_t *plcf = conf; 4464 4465 ngx_str_t *value; 4466 ngx_http_proxy_rewrite_t *pr; 4467 ngx_http_compile_complex_value_t ccv; 4468 4469 if (plcf->cookie_paths == NULL) { 4470 return "is duplicate"; 4471 } 4472 4473 value = cf->args->elts; 4474 4475 if (cf->args->nelts == 2) { 4476 4477 if (ngx_strcmp(value[1].data, "off") == 0) { 4478 4479 if (plcf->cookie_paths != NGX_CONF_UNSET_PTR) { 4480 return "is duplicate"; 4481 } 4482 4483 plcf->cookie_paths = NULL; 4484 return NGX_CONF_OK; 4485 } 4486 4487 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 4488 "invalid parameter \"%V\"", &value[1]); 4489 return NGX_CONF_ERROR; 4490 } 4491 4492 if (plcf->cookie_paths == NGX_CONF_UNSET_PTR) { 4493 plcf->cookie_paths = ngx_array_create(cf->pool, 1, 4494 sizeof(ngx_http_proxy_rewrite_t)); 4495 if (plcf->cookie_paths == NULL) { 4496 return NGX_CONF_ERROR; 4497 } 4498 } 4499 4500 pr = ngx_array_push(plcf->cookie_paths); 4501 if (pr == NULL) { 4502 return NGX_CONF_ERROR; 4503 } 4504 4505 if (value[1].data[0] == '~') { 4506 value[1].len--; 4507 value[1].data++; 4508 4509 if (value[1].data[0] == '*') { 4510 value[1].len--; 4511 value[1].data++; 4512 4513 if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) { 4514 return NGX_CONF_ERROR; 4515 } 4516 4517 } else { 4518 if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 0) != NGX_OK) { 4519 return NGX_CONF_ERROR; 4520 } 4521 } 4522 4523 } else { 4524 4525 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); 4526 4527 ccv.cf = cf; 4528 ccv.value = &value[1]; 4529 ccv.complex_value = &pr->pattern.complex; 4530 4531 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { 4532 return NGX_CONF_ERROR; 4533 } 4534 4535 pr->handler = ngx_http_proxy_rewrite_complex_handler; 4536 } 4537 4538 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); 4539 4540 ccv.cf = cf; 4541 ccv.value = &value[2]; 4542 ccv.complex_value = &pr->replacement; 4543 4544 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { 4545 return NGX_CONF_ERROR; 4546 } 4547 4548 return NGX_CONF_OK; 4549 } 4550 4551 4552 static char * 4553 ngx_http_proxy_cookie_flags(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 4554 { 4555 ngx_http_proxy_loc_conf_t *plcf = conf; 4556 4557 ngx_str_t *value; 4558 ngx_uint_t i; 4559 ngx_http_complex_value_t *cv; 4560 ngx_http_proxy_cookie_flags_t *pcf; 4561 ngx_http_compile_complex_value_t ccv; 4562 #if (NGX_PCRE) 4563 ngx_regex_compile_t rc; 4564 u_char errstr[NGX_MAX_CONF_ERRSTR]; 4565 #endif 4566 4567 if (plcf->cookie_flags == NULL) { 4568 return "is duplicate"; 4569 } 4570 4571 value = cf->args->elts; 4572 4573 if (cf->args->nelts == 2) { 4574 4575 if (ngx_strcmp(value[1].data, "off") == 0) { 4576 4577 if (plcf->cookie_flags != NGX_CONF_UNSET_PTR) { 4578 return "is duplicate"; 4579 } 4580 4581 plcf->cookie_flags = NULL; 4582 return NGX_CONF_OK; 4583 } 4584 4585 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 4586 "invalid parameter \"%V\"", &value[1]); 4587 return NGX_CONF_ERROR; 4588 } 4589 4590 if (plcf->cookie_flags == NGX_CONF_UNSET_PTR) { 4591 plcf->cookie_flags = ngx_array_create(cf->pool, 1, 4592 sizeof(ngx_http_proxy_cookie_flags_t)); 4593 if (plcf->cookie_flags == NULL) { 4594 return NGX_CONF_ERROR; 4595 } 4596 } 4597 4598 pcf = ngx_array_push(plcf->cookie_flags); 4599 if (pcf == NULL) { 4600 return NGX_CONF_ERROR; 4601 } 4602 4603 pcf->regex = 0; 4604 4605 if (value[1].data[0] == '~') { 4606 value[1].len--; 4607 value[1].data++; 4608 4609 #if (NGX_PCRE) 4610 ngx_memzero(&rc, sizeof(ngx_regex_compile_t)); 4611 4612 rc.pattern = value[1]; 4613 rc.err.len = NGX_MAX_CONF_ERRSTR; 4614 rc.err.data = errstr; 4615 rc.options = NGX_REGEX_CASELESS; 4616 4617 pcf->cookie.regex = ngx_http_regex_compile(cf, &rc); 4618 if (pcf->cookie.regex == NULL) { 4619 return NGX_CONF_ERROR; 4620 } 4621 4622 pcf->regex = 1; 4623 #else 4624 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 4625 "using regex \"%V\" requires PCRE library", 4626 &value[1]); 4627 return NGX_CONF_ERROR; 4628 #endif 4629 4630 } else { 4631 4632 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); 4633 4634 ccv.cf = cf; 4635 ccv.value = &value[1]; 4636 ccv.complex_value = &pcf->cookie.complex; 4637 4638 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { 4639 return NGX_CONF_ERROR; 4640 } 4641 } 4642 4643 if (ngx_array_init(&pcf->flags_values, cf->pool, cf->args->nelts - 2, 4644 sizeof(ngx_http_complex_value_t)) 4645 != NGX_OK) 4646 { 4647 return NGX_CONF_ERROR; 4648 } 4649 4650 for (i = 2; i < cf->args->nelts; i++) { 4651 4652 cv = ngx_array_push(&pcf->flags_values); 4653 if (cv == NULL) { 4654 return NGX_CONF_ERROR; 4655 } 4656 4657 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); 4658 4659 ccv.cf = cf; 4660 ccv.value = &value[i]; 4661 ccv.complex_value = cv; 4662 4663 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { 4664 return NGX_CONF_ERROR; 4665 } 4666 } 4667 4668 return NGX_CONF_OK; 4669 } 4670 4671 4672 static ngx_int_t 4673 ngx_http_proxy_rewrite_regex(ngx_conf_t *cf, ngx_http_proxy_rewrite_t *pr, 4674 ngx_str_t *regex, ngx_uint_t caseless) 4675 { 4676 #if (NGX_PCRE) 4677 u_char errstr[NGX_MAX_CONF_ERRSTR]; 4678 ngx_regex_compile_t rc; 4679 4680 ngx_memzero(&rc, sizeof(ngx_regex_compile_t)); 4681 4682 rc.pattern = *regex; 4683 rc.err.len = NGX_MAX_CONF_ERRSTR; 4684 rc.err.data = errstr; 4685 4686 if (caseless) { 4687 rc.options = NGX_REGEX_CASELESS; 4688 } 4689 4690 pr->pattern.regex = ngx_http_regex_compile(cf, &rc); 4691 if (pr->pattern.regex == NULL) { 4692 return NGX_ERROR; 4693 } 4694 4695 pr->handler = ngx_http_proxy_rewrite_regex_handler; 4696 4697 return NGX_OK; 4698 4699 #else 4700 4701 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 4702 "using regex \"%V\" requires PCRE library", regex); 4703 return NGX_ERROR; 4704 4705 #endif 4706 } 4707 4708 4709 static char * 4710 ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 4711 { 4712 ngx_http_proxy_loc_conf_t *plcf = conf; 4713 4714 ngx_str_t *value; 4715 ngx_http_script_compile_t sc; 4716 4717 if (plcf->upstream.store != NGX_CONF_UNSET) { 4718 return "is duplicate"; 4719 } 4720 4721 value = cf->args->elts; 4722 4723 if (ngx_strcmp(value[1].data, "off") == 0) { 4724 plcf->upstream.store = 0; 4725 return NGX_CONF_OK; 4726 } 4727 4728 #if (NGX_HTTP_CACHE) 4729 if (plcf->upstream.cache > 0) { 4730 return "is incompatible with \"proxy_cache\""; 4731 } 4732 #endif 4733 4734 plcf->upstream.store = 1; 4735 4736 if (ngx_strcmp(value[1].data, "on") == 0) { 4737 return NGX_CONF_OK; 4738 } 4739 4740 /* include the terminating '\0' into script */ 4741 value[1].len++; 4742 4743 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); 4744 4745 sc.cf = cf; 4746 sc.source = &value[1]; 4747 sc.lengths = &plcf->upstream.store_lengths; 4748 sc.values = &plcf->upstream.store_values; 4749 sc.variables = ngx_http_script_variables_count(&value[1]); 4750 sc.complete_lengths = 1; 4751 sc.complete_values = 1; 4752 4753 if (ngx_http_script_compile(&sc) != NGX_OK) { 4754 return NGX_CONF_ERROR; 4755 } 4756 4757 return NGX_CONF_OK; 4758 } 4759 4760 4761 #if (NGX_HTTP_CACHE) 4762 4763 static char * 4764 ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 4765 { 4766 ngx_http_proxy_loc_conf_t *plcf = conf; 4767 4768 ngx_str_t *value; 4769 ngx_http_complex_value_t cv; 4770 ngx_http_compile_complex_value_t ccv; 4771 4772 value = cf->args->elts; 4773 4774 if (plcf->upstream.cache != NGX_CONF_UNSET) { 4775 return "is duplicate"; 4776 } 4777 4778 if (ngx_strcmp(value[1].data, "off") == 0) { 4779 plcf->upstream.cache = 0; 4780 return NGX_CONF_OK; 4781 } 4782 4783 if (plcf->upstream.store > 0) { 4784 return "is incompatible with \"proxy_store\""; 4785 } 4786 4787 plcf->upstream.cache = 1; 4788 4789 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); 4790 4791 ccv.cf = cf; 4792 ccv.value = &value[1]; 4793 ccv.complex_value = &cv; 4794 4795 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { 4796 return NGX_CONF_ERROR; 4797 } 4798 4799 if (cv.lengths != NULL) { 4800 4801 plcf->upstream.cache_value = ngx_palloc(cf->pool, 4802 sizeof(ngx_http_complex_value_t)); 4803 if (plcf->upstream.cache_value == NULL) { 4804 return NGX_CONF_ERROR; 4805 } 4806 4807 *plcf->upstream.cache_value = cv; 4808 4809 return NGX_CONF_OK; 4810 } 4811 4812 plcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0, 4813 &ngx_http_proxy_module); 4814 if (plcf->upstream.cache_zone == NULL) { 4815 return NGX_CONF_ERROR; 4816 } 4817 4818 return NGX_CONF_OK; 4819 } 4820 4821 4822 static char * 4823 ngx_http_proxy_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 4824 { 4825 ngx_http_proxy_loc_conf_t *plcf = conf; 4826 4827 ngx_str_t *value; 4828 ngx_http_compile_complex_value_t ccv; 4829 4830 value = cf->args->elts; 4831 4832 if (plcf->cache_key.value.data) { 4833 return "is duplicate"; 4834 } 4835 4836 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); 4837 4838 ccv.cf = cf; 4839 ccv.value = &value[1]; 4840 ccv.complex_value = &plcf->cache_key; 4841 4842 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { 4843 return NGX_CONF_ERROR; 4844 } 4845 4846 return NGX_CONF_OK; 4847 } 4848 4849 #endif 4850 4851 4852 #if (NGX_HTTP_SSL) 4853 4854 static char * 4855 ngx_http_proxy_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 4856 { 4857 ngx_http_proxy_loc_conf_t *plcf = conf; 4858 4859 ngx_str_t *value; 4860 4861 if (plcf->upstream.ssl_passwords != NGX_CONF_UNSET_PTR) { 4862 return "is duplicate"; 4863 } 4864 4865 value = cf->args->elts; 4866 4867 plcf->upstream.ssl_passwords = ngx_ssl_read_password_file(cf, &value[1]); 4868 4869 if (plcf->upstream.ssl_passwords == NULL) { 4870 return NGX_CONF_ERROR; 4871 } 4872 4873 return NGX_CONF_OK; 4874 } 4875 4876 #endif 4877 4878 4879 static char * 4880 ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data) 4881 { 4882 #if (NGX_FREEBSD) 4883 ssize_t *np = data; 4884 4885 if ((u_long) *np >= ngx_freebsd_net_inet_tcp_sendspace) { 4886 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 4887 "\"proxy_send_lowat\" must be less than %d " 4888 "(sysctl net.inet.tcp.sendspace)", 4889 ngx_freebsd_net_inet_tcp_sendspace); 4890 4891 return NGX_CONF_ERROR; 4892 } 4893 4894 #elif !(NGX_HAVE_SO_SNDLOWAT) 4895 ssize_t *np = data; 4896 4897 ngx_conf_log_error(NGX_LOG_WARN, cf, 0, 4898 "\"proxy_send_lowat\" is not supported, ignored"); 4899 4900 *np = 0; 4901 4902 #endif 4903 4904 return NGX_CONF_OK; 4905 } 4906 4907 4908 #if (NGX_HTTP_SSL) 4909 4910 static char * 4911 ngx_http_proxy_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data) 4912 { 4913 #ifndef SSL_CONF_FLAG_FILE 4914 return "is not supported on this platform"; 4915 #else 4916 return NGX_CONF_OK; 4917 #endif 4918 } 4919 4920 4921 static ngx_int_t 4922 ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf) 4923 { 4924 ngx_pool_cleanup_t *cln; 4925 4926 plcf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t)); 4927 if (plcf->upstream.ssl == NULL) { 4928 return NGX_ERROR; 4929 } 4930 4931 plcf->upstream.ssl->log = cf->log; 4932 4933 if (ngx_ssl_create(plcf->upstream.ssl, plcf->ssl_protocols, NULL) 4934 != NGX_OK) 4935 { 4936 return NGX_ERROR; 4937 } 4938 4939 cln = ngx_pool_cleanup_add(cf->pool, 0); 4940 if (cln == NULL) { 4941 ngx_ssl_cleanup_ctx(plcf->upstream.ssl); 4942 return NGX_ERROR; 4943 } 4944 4945 cln->handler = ngx_ssl_cleanup_ctx; 4946 cln->data = plcf->upstream.ssl; 4947 4948 if (ngx_ssl_ciphers(cf, plcf->upstream.ssl, &plcf->ssl_ciphers, 0) 4949 != NGX_OK) 4950 { 4951 return NGX_ERROR; 4952 } 4953 4954 if (plcf->upstream.ssl_certificate) { 4955 4956 if (plcf->upstream.ssl_certificate_key == NULL) { 4957 ngx_log_error(NGX_LOG_EMERG, cf->log, 0, 4958 "no \"proxy_ssl_certificate_key\" is defined " 4959 "for certificate \"%V\"", 4960 &plcf->upstream.ssl_certificate->value); 4961 return NGX_ERROR; 4962 } 4963 4964 if (plcf->upstream.ssl_certificate->lengths 4965 || plcf->upstream.ssl_certificate_key->lengths) 4966 { 4967 plcf->upstream.ssl_passwords = 4968 ngx_ssl_preserve_passwords(cf, plcf->upstream.ssl_passwords); 4969 if (plcf->upstream.ssl_passwords == NULL) { 4970 return NGX_ERROR; 4971 } 4972 4973 } else { 4974 if (ngx_ssl_certificate(cf, plcf->upstream.ssl, 4975 &plcf->upstream.ssl_certificate->value, 4976 &plcf->upstream.ssl_certificate_key->value, 4977 plcf->upstream.ssl_passwords) 4978 != NGX_OK) 4979 { 4980 return NGX_ERROR; 4981 } 4982 } 4983 } 4984 4985 if (plcf->upstream.ssl_verify) { 4986 if (plcf->ssl_trusted_certificate.len == 0) { 4987 ngx_log_error(NGX_LOG_EMERG, cf->log, 0, 4988 "no proxy_ssl_trusted_certificate for proxy_ssl_verify"); 4989 return NGX_ERROR; 4990 } 4991 4992 if (ngx_ssl_trusted_certificate(cf, plcf->upstream.ssl, 4993 &plcf->ssl_trusted_certificate, 4994 plcf->ssl_verify_depth) 4995 != NGX_OK) 4996 { 4997 return NGX_ERROR; 4998 } 4999 5000 if (ngx_ssl_crl(cf, plcf->upstream.ssl, &plcf->ssl_crl) != NGX_OK) { 5001 return NGX_ERROR; 5002 } 5003 } 5004 5005 if (ngx_ssl_client_session_cache(cf, plcf->upstream.ssl, 5006 plcf->upstream.ssl_session_reuse) 5007 != NGX_OK) 5008 { 5009 return NGX_ERROR; 5010 } 5011 5012 if (ngx_ssl_conf_commands(cf, plcf->upstream.ssl, plcf->ssl_conf_commands) 5013 != NGX_OK) 5014 { 5015 return NGX_ERROR; 5016 } 5017 5018 return NGX_OK; 5019 } 5020 5021 #endif 5022 5023 5024 static void 5025 ngx_http_proxy_set_vars(ngx_url_t *u, ngx_http_proxy_vars_t *v) 5026 { 5027 if (u->family != AF_UNIX) { 5028 5029 if (u->no_port || u->port == u->default_port) { 5030 5031 v->host_header = u->host; 5032 5033 if (u->default_port == 80) { 5034 ngx_str_set(&v->port, "80"); 5035 5036 } else { 5037 ngx_str_set(&v->port, "443"); 5038 } 5039 5040 } else { 5041 v->host_header.len = u->host.len + 1 + u->port_text.len; 5042 v->host_header.data = u->host.data; 5043 v->port = u->port_text; 5044 } 5045 5046 v->key_start.len += v->host_header.len; 5047 5048 } else { 5049 ngx_str_set(&v->host_header, "localhost"); 5050 ngx_str_null(&v->port); 5051 v->key_start.len += sizeof("unix:") - 1 + u->host.len + 1; 5052 } 5053 5054 v->uri = u->uri; 5055 } 5056