1
0
mirror of https://github.com/apache/httpd.git synced 2025-08-07 04:02:58 +03:00

This is the 1.3.x current proxy into 2.0 - first stage

PR:
Obtained from: Sam Magnuson
Submitted by:  Chuck Murcko
Reviewed by:


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@86923 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Chuck Murcko
2000-11-11 11:07:03 +00:00
parent adebe63463
commit 31c42a957c
3 changed files with 637 additions and 587 deletions

View File

@@ -58,13 +58,12 @@
/* CONNECT method for Apache proxy */ /* CONNECT method for Apache proxy */
#include "apr_strings.h"
#include "mod_proxy.h" #include "mod_proxy.h"
#include "http_log.h" #include "http_log.h"
#include "http_main.h" #include "http_main.h"
#ifdef HAVE_BSTRING_H #ifdef HAVE_BSTRING_H
#include <bstring.h> /* for IRIX, FD_SET calls bzero() */ #include <bstring.h> /* for IRIX, FD_SET calls bzero() */
#endif #endif
/* /*
@@ -104,15 +103,15 @@ allowed_port(proxy_server_conf *conf, int port)
int *list = (int *) conf->allowed_connect_ports->elts; int *list = (int *) conf->allowed_connect_ports->elts;
for(i = 0; i < conf->allowed_connect_ports->nelts; i++) { for(i = 0; i < conf->allowed_connect_ports->nelts; i++) {
if(port == list[i]) if(port == list[i])
return 1; return 1;
} }
return 0; return 0;
} }
int ap_proxy_connect_handler(request_rec *r, ap_cache_el *c, char *url, int ap_proxy_connect_handler(request_rec *r, ap_cache_el *c, char *url,
const char *proxyhost, int proxyport) const char *proxyhost, int proxyport)
{ {
struct in_addr destaddr; struct in_addr destaddr;
const char *host; const char *host;
@@ -123,7 +122,7 @@ int ap_proxy_connect_handler(request_rec *r, ap_cache_el *c, char *url,
int nbytes, i; int nbytes, i;
BUFF *sock_buff; BUFF *sock_buff;
apr_socket_t *client_sock=NULL; apr_socket_t *client_sock = NULL;
apr_pollfd_t *pollfd; apr_pollfd_t *pollfd;
apr_int32_t pollcnt; apr_int32_t pollcnt;
apr_int16_t pollevent; apr_int16_t pollevent;
@@ -137,77 +136,80 @@ int ap_proxy_connect_handler(request_rec *r, ap_cache_el *c, char *url,
host = url; host = url;
p = strchr(url, ':'); p = strchr(url, ':');
if (p == NULL) if (p == NULL)
port = DEFAULT_HTTPS_PORT; port = DEFAULT_HTTPS_PORT;
else { else {
port = atoi(p + 1); port = atoi(p + 1);
*p = '\0'; *p = '\0';
} }
/* check if ProxyBlock directive on this host */ /* check if ProxyBlock directive on this host */
destaddr.s_addr = apr_inet_addr(host); destaddr.s_addr = ap_inet_addr(host);
for (i = 0; i < conf->noproxies->nelts; i++) { for (i = 0; i < conf->noproxies->nelts; i++) {
if ((npent[i].name != NULL && ap_strstr_c(host, npent[i].name) != NULL) if ((npent[i].name != NULL && ap_strstr_c(host, npent[i].name) != NULL)
|| destaddr.s_addr == npent[i].addr.s_addr || npent[i].name[0] == '*') || destaddr.s_addr == npent[i].addr.s_addr || npent[i].name[0] == '*')
return ap_proxyerror(r, HTTP_FORBIDDEN, return ap_proxyerror(r, HTTP_FORBIDDEN,
"Connect to remote machine blocked"); "Connect to remote machine blocked");
} }
/* Check if it is an allowed port */ /* Check if it is an allowed port */
if (conf->allowed_connect_ports->nelts == 0) { if (conf->allowed_connect_ports->nelts == 0) {
/* Default setting if not overridden by AllowCONNECT */ /* Default setting if not overridden by AllowCONNECT */
switch (port) { switch (port) {
case DEFAULT_HTTPS_PORT: case DEFAULT_HTTPS_PORT:
case DEFAULT_SNEWS_PORT: case DEFAULT_SNEWS_PORT:
break; break;
default: default:
return HTTP_FORBIDDEN; return HTTP_FORBIDDEN;
} }
} else if(!allowed_port(conf, port)) } else if(!allowed_port(conf, port))
return HTTP_FORBIDDEN; return HTTP_FORBIDDEN;
if (proxyhost) { if (proxyhost) {
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL, ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
"CONNECT to remote proxy %s on port %d", proxyhost, proxyport); "CONNECT to remote proxy %s on port %d", proxyhost, proxyport);
} }
else { else {
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL, ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
"CONNECT to %s on port %d", host, port); "CONNECT to %s on port %d", host, port);
} }
if ((apr_create_tcp_socket(&sock, r->pool)) != APR_SUCCESS) { if ((apr_create_tcp_socket(&sock, r->pool)) != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"proxy: error creating socket"); "proxy: error creating socket");
return HTTP_INTERNAL_SERVER_ERROR; return HTTP_INTERNAL_SERVER_ERROR;
} }
if (ap_proxy_doconnect(sock, (char *)(proxyhost ? proxyhost : host), proxyport ? proxyport : port, r) == -1) { if (ap_proxy_doconnect(sock, (char *)(proxyhost ? proxyhost : host),
proxyport ? proxyport : port, r) == -1) {
apr_close_socket(sock); apr_close_socket(sock);
return ap_proxyerror(r, HTTP_INTERNAL_SERVER_ERROR, return ap_proxyerror(r, HTTP_INTERNAL_SERVER_ERROR,
apr_pstrcat(r->pool, "Could not connect to remote machine:<br>", apr_pstrcat(r->pool, "Could not connect to remote machine:<br>",
strerror(errno), NULL)); strerror(errno), NULL));
} }
/* If we are connecting through a remote proxy, we need to pass /* If we are connecting through a remote proxy, we need to pass
* the CONNECT request on to it. * the CONNECT request on to it.
*/ */
if (proxyport) { if (proxyport) {
/* FIXME: We should not be calling write() directly, but we currently /* FIXME: We should not be calling write() directly, but we currently
* have no alternative. Error checking ignored. Also, we force * have no alternative. Error checking ignored. Also, we force
* a HTTP/1.0 request to keep things simple. * a HTTP/1.0 request to keep things simple.
*/ */
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL, ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
"Sending the CONNECT request to the remote proxy"); "Sending the CONNECT request to the remote proxy");
nbytes = apr_snprintf(buffer, sizeof(buffer), "CONNECT %s HTTP/1.0" CRLF, r->uri); nbytes = apr_snprintf(buffer, sizeof(buffer),
"CONNECT %s HTTP/1.0" CRLF, r->uri);
apr_send(sock, buffer, &nbytes); apr_send(sock, buffer, &nbytes);
nbytes = apr_snprintf(buffer, sizeof(buffer),"Proxy-agent: %s" CRLF CRLF, ap_get_server_version()); nbytes = apr_snprintf(buffer, sizeof(buffer),
"Proxy-agent: %s" CRLF CRLF, ap_get_server_version());
apr_send(sock, buffer, &nbytes); apr_send(sock, buffer, &nbytes);
} }
else { else {
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL, ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
"Returning 200 OK Status"); "Returning 200 OK Status");
ap_rvputs(r, "HTTP/1.0 200 Connection established" CRLF, NULL); ap_rvputs(r, "HTTP/1.0 200 Connection established" CRLF, NULL);
ap_rvputs(r, "Proxy-agent: ", ap_get_server_version(), CRLF CRLF, NULL); ap_rvputs(r, "Proxy-agent: ", ap_get_server_version(), CRLF CRLF, NULL);
ap_bflush(r->connection->client); ap_bflush(r->connection->client);
} }
sock_buff = ap_bcreate(r->pool, B_RDWR); sock_buff = ap_bcreate(r->pool, B_RDWR);
@@ -215,7 +217,8 @@ int ap_proxy_connect_handler(request_rec *r, ap_cache_el *c, char *url,
if(apr_setup_poll(&pollfd, 2, r->pool) != APR_SUCCESS) if(apr_setup_poll(&pollfd, 2, r->pool) != APR_SUCCESS)
{ {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "proxy: error apr_setup_poll()"); ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"proxy: error apr_setup_poll()");
return HTTP_INTERNAL_SERVER_ERROR; return HTTP_INTERNAL_SERVER_ERROR;
} }
@@ -226,20 +229,21 @@ int ap_proxy_connect_handler(request_rec *r, ap_cache_el *c, char *url,
just see if a recv gives us anything and do the same to sock (server) side, I'll leave this as TBD so just see if a recv gives us anything and do the same to sock (server) side, I'll leave this as TBD so
one can decide the best path to take one can decide the best path to take
*/ */
if(apr_put_os_sock(&client_sock, (apr_os_sock_t *)get_socket(r->connection->client), if(apr_put_os_sock(&client_sock,
(apr_os_sock_t *)get_socket(r->connection->client),
r->pool) != APR_SUCCESS) r->pool) != APR_SUCCESS)
{ {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "proxy: error creating client apr_socket_t"); ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"proxy: error creating client apr_socket_t");
return HTTP_INTERNAL_SERVER_ERROR; return HTTP_INTERNAL_SERVER_ERROR;
} }
apr_add_poll_socket(pollfd, client_sock, APR_POLLIN); apr_add_poll_socket(pollfd, client_sock, APR_POLLIN);
#endif #endif
/* Add the server side to the poll */ /* Add the server side to the poll */
apr_add_poll_socket(pollfd, sock, APR_POLLIN); apr_add_poll_socket(pollfd, sock, APR_POLLIN);
while (1) { /* Infinite loop until error (one side closes the connection) */ while (1) { /* Infinite loop until error (one side closes the connection) */
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL, "Going to sleep (poll)"); ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL, "Going to sleep (poll)");
if(apr_poll(pollfd, &pollcnt, -1) != APR_SUCCESS) if(apr_poll(pollfd, &pollcnt, -1) != APR_SUCCESS)
{ {
@@ -262,8 +266,7 @@ int ap_proxy_connect_handler(request_rec *r, ap_cache_el *c, char *url,
o += i; o += i;
nbytes -= i; nbytes -= i;
} }
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL, ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL, "Wrote %d bytes to client", nbytes);
"Wrote %d bytes to client", nbytes);
} }
else else
break; break;
@@ -273,7 +276,8 @@ int ap_proxy_connect_handler(request_rec *r, ap_cache_el *c, char *url,
if (pollevent & APR_POLLIN) { if (pollevent & APR_POLLIN) {
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL, ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
"client was set"); "client was set");
if(ap_bread(r->connection->client, buffer, HUGE_STRING_LEN, &nbytes) == APR_SUCCESS) { if(ap_bread(r->connection->client, buffer, HUGE_STRING_LEN,
&nbytes) == APR_SUCCESS) {
int o = 0; int o = 0;
while(nbytes) while(nbytes)
{ {
@@ -281,8 +285,8 @@ int ap_proxy_connect_handler(request_rec *r, ap_cache_el *c, char *url,
o += i; o += i;
nbytes -= i; nbytes -= i;
} }
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL, ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
"Wrote %d bytes to server", nbytes); NULL, "Wrote %d bytes to server", nbytes);
} }
else else
break; break;
@@ -291,7 +295,7 @@ int ap_proxy_connect_handler(request_rec *r, ap_cache_el *c, char *url,
else else
break; break;
} }
apr_close_socket(sock); apr_close_socket(sock);
return OK; return OK;

View File

@@ -58,7 +58,6 @@
/* HTTP routines for Apache proxy */ /* HTTP routines for Apache proxy */
#include "apr_strings.h"
#include "mod_proxy.h" #include "mod_proxy.h"
#include "http_log.h" #include "http_log.h"
#include "http_main.h" #include "http_main.h"
@@ -83,7 +82,7 @@ int ap_proxy_http_canon(request_rec *r, char *url, const char *scheme, int def_p
port = def_port; port = def_port;
err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port); err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port);
if (err) if (err)
return HTTP_BAD_REQUEST; return HTTP_BAD_REQUEST;
/* now parse path/search args, according to rfc1738 */ /* now parse path/search args, according to rfc1738 */
/* N.B. if this isn't a true proxy request, then the URL _path_ /* N.B. if this isn't a true proxy request, then the URL _path_
@@ -91,25 +90,25 @@ int ap_proxy_http_canon(request_rec *r, char *url, const char *scheme, int def_p
* == r->unparsed_uri, and no others have that property. * == r->unparsed_uri, and no others have that property.
*/ */
if (r->uri == r->unparsed_uri) { if (r->uri == r->unparsed_uri) {
search = strchr(url, '?'); search = strchr(url, '?');
if (search != NULL) if (search != NULL)
*(search++) = '\0'; *(search++) = '\0';
} }
else else
search = r->args; search = r->args;
/* process path */ /* process path */
path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, r->proxyreq); path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, r->proxyreq);
if (path == NULL) if (path == NULL)
return HTTP_BAD_REQUEST; return HTTP_BAD_REQUEST;
if (port != def_port) if (port != def_port)
apr_snprintf(sport, sizeof(sport), ":%d", port); apr_snprintf(sport, sizeof(sport), ":%d", port);
else else
sport[0] = '\0'; sport[0] = '\0';
r->filename = apr_pstrcat(r->pool, "proxy:", scheme, "://", host, sport, "/", r->filename = apr_pstrcat(r->pool, "proxy:", scheme, "://", host, sport, "/",
path, (search) ? "?" : "", (search) ? search : "", NULL); path, (search) ? "?" : "", (search) ? search : "", NULL);
return OK; return OK;
} }
@@ -135,7 +134,7 @@ static const char *proxy_location_reverse_map(request_rec *r, const char *url)
return url; return url;
} }
/* Clear all connection-based headers from the incoming headers apr_table_t */ /* Clear all connection-based headers from the incoming headers table */
static void clear_connection(apr_pool_t *p, apr_table_t *headers) static void clear_connection(apr_pool_t *p, apr_table_t *headers)
{ {
const char *name; const char *name;
@@ -143,17 +142,17 @@ static void clear_connection(apr_pool_t *p, apr_table_t *headers)
apr_table_unset(headers, "Proxy-Connection"); apr_table_unset(headers, "Proxy-Connection");
if (!next) if (!next)
return; return;
while (*next) { while (*next) {
name = next; name = next;
while (*next && !apr_isspace(*next) && (*next != ',')) while (*next && !apr_isspace(*next) && (*next != ','))
++next; ++next;
while (*next && (apr_isspace(*next) || (*next == ','))) { while (*next && (apr_isspace(*next) || (*next == ','))) {
*next = '\0'; *next = '\0';
++next; ++next;
} }
apr_table_unset(headers, name); apr_table_unset(headers, name);
} }
apr_table_unset(headers, "Connection"); apr_table_unset(headers, "Connection");
} }
@@ -167,34 +166,34 @@ static void clear_connection(apr_pool_t *p, apr_table_t *headers)
* we return DECLINED so that we can try another proxy. (Or the direct * we return DECLINED so that we can try another proxy. (Or the direct
* route.) * route.)
*/ */
int ap_proxy_http_handler(request_rec *r, ap_cache_el *c, char *url, int ap_proxy_http_handler(request_rec *r, ap_cache_el *c, char *url,
const char *proxyhost, int proxyport) const char *proxyhost, int proxyport)
{ {
const char *strp; const char *strp;
char *strp2; char *strp2;
char *desthost; char *desthost;
apr_socket_t *sock; apr_socket_t *sock;
int i, len, backasswards, content_length=-1; int i, len, backasswards, content_length = -1;
apr_array_header_t *reqhdrs_arr; apr_array_header_t *reqhdrs_arr;
apr_table_t *resp_hdrs=NULL; apr_table_t *resp_hdrs = NULL;
apr_table_entry_t *reqhdrs; apr_table_entry_t *reqhdrs;
struct sockaddr_in server; struct sockaddr_in server;
struct in_addr destaddr; struct in_addr destaddr;
BUFF *f; BUFF *f;
apr_file_t *cachefp=NULL;
char buffer[HUGE_STRING_LEN]; char buffer[HUGE_STRING_LEN];
char portstr[32]; char portstr[32];
apr_pool_t *p = r->pool; apr_pool_t *p = r->pool;
const long int zero = 0L; const long int zero = 0L;
int destport = 0; int destport = 0;
apr_ssize_t cntr;
char *destportstr = NULL; char *destportstr = NULL;
const char *urlptr = NULL; const char *urlptr = NULL;
char *datestr, *clen; char *datestr, *clen;
apr_ssize_t cntr;
apr_file_t *cachefp = NULL;
void *sconf = r->server->module_config; void *sconf = r->server->module_config;
proxy_server_conf *conf = proxy_server_conf *conf =
(proxy_server_conf *) ap_get_module_config(sconf, &proxy_module); (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
struct noproxy_entry *npent = (struct noproxy_entry *) conf->noproxies->elts; struct noproxy_entry *npent = (struct noproxy_entry *) conf->noproxies->elts;
struct nocache_entry *ncent = (struct nocache_entry *) conf->nocaches->elts; struct nocache_entry *ncent = (struct nocache_entry *) conf->nocaches->elts;
int nocache = 0; int nocache = 0;
@@ -206,38 +205,40 @@ int ap_proxy_http_handler(request_rec *r, ap_cache_el *c, char *url,
urlptr = strstr(url, "://"); urlptr = strstr(url, "://");
if (urlptr == NULL) if (urlptr == NULL)
return HTTP_BAD_REQUEST; return HTTP_BAD_REQUEST;
urlptr += 3; urlptr += 3;
destport = DEFAULT_HTTP_PORT; destport = DEFAULT_HTTP_PORT;
strp = ap_strchr_c(urlptr, '/'); strp = ap_strchr_c(urlptr, '/');
if (strp == NULL) { if (strp == NULL) {
desthost = apr_pstrdup(p, urlptr); desthost = apr_pstrdup(p, urlptr);
urlptr = "/"; urlptr = "/";
} }
else { else {
char *q = apr_palloc(p, strp - urlptr + 1); char *q = apr_palloc(p, strp - urlptr + 1);
memcpy(q, urlptr, strp - urlptr); memcpy(q, urlptr, strp - urlptr);
q[strp - urlptr] = '\0'; q[strp - urlptr] = '\0';
urlptr = strp; urlptr = strp;
desthost = q; desthost = q;
} }
strp2 = ap_strchr(desthost, ':'); strp2 = ap_strchr(desthost, ':');
if (strp2 != NULL) { if (strp2 != NULL) {
*(strp2++) = '\0'; *(strp2++) = '\0';
if (apr_isdigit(*strp2)) { if (apr_isdigit(*strp2)) {
destport = atoi(strp2); destport = atoi(strp2);
destportstr = strp2; destportstr = strp2;
} }
} }
/* check if ProxyBlock directive on this host */ /* check if ProxyBlock directive on this host */
destaddr.s_addr = apr_inet_addr(desthost); destaddr.s_addr = apr_inet_addr(desthost);
for (i = 0; i < conf->noproxies->nelts; i++) { for (i = 0; i < conf->noproxies->nelts; i++) {
if ((npent[i].name != NULL && ap_strstr_c(desthost, npent[i].name) != NULL) if ((npent[i].name != NULL
|| destaddr.s_addr == npent[i].addr.s_addr || npent[i].name[0] == '*') && ap_strstr_c(desthost, npent[i].name) != NULL)
return ap_proxyerror(r, HTTP_FORBIDDEN, || destaddr.s_addr == npent[i].addr.s_addr
"Connect to remote machine blocked"); || npent[i].name[0] == '*')
return ap_proxyerror(r, HTTP_FORBIDDEN,
"Connect to remote machine blocked");
} }
if ((apr_create_tcp_socket(&sock, r->pool)) != APR_SUCCESS) { if ((apr_create_tcp_socket(&sock, r->pool)) != APR_SUCCESS) {
@@ -246,11 +247,14 @@ int ap_proxy_http_handler(request_rec *r, ap_cache_el *c, char *url,
return HTTP_INTERNAL_SERVER_ERROR; return HTTP_INTERNAL_SERVER_ERROR;
} }
if (conf->recv_buffer_size > 0 && apr_setsocketopt(sock, APR_SO_RCVBUF,conf->recv_buffer_size)) { #if !defined(TPF) && !defined(BEOS)
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, if (conf->recv_buffer_size > 0 && apr_setsocketopt(sock, APR_SO_RCVBUF,
"setsockopt(SO_RCVBUF): Failed to set ProxyReceiveBufferSize, using default"); conf->recv_buffer_size)) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"setsockopt(SO_RCVBUF): Failed to set ProxyReceiveBufferSize, using default");
} }
#endif
if (proxyhost != NULL) { if (proxyhost != NULL) {
i = ap_proxy_doconnect(sock, (char *)proxyhost, proxyport, r); i = ap_proxy_doconnect(sock, (char *)proxyhost, proxyport, r);
} }
@@ -259,147 +263,148 @@ int ap_proxy_http_handler(request_rec *r, ap_cache_el *c, char *url,
} }
if (i == -1) { if (i == -1) {
if (proxyhost != NULL) if (proxyhost != NULL)
return DECLINED; /* try again another way */ return DECLINED; /* try again another way */
else else
return ap_proxyerror(r, HTTP_BAD_GATEWAY, return ap_proxyerror(r, HTTP_BAD_GATEWAY, apr_pstrcat(r->pool,
apr_pstrcat(r->pool, "Could not connect to remote machine: ", "Could not connect to remote machine: ",
strerror(errno), NULL)); strerror(errno), NULL));
} }
clear_connection(r->pool, r->headers_in); /* Strip connection-based headers */ clear_connection(r->pool, r->headers_in); /* Strip connection-based headers */
f = ap_bcreate(p, B_RDWR); f = ap_bcreate(p, B_RDWR);
ap_bpush_socket(f, sock); ap_bpush_socket(f, sock);
ap_bvputs(f, r->method, " ", proxyhost ? url : urlptr, " HTTP/1.0" CRLF, ap_bvputs(f, r->method, " ", proxyhost ? url : urlptr, " HTTP/1.0" CRLF,
NULL); NULL);
if (destportstr != NULL && destport != DEFAULT_HTTP_PORT) if (destportstr != NULL && destport != DEFAULT_HTTP_PORT)
ap_bvputs(f, "Host: ", desthost, ":", destportstr, CRLF, NULL); ap_bvputs(f, "Host: ", desthost, ":", destportstr, CRLF, NULL);
else else
ap_bvputs(f, "Host: ", desthost, CRLF, NULL); ap_bvputs(f, "Host: ", desthost, CRLF, NULL);
if (conf->viaopt == via_block) { if (conf->viaopt == via_block) {
/* Block all outgoing Via: headers */ /* Block all outgoing Via: headers */
apr_table_unset(r->headers_in, "Via"); apr_table_unset(r->headers_in, "Via");
} else if (conf->viaopt != via_off) { } else if (conf->viaopt != via_off) {
/* Create a "Via:" request header entry and merge it */ /* Create a "Via:" request header entry and merge it */
i = ap_get_server_port(r); i = ap_get_server_port(r);
if (ap_is_default_port(i,r)) { if (ap_is_default_port(i,r)) {
strcpy(portstr,""); strcpy(portstr,"");
} else { } else {
apr_snprintf(portstr, sizeof portstr, ":%d", i); apr_snprintf(portstr, sizeof portstr, ":%d", i);
} }
/* Generate outgoing Via: header with/without server comment: */ /* Generate outgoing Via: header with/without server comment: */
apr_table_mergen(r->headers_in, "Via", ap_table_mergen(r->headers_in, "Via",
(conf->viaopt == via_full) (conf->viaopt == via_full)
? apr_psprintf(p, "%d.%d %s%s (%s)", ? apr_psprintf(p, "%d.%d %s%s (%s)",
HTTP_VERSION_MAJOR(r->proto_num), HTTP_VERSION_MAJOR(r->proto_num),
HTTP_VERSION_MINOR(r->proto_num), HTTP_VERSION_MINOR(r->proto_num),
ap_get_server_name(r), portstr, ap_get_server_name(r), portstr,
AP_SERVER_BASEVERSION) AP_SERVER_BASEVERSION)
: apr_psprintf(p, "%d.%d %s%s", : apr_psprintf(p, "%d.%d %s%s",
HTTP_VERSION_MAJOR(r->proto_num), HTTP_VERSION_MAJOR(r->proto_num),
HTTP_VERSION_MINOR(r->proto_num), HTTP_VERSION_MINOR(r->proto_num),
ap_get_server_name(r), portstr) ap_get_server_name(r), portstr)
); );
} }
reqhdrs_arr = apr_table_elts(r->headers_in); reqhdrs_arr = apr_table_elts(r->headers_in);
reqhdrs = (apr_table_entry_t *) reqhdrs_arr->elts; reqhdrs = (apr_table_entry_t *) reqhdrs_arr->elts;
for (i = 0; i < reqhdrs_arr->nelts; i++) { for (i = 0; i < reqhdrs_arr->nelts; i++) {
if (reqhdrs[i].key == NULL || reqhdrs[i].val == NULL if (reqhdrs[i].key == NULL || reqhdrs[i].val == NULL
/* Clear out headers not to send */ /* Clear out headers not to send */
|| !strcasecmp(reqhdrs[i].key, "Host") /* Already sent */ || !strcasecmp(reqhdrs[i].key, "Host") /* Already sent */
/* XXX: @@@ FIXME: "Proxy-Authorization" should *only* be /* XXX: @@@ FIXME: "Proxy-Authorization" should *only* be
* suppressed if THIS server requested the authentication, * suppressed if THIS server requested the authentication,
* not when a frontend proxy requested it! * not when a frontend proxy requested it!
*/ */
|| !strcasecmp(reqhdrs[i].key, "Proxy-Authorization")) || !strcasecmp(reqhdrs[i].key, "Proxy-Authorization"))
continue; continue;
ap_bvputs(f, reqhdrs[i].key, ": ", reqhdrs[i].val, CRLF, NULL); ap_bvputs(f, reqhdrs[i].key, ": ", reqhdrs[i].val, CRLF, NULL);
} }
ap_bputs(CRLF, f); ap_bputs(CRLF, f);
/* send the request data, if any. */ /* send the request data, if any. */
if (ap_should_client_block(r)) { if (ap_should_client_block(r)) {
while ((i = ap_get_client_block(r, buffer, sizeof buffer)) > 0) while ((i = ap_get_client_block(r, buffer, sizeof buffer)) > 0)
ap_bwrite(f, buffer, i, &cntr); ap_bwrite(f, buffer, i, &cntr);
} }
ap_bflush(f); ap_bflush(f);
len = ap_bgets(buffer, sizeof buffer - 1, f); len = ap_bgets(buffer, sizeof buffer - 1, f);
if (len == -1) { if (len == -1) {
ap_bclose(f); ap_bclose(f);
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"ap_bgets() - proxy receive - Error reading from remote server %s (length %d)", "ap_bgets() - proxy receive - Error reading from remote server %s (length %d)",
proxyhost ? proxyhost : desthost, len); proxyhost ? proxyhost : desthost, len);
return ap_proxyerror(r, HTTP_BAD_GATEWAY, return ap_proxyerror(r, HTTP_BAD_GATEWAY,
"Error reading from remote server"); "Error reading from remote server");
} else if (len == 0) { } else if (len == 0) {
ap_bclose(f); ap_bclose(f);
return ap_proxyerror(r, HTTP_BAD_GATEWAY, return ap_proxyerror(r, HTTP_BAD_GATEWAY,
"Document contains no data"); "Document contains no data");
} }
/* Is it an HTTP/1 response? This is buggy if we ever see an HTTP/1.10 */ /* Is it an HTTP/1 response? This is buggy if we ever see an HTTP/1.10 */
if (ap_checkmask(buffer, "HTTP/#.# ###*")) { if (ap_checkmask(buffer, "HTTP/#.# ###*")) {
int major, minor; int major, minor;
if (2 != sscanf(buffer, "HTTP/%u.%u", &major, &minor)) { if (2 != sscanf(buffer, "HTTP/%u.%u", &major, &minor)) {
major = 1; major = 1;
minor = 0; minor = 0;
} }
/* If not an HTTP/1 message or if the status line was > 8192 bytes */ /* If not an HTTP/1 message or if the status line was > 8192 bytes */
if (buffer[5] != '1' || buffer[len - 1] != '\n') { if (buffer[5] != '1' || buffer[len - 1] != '\n') {
ap_bclose(f); ap_bclose(f);
return HTTP_BAD_GATEWAY; return HTTP_BAD_GATEWAY;
} }
backasswards = 0; backasswards = 0;
buffer[--len] = '\0'; buffer[--len] = '\0';
buffer[12] = '\0'; buffer[12] = '\0';
r->status = atoi(&buffer[9]); r->status = atoi(&buffer[9]);
buffer[12] = ' '; buffer[12] = ' ';
r->status_line = apr_pstrdup(p, &buffer[9]); r->status_line = apr_pstrdup(p, &buffer[9]);
/* read the headers. */ /* read the headers. */
/* N.B. for HTTP/1.0 clients, we have to fold line-wrapped headers */ /* N.B. for HTTP/1.0 clients, we have to fold line-wrapped headers */
/* Also, take care with headers with multiple occurences. */ /* Also, take care with headers with multiple occurences. */
resp_hdrs = ap_proxy_read_headers(r, buffer, HUGE_STRING_LEN, f);
if (resp_hdrs == NULL) { resp_hdrs = ap_proxy_read_headers(r, buffer, HUGE_STRING_LEN, f);
ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r->server, if (resp_hdrs == NULL) {
"proxy: Bad HTTP/%d.%d header returned by %s (%s)", ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r->server,
major, minor, r->uri, r->method); "proxy: Bad HTTP/%d.%d header returned by %s (%s)",
nocache = 1; /* do not cache this broken file */ major, minor, r->uri, r->method);
} nocache = 1; /* do not cache this broken file */
}
else else
{ {
clear_connection(p, resp_hdrs); /* Strip Connection hdrs */ clear_connection(p, resp_hdrs); /* Strip Connection hdrs */
ap_cache_el_header_merge(c, resp_hdrs); ap_cache_el_header_merge(c, resp_hdrs);
} }
if (conf->viaopt != via_off && conf->viaopt != via_block) { if (conf->viaopt != via_off && conf->viaopt != via_block) {
/* Create a "Via:" response header entry and merge it */ /* Create a "Via:" response header entry and merge it */
i = ap_get_server_port(r); i = ap_get_server_port(r);
if (ap_is_default_port(i,r)) { if (ap_is_default_port(i,r)) {
strcpy(portstr,""); strcpy(portstr,"");
} else { } else {
apr_snprintf(portstr, sizeof portstr, ":%d", i); apr_snprintf(portstr, sizeof portstr, ":%d", i);
} }
ap_cache_el_header_add(c, "Via", (conf->viaopt == via_full) ap_cache_el_header_add(c, "Via", (conf->viaopt == via_full)
? apr_psprintf(p, "%d.%d %s%s (%s)", major, minor, ? apr_psprintf(p, "%d.%d %s%s (%s)", major, minor,
ap_get_server_name(r), portstr, AP_SERVER_BASEVERSION) ap_get_server_name(r), portstr, AP_SERVER_BASEVERSION)
: apr_psprintf(p, "%d.%d %s%s", major, minor, ap_get_server_name(r), portstr) : apr_psprintf(p, "%d.%d %s%s", major, minor,
); ap_get_server_name(r), portstr));
} }
} }
else { else {
/* an http/0.9 response */ /* an http/0.9 response */
backasswards = 1; backasswards = 1;
r->status = 200; r->status = 200;
r->status_line = "200 OK"; r->status_line = "200 OK";
} }
/* /*
@@ -423,44 +428,44 @@ int ap_proxy_http_handler(request_rec *r, ap_cache_el *c, char *url,
content_length = atoi(clen ? clen : "-1"); content_length = atoi(clen ? clen : "-1");
for (i = 0; i < conf->nocaches->nelts; i++) { for (i = 0; i < conf->nocaches->nelts; i++) {
if ((ncent[i].name != NULL && ap_strstr_c(desthost, ncent[i].name) != NULL) if ((ncent[i].name != NULL && ap_strstr_c(desthost, ncent[i].name) != NULL)
|| destaddr.s_addr == ncent[i].addr.s_addr || ncent[i].name[0] == '*') || destaddr.s_addr == ncent[i].addr.s_addr || ncent[i].name[0] == '*')
nocache = 1; nocache = 1;
} }
if(nocache || !ap_proxy_cache_should_cache(r, resp_hdrs, !backasswards)) if(nocache || !ap_proxy_cache_should_cache(r, resp_hdrs, !backasswards))
ap_proxy_cache_error(&c); ap_proxy_cache_error(&c);
else else
ap_cache_el_data(c, &cachefp); ap_cache_el_data(c, &cachefp);
/* write status line */ /* write status line */
if (!r->assbackwards) if (!r->assbackwards)
ap_rvputs(r, "HTTP/1.0 ", r->status_line, CRLF, NULL); ap_rvputs(r, "HTTP/1.0 ", r->status_line, CRLF, NULL);
if (cachefp && apr_puts(apr_pstrcat(r->pool, "HTTP/1.0 ", r->status_line, CRLF, NULL), cachefp) != APR_SUCCESS) { if (cachefp && apr_puts(apr_pstrcat(r->pool, "HTTP/1.0 ",
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, r->status_line, CRLF, NULL), cachefp) != APR_SUCCESS) {
"proxy: error writing status line to cache"); ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
ap_proxy_cache_error(&c); "proxy: error writing status line to cache");
cachefp = NULL; ap_proxy_cache_error(&c);
cachefp = NULL;
} }
/* send headers */ /* send headers */
ap_cache_el_header_walk(c, ap_proxy_send_hdr_line, r, NULL); ap_cache_el_header_walk(c, ap_proxy_send_hdr_line, r, NULL);
if (!r->assbackwards) if (!r->assbackwards)
ap_rputs(CRLF, r); ap_rputs(CRLF, r);
ap_bsetopt(r->connection->client, BO_BYTECT, &zero); ap_bsetopt(r->connection->client, BO_BYTECT, &zero);
r->sent_bodyct = 1; r->sent_bodyct = 1;
/* Is it an HTTP/0.9 respose? If so, send the extra data */ /* Is it an HTTP/0.9 response? If so, send the extra data */
if (backasswards) { if (backasswards) {
ap_bwrite(r->connection->client, buffer, len, &cntr); ap_bwrite(r->connection->client, buffer, len, &cntr);
cntr = len; cntr = len;
if (cachefp && apr_write(cachefp, buffer, &cntr) != APR_SUCCESS) { if (cachefp && apr_write(cachefp, buffer, &cntr) != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"proxy: error writing extra data to cache %ld", "proxy: error writing extra data to cache");
(long)cachefp); ap_proxy_cache_error(&c);
ap_proxy_cache_error(&c); }
}
} }
#ifdef CHARSET_EBCDIC #ifdef CHARSET_EBCDIC
@@ -471,14 +476,14 @@ int ap_proxy_http_handler(request_rec *r, ap_cache_el *c, char *url,
ap_bsetflag(r->connection->client, B_ASCII2EBCDIC|B_EBCDIC2ASCII, 0); ap_bsetflag(r->connection->client, B_ASCII2EBCDIC|B_EBCDIC2ASCII, 0);
#endif #endif
/* send body */ /* send body */
/* if header only, then cache will be NULL */ /* if header only, then cache will be NULL */
/* HTTP/1.0 tells us to read to EOF, rather than content-length bytes */ /* HTTP/1.0 tells us to read to EOF, rather than content-length bytes */
if (!r->header_only) { if (!r->header_only) {
proxy_completion pc; proxy_completion pc;
pc.content_length = content_length; pc.content_length = content_length;
pc.cache_completion = conf->cache_completion; pc.cache_completion = conf->cache_completion;
ap_proxy_send_fb(&pc, f, r, c); ap_proxy_send_fb(&pc, f, r, c);
} }
ap_bclose(f); ap_bclose(f);

File diff suppressed because it is too large Load Diff