📄 proxy_http.c
字号:
else {
/* don't want to use r->hostname, as the incoming header might have a
* port attached
*/
const char* hostname = apr_table_get(r->headers_in,"Host");
if (!hostname) {
hostname = r->server->server_hostname;
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
"proxy: no HTTP 0.9 request (with no host line) "
"on incoming request and preserve host set "
"forcing hostname to be %s for uri %s",
hostname,
r->uri );
}
buf = apr_pstrcat(p, "Host: ", hostname, CRLF, NULL);
}
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);
/* handle Via */
if (conf->viaopt == via_block) {
/* Block all outgoing Via: headers */
apr_table_unset(r->headers_in, "Via");
} else if (conf->viaopt != via_off) {
const char *server_name = ap_get_server_name(r);
/* If USE_CANONICAL_NAME_OFF was configured for the proxy virtual host,
* then the server name returned by ap_get_server_name() is the
* origin server name (which does make too much sense with Via: headers)
* so we use the proxy vhost's name instead.
*/
if (server_name == r->hostname)
server_name = r->server->server_hostname;
/* Create a "Via:" request header entry and merge it */
/* Generate outgoing Via: header with/without server comment: */
apr_table_mergen(r->headers_in, "Via",
(conf->viaopt == via_full)
? apr_psprintf(p, "%d.%d %s%s (%s)",
HTTP_VERSION_MAJOR(r->proto_num),
HTTP_VERSION_MINOR(r->proto_num),
server_name, server_portstr,
AP_SERVER_BASEVERSION)
: apr_psprintf(p, "%d.%d %s%s",
HTTP_VERSION_MAJOR(r->proto_num),
HTTP_VERSION_MINOR(r->proto_num),
server_name, server_portstr)
);
}
/* X-Forwarded-*: handling
*
* XXX Privacy Note:
* -----------------
*
* These request headers are only really useful when the mod_proxy
* is used in a reverse proxy configuration, so that useful info
* about the client can be passed through the reverse proxy and on
* to the backend server, which may require the information to
* function properly.
*
* In a forward proxy situation, these options are a potential
* privacy violation, as information about clients behind the proxy
* are revealed to arbitrary servers out there on the internet.
*
* The HTTP/1.1 Via: header is designed for passing client
* information through proxies to a server, and should be used in
* a forward proxy configuation instead of X-Forwarded-*. See the
* ProxyVia option for details.
*/
if (PROXYREQ_REVERSE == r->proxyreq) {
const char *buf;
/* Add X-Forwarded-For: so that the upstream has a chance to
* determine, where the original request came from.
*/
apr_table_mergen(r->headers_in, "X-Forwarded-For",
r->connection->remote_ip);
/* Add X-Forwarded-Host: so that upstream knows what the
* original request hostname was.
*/
if ((buf = apr_table_get(r->headers_in, "Host"))) {
apr_table_mergen(r->headers_in, "X-Forwarded-Host", buf);
}
/* Add X-Forwarded-Server: so that upstream knows what the
* name of this proxy server is (if there are more than one)
* XXX: This duplicates Via: - do we strictly need it?
*/
apr_table_mergen(r->headers_in, "X-Forwarded-Server",
r->server->server_hostname);
}
/* send request headers */
proxy_run_fixups(r);
headers_in_array = apr_table_elts(r->headers_in);
headers_in = (const apr_table_entry_t *) headers_in_array->elts;
for (counter = 0; counter < headers_in_array->nelts; counter++) {
if (headers_in[counter].key == NULL || headers_in[counter].val == NULL
/* Clear out hop-by-hop request headers not to send
* RFC2616 13.5.1 says we should strip these headers
*/
/* Already sent */
|| !apr_strnatcasecmp(headers_in[counter].key, "Host")
|| !apr_strnatcasecmp(headers_in[counter].key, "Keep-Alive")
|| !apr_strnatcasecmp(headers_in[counter].key, "TE")
|| !apr_strnatcasecmp(headers_in[counter].key, "Trailer")
|| !apr_strnatcasecmp(headers_in[counter].key, "Transfer-Encoding")
|| !apr_strnatcasecmp(headers_in[counter].key, "Upgrade")
/* We have no way of knowing whether this Content-Length will
* be accurate, so we must not include it.
*/
|| !apr_strnatcasecmp(headers_in[counter].key, "Content-Length")
/* XXX: @@@ FIXME: "Proxy-Authorization" should *only* be
* suppressed if THIS server requested the authentication,
* not when a frontend proxy requested it!
*
* The solution to this problem is probably to strip out
* the Proxy-Authorisation header in the authorisation
* code itself, not here. This saves us having to signal
* somehow whether this request was authenticated or not.
*/
|| !apr_strnatcasecmp(headers_in[counter].key,"Proxy-Authorization")
|| !apr_strnatcasecmp(headers_in[counter].key,"Proxy-Authenticate")) {
continue;
}
/* for sub-requests, ignore freshness/expiry headers */
if (r->main) {
if (headers_in[counter].key == NULL || headers_in[counter].val == NULL
|| !apr_strnatcasecmp(headers_in[counter].key, "If-Match")
|| !apr_strnatcasecmp(headers_in[counter].key, "If-Modified-Since")
|| !apr_strnatcasecmp(headers_in[counter].key, "If-Range")
|| !apr_strnatcasecmp(headers_in[counter].key, "If-Unmodified-Since")
|| !apr_strnatcasecmp(headers_in[counter].key, "If-None-Match")) {
continue;
}
}
buf = apr_pstrcat(p, headers_in[counter].key, ": ",
headers_in[counter].val, CRLF,
NULL);
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);
}
/* If we can send chunks, do so! */
if (send_chunks) {
const char *te_hdr = "Transfer-Encoding: chunked" CRLF;
buf = apr_pmemdup(p, te_hdr, sizeof(te_hdr)-1);
ap_xlate_proto_to_ascii(buf, sizeof(te_hdr)-1);
e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(header_brigade, e);
}
else {
last_header_bucket = APR_BRIGADE_LAST(header_brigade);
}
/* add empty line at the end of the headers */
#if APR_CHARSET_EBCDIC
e = apr_bucket_immortal_create("\015\012", 2, c->bucket_alloc);
#else
e = apr_bucket_immortal_create(CRLF, sizeof(CRLF)-1, c->bucket_alloc);
#endif
APR_BRIGADE_INSERT_TAIL(header_brigade, e);
e = apr_bucket_flush_create(c->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(header_brigade, e);
if (send_chunks) {
status = ap_pass_brigade(origin->output_filters, header_brigade);
if (status != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
"proxy: request failed to %pI (%s)",
conn->worker->cp->addr, conn->hostname);
return status;
}
}
/* send the request data, if any. */
seen_eos = 0;
do {
char chunk_hdr[20]; /* must be here due to transient bucket. */
status = ap_get_brigade(r->input_filters, input_brigade,
AP_MODE_READBYTES, APR_BLOCK_READ,
HUGE_STRING_LEN);
if (status != APR_SUCCESS) {
return status;
}
/* If this brigade contain EOS, either stop or remove it. */
if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) {
seen_eos = 1;
/* As a shortcut, if this brigade is simply an EOS bucket,
* don't send anything down the filter chain.
*/
if (APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade))) {
break;
}
/* We can't pass this EOS to the output_filters. */
e = APR_BRIGADE_LAST(input_brigade);
apr_bucket_delete(e);
}
if (send_chunks) {
#define ASCII_CRLF "\015\012"
#define ASCII_ZERO "\060"
apr_size_t hdr_len;
apr_off_t bytes;
apr_brigade_length(input_brigade, 1, &bytes);
hdr_len = apr_snprintf(chunk_hdr, sizeof(chunk_hdr),
"%" APR_UINT64_T_HEX_FMT CRLF,
(apr_uint64_t)bytes);
ap_xlate_proto_to_ascii(chunk_hdr, hdr_len);
e = apr_bucket_transient_create(chunk_hdr, hdr_len,
body_brigade->bucket_alloc);
APR_BRIGADE_INSERT_HEAD(input_brigade, e);
/*
* Append the end-of-chunk CRLF
*/
e = apr_bucket_immortal_create(ASCII_CRLF, 2, c->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(input_brigade, e);
}
e = apr_bucket_flush_create(c->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(input_brigade, e);
APR_BRIGADE_CONCAT(body_brigade, input_brigade);
if (send_chunks) {
status = ap_pass_brigade(origin->output_filters, body_brigade);
if (status != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
"proxy: pass request data failed to %pI (%s)",
conn->worker->cp->addr, conn->hostname);
return status;
}
apr_brigade_cleanup(body_brigade);
}
} while (!seen_eos);
if (send_chunks) {
e = apr_bucket_immortal_create(ASCII_ZERO ASCII_CRLF
/* <trailers> */
ASCII_CRLF, 5, c->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(body_brigade, e);
}
if (!send_chunks) {
apr_off_t bytes;
apr_brigade_length(body_brigade, 1, &bytes);
if (bytes) {
const char *cl_hdr = "Content-Length", *cl_val;
cl_val = apr_off_t_toa(c->pool, bytes);
buf = apr_pstrcat(p, cl_hdr, ": ", cl_val, CRLF, NULL);
ap_xlate_proto_to_ascii(buf, strlen(buf));
e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc);
APR_BUCKET_INSERT_AFTER(last_header_bucket, e);
}
status = ap_pass_brigade(origin->output_filters, header_brigade);
if (status != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
"proxy: pass request data failed to %pI (%s)",
conn->worker->cp->addr, conn->hostname);
return status;
}
apr_brigade_cleanup(header_brigade);
}
status = ap_pass_brigade(origin->output_filters, body_brigade);
if (status != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
"proxy: pass request data failed to %pI (%s)",
conn->worker->cp->addr, conn->hostname);
return status;
}
apr_brigade_cleanup(body_brigade);
return APR_SUCCESS;
}
static void process_proxy_header(request_rec* r, proxy_server_conf* c,
const char* key, const char* value)
{
static const char* date_hdrs[]
= { "Date", "Expires", "Last-Modified", NULL } ;
static const struct {
const char* name ;
const char* (*func)(request_rec*, proxy_server_conf*, const char*) ;
} transform_hdrs[] = {
{ "Location", ap_proxy_location_reverse_map } ,
{ "Content-Location", ap_proxy_location_reverse_map } ,
{ "URI", ap_proxy_location_reverse_map } ,
{ "Set-Cookie", proxy_cookie_reverse_map } ,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -