📄 proxy_http.c
字号:
/* Copyright 1999-2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* HTTP routines for Apache proxy */
#include "mod_proxy.h"
module AP_MODULE_DECLARE_DATA proxy_http_module;
int ap_proxy_http_canon(request_rec *r, char *url);
int ap_proxy_http_handler(request_rec *r, proxy_worker *worker,
proxy_server_conf *conf,
char *url, const char *proxyname,
apr_port_t proxyport);
static apr_status_t ap_proxy_http_cleanup(const char *scheme,
request_rec *r,
proxy_conn_rec *backend);
/*
* Canonicalise http-like URLs.
* scheme is the scheme for the URL
* url is the URL starting with the first '/'
* def_port is the default port for this scheme.
*/
int ap_proxy_http_canon(request_rec *r, char *url)
{
char *host, *path, *search, sport[7];
const char *err;
const char *scheme;
apr_port_t port, def_port;
/* ap_port_of_scheme() */
if (strncasecmp(url, "http:", 5) == 0) {
url += 5;
scheme = "http";
}
else if (strncasecmp(url, "https:", 6) == 0) {
url += 6;
scheme = "https";
}
else {
return DECLINED;
}
def_port = apr_uri_port_of_scheme(scheme);
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
"proxy: HTTP: canonicalising URL %s", url);
/* do syntatic check.
* We break the URL into host, port, path, search
*/
port = def_port;
err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port);
if (err) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"error parsing URL %s: %s",
url, err);
return HTTP_BAD_REQUEST;
}
/* now parse path/search args, according to rfc1738 */
/* N.B. if this isn't a true proxy request, then the URL _path_
* has already been decoded. True proxy requests have r->uri
* == r->unparsed_uri, and no others have that property.
*/
if (r->uri == r->unparsed_uri) {
search = strchr(url, '?');
if (search != NULL)
*(search++) = '\0';
}
else
search = r->args;
/* process path */
path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, r->proxyreq);
if (path == NULL)
return HTTP_BAD_REQUEST;
if (port != def_port)
apr_snprintf(sport, sizeof(sport), ":%d", port);
else
sport[0] = '\0';
if (ap_strchr_c(host, ':')) { /* if literal IPv6 address */
host = apr_pstrcat(r->pool, "[", host, "]", NULL);
}
r->filename = apr_pstrcat(r->pool, "proxy:", scheme, "://", host, sport,
"/", path, (search) ? "?" : "", (search) ? search : "", NULL);
return OK;
}
static const char *ap_proxy_location_reverse_map(request_rec *r, proxy_server_conf *conf, const char *url)
{
struct proxy_alias *ent;
int i, l1, l2;
char *u;
/* XXX FIXME: Make sure this handled the ambiguous case of the :80
* after the hostname */
l1 = strlen(url);
ent = (struct proxy_alias *)conf->raliases->elts;
for (i = 0; i < conf->raliases->nelts; i++) {
l2 = strlen(ent[i].real);
if (l1 >= l2 && strncasecmp(ent[i].real, url, l2) == 0) {
u = apr_pstrcat(r->pool, ent[i].fake, &url[l2], NULL);
return ap_construct_url(r->pool, u, r);
}
}
return url;
}
/* cookies are a bit trickier to match: we've got two substrings to worry
* about, and we can't just find them with strstr 'cos of case. Regexp
* matching would be an easy fix, but for better consistency with all the
* other matches we'll refrain and use apr_strmatch to find path=/domain=
* and stick to plain strings for the config values.
*/
static const char *proxy_cookie_reverse_map(request_rec *r,
proxy_server_conf *conf, const char *str)
{
struct proxy_alias *ent;
size_t len = strlen(str);
const char* newpath = NULL ;
const char* newdomain = NULL ;
const char* pathp ;
const char* domainp ;
const char* pathe = NULL;
const char* domaine = NULL;
size_t l1, l2, poffs = 0, doffs = 0 ;
int i;
int ddiff = 0 ;
int pdiff = 0 ;
char* ret ;
/* find the match and replacement, but save replacing until we've done
both path and domain so we know the new strlen
*/
if ( pathp = apr_strmatch(conf->cookie_path_str, str, len) , pathp ) {
pathp += 5 ;
poffs = pathp - str ;
pathe = ap_strchr_c(pathp, ';') ;
l1 = pathe ? (pathe-pathp) : strlen(pathp) ;
pathe = pathp + l1 ;
ent = (struct proxy_alias *)conf->cookie_paths->elts;
for (i = 0; i < conf->cookie_paths->nelts; i++) {
l2 = strlen(ent[i].fake);
if (l1 >= l2 && strncmp(ent[i].fake, pathp, l2) == 0) {
newpath = ent[i].real ;
pdiff = strlen(newpath) - l1 ;
break ;
}
}
}
if ( domainp = apr_strmatch(conf->cookie_domain_str, str, len) , domainp ) {
domainp += 7 ;
doffs = domainp - str ;
domaine = ap_strchr_c(domainp, ';') ;
l1 = domaine ? (domaine-domainp) : strlen(domainp) ;
domaine = domainp + l1 ;
ent = (struct proxy_alias *)conf->cookie_domains->elts;
for (i = 0; i < conf->cookie_domains->nelts; i++) {
l2 = strlen(ent[i].fake);
if (l1 >= l2 && strncasecmp(ent[i].fake, domainp, l2) == 0) {
newdomain = ent[i].real ;
ddiff = strlen(newdomain) - l1 ;
break ;
}
}
}
if ( newpath ) {
ret = apr_palloc(r->pool, len+pdiff+ddiff+1) ;
l1 = strlen(newpath) ;
if ( newdomain ) {
l2 = strlen(newdomain) ;
if ( doffs > poffs ) {
memcpy(ret, str, poffs) ;
memcpy(ret+poffs, newpath, l1) ;
memcpy(ret+poffs+l1, pathe, domainp-pathe) ;
memcpy(ret+doffs+pdiff, newdomain, l2) ;
strcpy(ret+doffs+pdiff+l2, domaine) ;
} else {
memcpy(ret, str, doffs) ;
memcpy(ret+doffs, newdomain, l2) ;
memcpy(ret+doffs+l2, domaine, pathp-domaine) ;
memcpy(ret+poffs+ddiff, newpath, l1) ;
strcpy(ret+poffs+ddiff+l1, pathe) ;
}
} else {
memcpy(ret, str, poffs) ;
memcpy(ret+poffs, newpath, l1) ;
strcpy(ret+poffs+l1, pathe) ;
}
} else {
if ( newdomain ) {
ret = apr_palloc(r->pool, len+pdiff+ddiff+1) ;
l2 = strlen(newdomain) ;
memcpy(ret, str, doffs) ;
memcpy(ret+doffs, newdomain, l2) ;
strcpy(ret+doffs+l2, domaine) ;
} else {
ret = (char*) str ; /* no change */
}
}
return ret ;
}
/* Clear all connection-based headers from the incoming headers table */
static void ap_proxy_clear_connection(apr_pool_t *p, apr_table_t *headers)
{
const char *name;
char *next = apr_pstrdup(p, apr_table_get(headers, "Connection"));
apr_table_unset(headers, "Proxy-Connection");
if (!next)
return;
while (*next) {
name = next;
while (*next && !apr_isspace(*next) && (*next != ',')) {
++next;
}
while (*next && (apr_isspace(*next) || (*next == ','))) {
*next = '\0';
++next;
}
apr_table_unset(headers, name);
}
apr_table_unset(headers, "Connection");
}
static
apr_status_t ap_proxy_http_request(apr_pool_t *p, request_rec *r,
proxy_conn_rec *conn, conn_rec *origin,
proxy_server_conf *conf,
apr_uri_t *uri,
char *url, char *server_portstr)
{
conn_rec *c = r->connection;
char *buf;
apr_bucket *e, *last_header_bucket = NULL;
const apr_array_header_t *headers_in_array;
const apr_table_entry_t *headers_in;
int counter, seen_eos, send_chunks;
apr_status_t status;
apr_bucket_brigade *header_brigade, *body_brigade, *input_brigade;
header_brigade = apr_brigade_create(p, origin->bucket_alloc);
body_brigade = apr_brigade_create(p, origin->bucket_alloc);
input_brigade = apr_brigade_create(p, origin->bucket_alloc);
/*
* Send the HTTP/1.1 request to the remote server
*/
/* strip connection listed hop-by-hop headers from the request */
/* even though in theory a connection: close coming from the client
* should not affect the connection to the server, it's unlikely
* that subsequent client requests will hit this thread/process, so
* we cancel server keepalive if the client does.
*/
conn->close += ap_proxy_liststr(apr_table_get(r->headers_in,
"Connection"), "close");
/* sub-requests never use keepalives */
if (r->main) {
conn->close++;
}
ap_proxy_clear_connection(p, r->headers_in);
if (conn->close) {
apr_table_setn(r->headers_in, "Connection", "close");
origin->keepalive = AP_CONN_CLOSE;
}
/* By default, we can not send chunks. That means we must buffer
* the entire request before sending it along to ensure we have
* the correct Content-Length attached.
*/
send_chunks = 0;
if (apr_table_get(r->subprocess_env, "force-proxy-request-1.0")) {
buf = apr_pstrcat(p, r->method, " ", url, " HTTP/1.0" CRLF, NULL);
} else {
buf = apr_pstrcat(p, r->method, " ", url, " HTTP/1.1" CRLF, NULL);
if (apr_table_get(r->subprocess_env, "proxy-sendchunks")) {
send_chunks = 1;
}
}
if (apr_table_get(r->subprocess_env, "proxy-nokeepalive")) {
apr_table_unset(r->headers_in, "Connection");
origin->keepalive = AP_CONN_CLOSE;
}
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 (conf->preserve_host == 0) {
if (uri->port_str && uri->port != DEFAULT_HTTP_PORT) {
buf = apr_pstrcat(p, "Host: ", uri->hostname, ":", uri->port_str,
CRLF, NULL);
} else {
buf = apr_pstrcat(p, "Host: ", uri->hostname, CRLF, NULL);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -