📄 mod_proxy_http.c
字号:
* * We have no request body (handled by RB_STREAM_CL) * * We have a request body length <= MAX_MEM_SPOOL * * The administrator has setenv force-proxy-request-1.0 * * The client sent a C-L body, and the administrator has * not setenv proxy-sendchunked or has set setenv proxy-sendcl * * The client sent a T-E body, and the administrator has * setenv proxy-sendcl, and not setenv proxy-sendchunked * * If both proxy-sendcl and proxy-sendchunked are set, the * behavior is the same as if neither were set, large bodies * that can't be read will be forwarded in their original * form of C-L, or T-E. * * To ensure maximum compatibility, setenv proxy-sendcl * To reduce server resource use, setenv proxy-sendchunked * * Then address specific servers with conditional setenv * options to restore the default behavior where desireable. * * We have to compute content length by reading the entire request * body; if request body is not small, we'll spool the remaining * input to a temporary file. Chunked is always preferable. * * We can only trust the client-provided C-L if the T-E header * is absent, and the filters are unchanged (the body won't * be resized by another content filter). */ if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) { /* The whole thing fit, so our decision is trivial, use * the filtered bytes read from the client for the request * body Content-Length. * * If we expected no body, and read no body, do not set * the Content-Length. */ if (old_cl_val || old_te_val || bytes_read) { old_cl_val = apr_off_t_toa(r->pool, bytes_read); } rb_method = RB_STREAM_CL; } else if (old_te_val) { if (force10 || (apr_table_get(r->subprocess_env, "proxy-sendcl") && !apr_table_get(r->subprocess_env, "proxy-sendchunks") && !apr_table_get(r->subprocess_env, "proxy-sendchunked"))) { rb_method = RB_SPOOL_CL; } else { rb_method = RB_STREAM_CHUNKED; } } else if (old_cl_val) { if (r->input_filters == r->proto_input_filters) { rb_method = RB_STREAM_CL; } else if (!force10 && (apr_table_get(r->subprocess_env, "proxy-sendchunks") || apr_table_get(r->subprocess_env, "proxy-sendchunked")) && !apr_table_get(r->subprocess_env, "proxy-sendcl")) { rb_method = RB_STREAM_CHUNKED; } else { rb_method = RB_SPOOL_CL; } } else { /* This is an appropriate default; very efficient for no-body * requests, and has the behavior that it will not add any C-L * when the old_cl_val is NULL. */ rb_method = RB_SPOOL_CL; }/* Yes I hate gotos. This is the subrequest shortcut */skip_body: /* * Handle Connection: header if we do HTTP/1.1 request: * If we plan to close the backend connection sent Connection: close * otherwise sent Connection: Keep-Alive. */ if (!force10) { if (p_conn->close || p_conn->close_on_recycle) { buf = apr_pstrdup(p, "Connection: close" CRLF); } else { buf = apr_pstrdup(p, "Connection: Keep-Alive" CRLF); } ap_xlate_proto_to_ascii(buf, strlen(buf)); e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(header_brigade, e); } /* send the request body, if any. */ switch(rb_method) { case RB_STREAM_CHUNKED: rv = stream_reqbody_chunked(p, r, p_conn, origin, header_brigade, input_brigade); break; case RB_STREAM_CL: rv = stream_reqbody_cl(p, r, p_conn, origin, header_brigade, input_brigade, old_cl_val); break; case RB_SPOOL_CL: rv = spool_reqbody_cl(p, r, p_conn, origin, header_brigade, input_brigade, (old_cl_val != NULL) || (old_te_val != NULL) || (bytes_read > 0)); break; default: /* shouldn't be possible */ rv = HTTP_INTERNAL_SERVER_ERROR ; break; } if (rv != OK) { /* apr_errno value has been logged in lower level method */ ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, "proxy: pass request body failed to %pI (%s)" " from %s (%s)", p_conn->addr, p_conn->hostname ? p_conn->hostname: "", c->remote_ip, c->remote_host ? c->remote_host: ""); return rv; } return OK;}static void process_proxy_header(request_rec* r, proxy_dir_conf* c, const char* key, const char* value){ static const char* date_hdrs[] = { "Date", "Expires", "Last-Modified", NULL } ; static const struct { const char* name; ap_proxy_header_reverse_map_fn func; } transform_hdrs[] = { { "Location", ap_proxy_location_reverse_map } , { "Content-Location", ap_proxy_location_reverse_map } , { "URI", ap_proxy_location_reverse_map } , { "Destination", ap_proxy_location_reverse_map } , { "Set-Cookie", ap_proxy_cookie_reverse_map } , { NULL, NULL } } ; int i ; for ( i = 0 ; date_hdrs[i] ; ++i ) { if ( !strcasecmp(date_hdrs[i], key) ) { apr_table_add(r->headers_out, key, ap_proxy_date_canon(r->pool, value)) ; return ; } } for ( i = 0 ; transform_hdrs[i].name ; ++i ) { if ( !strcasecmp(transform_hdrs[i].name, key) ) { apr_table_add(r->headers_out, key, (*transform_hdrs[i].func)(r, c, value)) ; return ; } } apr_table_add(r->headers_out, key, value) ; return ;}/* * Note: pread_len is the length of the response that we've mistakenly * read (assuming that we don't consider that an error via * ProxyBadHeader StartBody). This depends on buffer actually being * local storage to the calling code in order for pread_len to make * any sense at all, since we depend on buffer still containing * what was read by ap_getline() upon return. */static void ap_proxy_read_headers(request_rec *r, request_rec *rr, char *buffer, int size, conn_rec *c, int *pread_len){ int len; char *value, *end; char field[MAX_STRING_LEN]; int saw_headers = 0; void *sconf = r->server->module_config; proxy_server_conf *psc; proxy_dir_conf *dconf; dconf = ap_get_module_config(r->per_dir_config, &proxy_module); psc = (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module); r->headers_out = apr_table_make(r->pool, 20); *pread_len = 0; /* * Read header lines until we get the empty separator line, a read error, * the connection closes (EOF), or we timeout. */ while ((len = ap_getline(buffer, size, rr, 1)) > 0) { if (!(value = strchr(buffer, ':'))) { /* Find the colon separator */ /* We may encounter invalid headers, usually from buggy * MS IIS servers, so we need to determine just how to handle * them. We can either ignore them, assume that they mark the * start-of-body (eg: a missing CRLF) or (the default) mark * the headers as totally bogus and return a 500. The sole * exception is an extra "HTTP/1.0 200, OK" line sprinkled * in between the usual MIME headers, which is a favorite * IIS bug. */ /* XXX: The mask check is buggy if we ever see an HTTP/1.10 */ if (!apr_date_checkmask(buffer, "HTTP/#.# ###*")) { if (psc->badopt == bad_error) { /* Nope, it wasn't even an extra HTTP header. Give up. */ r->headers_out = NULL; return ; } else if (psc->badopt == bad_body) { /* if we've already started loading headers_out, then * return what we've accumulated so far, in the hopes * that they are useful; also note that we likely pre-read * the first line of the response. */ if (saw_headers) { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server, "proxy: Starting body due to bogus non-header in headers " "returned by %s (%s)", r->uri, r->method); *pread_len = len; return ; } else { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server, "proxy: No HTTP headers " "returned by %s (%s)", r->uri, r->method); return ; } } } /* this is the psc->badopt == bad_ignore case */ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server, "proxy: Ignoring bogus HTTP header " "returned by %s (%s)", r->uri, r->method); continue; } *value = '\0'; ++value; /* XXX: RFC2068 defines only SP and HT as whitespace, this test is * wrong... and so are many others probably. */ while (apr_isspace(*value)) ++value; /* Skip to start of value */ /* should strip trailing whitespace as well */ for (end = &value[strlen(value)-1]; end > value && apr_isspace(*end); --end) *end = '\0'; /* make sure we add so as not to destroy duplicated headers * Modify headers requiring canonicalisation and/or affected * by ProxyPassReverse and family with process_proxy_header */ process_proxy_header(r, dconf, buffer, value) ; saw_headers = 1; /* the header was too long; at the least we should skip extra data */ if (len >= size - 1) { while ((len = ap_getline(field, MAX_STRING_LEN, rr, 1)) >= MAX_STRING_LEN - 1) { /* soak up the extra data */ } if (len == 0) /* time to exit the larger loop as well */ break; } }}static int addit_dammit(void *v, const char *key, const char *val){ apr_table_addn(v, key, val); return 1;}staticapr_status_t ap_proxygetline(apr_bucket_brigade *bb, char *s, int n, request_rec *r, int fold, int *writen){ char *tmp_s = s; apr_status_t rv; apr_size_t len; rv = ap_rgetline(&tmp_s, n, &len, r, fold, bb); apr_brigade_cleanup(bb); if (rv == APR_SUCCESS) { *writen = (int) len; } else if (rv == APR_ENOSPC) { *writen = n; } else { *writen = -1; } return rv;}/* * Limit the number of interim respones we sent back to the client. Otherwise * we suffer from a memory build up. Besides there is NO sense in sending back * an unlimited number of interim responses to the client. Thus if we cross * this limit send back a 502 (Bad Gateway). */#ifndef AP_MAX_INTERIM_RESPONSES#define AP_MAX_INTERIM_RESPONSES 10#endifstaticapr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, proxy_conn_rec *backend, conn_rec *origin, proxy_server_conf *conf, char *server_portstr) { conn_rec *c = r->connection; char buffer[HUGE_STRING_LEN]; const char *buf; char keepchar; request_rec *rp; apr_bucket *e; apr_bucket_brigade *bb, *tmp_bb; apr_bucket_brigade *pass_bb; int len, backasswards; int interim_response = 0; /* non-zero whilst interim 1xx responses * are being read. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -