📄 proxy_http.c
字号:
{ 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 ;
}
static void ap_proxy_read_headers(request_rec *r, request_rec *rr, char *buffer, int size, conn_rec *c)
{
int len;
char *value, *end;
char field[MAX_STRING_LEN];
int saw_headers = 0;
void *sconf = r->server->module_config;
proxy_server_conf *psc;
psc = (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
r->headers_out = apr_table_make(r->pool, 20);
/*
* 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. */
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. Otherwise, we completely bail.
*/
/* FIXME: We've already scarfed the supposed 1st line of
* the body, so the actual content may end up being bogus
* as well. If the content is HTML, we may be lucky.
*/
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);
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, psc, 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;
}
static
apr_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];
char keepchar;
request_rec *rp;
apr_bucket *e;
apr_bucket_brigade *bb;
int len, backasswards;
int interim_response; /* non-zero whilst interim 1xx responses
* are being read. */
apr_table_t *save_table;
bb = apr_brigade_create(p, c->bucket_alloc);
/* Get response from the remote server, and pass it up the
* filter chain
*/
rp = ap_proxy_make_fake_req(origin, r);
/* In case anyone needs to know, this is a fake request that is really a
* response.
*/
rp->proxyreq = PROXYREQ_RESPONSE;
do {
apr_brigade_cleanup(bb);
len = ap_getline(buffer, sizeof(buffer), rp, 0);
if (len == 0) {
/* handle one potential stray CRLF */
len = ap_getline(buffer, sizeof(buffer), rp, 0);
}
if (len <= 0) {
ap_proxy_http_cleanup(NULL, r, backend);
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"proxy: error reading status line from remote "
"server %s", backend->hostname);
return ap_proxyerror(r, HTTP_BAD_GATEWAY,
"Error reading from remote server");
}
/* Is it an HTTP/1 response?
* This is buggy if we ever see an HTTP/1.10
*/
if (apr_date_checkmask(buffer, "HTTP/#.# ###*")) {
int major, minor;
if (2 != sscanf(buffer, "HTTP/%u.%u", &major, &minor)) {
major = 1;
minor = 1;
}
/* If not an HTTP/1 message or
* if the status line was > 8192 bytes
*/
else if ((buffer[5] != '1') || (len >= sizeof(buffer)-1)) {
ap_proxy_http_cleanup(NULL, r, backend);
return ap_proxyerror(r, HTTP_BAD_GATEWAY,
apr_pstrcat(p, "Corrupt status line returned by remote "
"server: ", buffer, NULL));
}
backasswards = 0;
keepchar = buffer[12];
buffer[12] = '\0';
r->status = atoi(&buffer[9]);
if (keepchar != '\0') {
buffer[12] = keepchar;
} else {
/* 2616 requires the space in Status-Line; the origin
* server may have sent one but ap_rgetline_core will
* have stripped it. */
buffer[12] = ' ';
buffer[13] = '\0';
}
r->status_line = apr_pstrdup(p, &buffer[9]);
/* read the headers. */
/* N.B. for HTTP/1.0 clients, we have to fold line-wrapped headers*/
/* Also, take care with headers with multiple occurences. */
/* First, tuck away all already existing cookies */
save_table = apr_table_make(r->pool, 2);
apr_table_do(addit_dammit, save_table, r->headers_out,
"Set-Cookie", NULL);
/* shove the headers direct into r->headers_out */
ap_proxy_read_headers(r, rp, buffer, sizeof(buffer), origin);
if (r->headers_out == NULL) {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0,
r->server, "proxy: bad HTTP/%d.%d header "
"returned by %s (%s)", major, minor, r->uri,
r->method);
backend->close += 1;
/*
* ap_send_error relies on a headers_out to be present. we
* are in a bad position here.. so force everything we send out
* to have nothing to do with the incoming packet
*/
r->headers_out = apr_table_make(r->pool,1);
r->status = HTTP_BAD_GATEWAY;
r->status_line = "bad gateway";
return r->status;
} else {
const char *buf;
/* Now, add in the just read cookies */
apr_table_do(addit_dammit, save_table, r->headers_out,
"Set-Cookie", NULL);
/* and now load 'em all in */
if (!apr_is_empty_table(save_table)) {
apr_table_unset(r->headers_out, "Set-Cookie");
r->headers_out = apr_table_overlay(r->pool,
r->headers_out,
save_table);
}
/* strip connection listed hop-by-hop headers from response */
backend->close += ap_proxy_liststr(apr_table_get(r->headers_out,
"Connection"),
"close");
ap_proxy_clear_connection(p, r->headers_out);
if ((buf = apr_table_get(r->headers_out, "Content-Type"))) {
ap_set_content_type(r, apr_pstrdup(p, buf));
}
ap_proxy_pre_http_request(origin,rp);
}
/* handle Via header in response */
if (conf->viaopt != via_off && conf->viaopt != via_block) {
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:" response header entry and merge it */
apr_table_mergen(r->headers_out, "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)
);
}
/* cancel keepalive if HTTP/1.0 or less */
if ((major < 1) || (minor < 1)) {
backend->close += 1;
origin->keepalive = AP_CONN_CLOSE;
}
} else {
/* an http/0.9 response */
backasswards = 1;
r->status = 200;
r->status_line = "200 OK";
backend->close += 1;
}
interim_response = ap_is_HTTP_INFO(r->status);
if (interim_response) {
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL,
"proxy: HTTP: received interim %d response",
r->status);
}
/* Moved the fixups of Date headers and those affected by
* ProxyPassReverse/etc from here to ap_proxy_read_headers
*/
if ((r->status == 401) && (conf->error_override != 0)) {
const char *buf;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -