Annotation of embedaddon/nginx/src/http/modules/ngx_http_proxy_module.c, revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>