mirror of
https://github.com/apache/httpd.git
synced 2025-08-08 15:02:10 +03:00
New mod_proxy/mod_cache (file cache) for 2.0. This uses a caching API so
that shared mem, LDAP servers, DBs, etc. can also be used for proxy caching. The caching API is very young, and subject to change as APR changes. proxy_cache.c from the proxy subdir is no longer used. Build with --enable-modules=proxy,cache Lightly tested on Linux, no warranties expressed or implied yet. Still to do: strerror(), waitpid(), stat() cleanups address issues marked by @@@FIXME add HTTP/1.1 This should be considered a *reference* proxy implementation for 2.0. What actually ends up shipping with 2.0 is likely going to be rather different as the redesign evolves. This may end up being the 2.0 backwards compatibility workalike. Modified to work with today's conf/build/layout scheme PR: Obtained from: Submitted by: Sam Magnuson Reviewed by: Chuck Murcko git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@85552 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
5
modules/proxy/Makefile.in
Normal file
5
modules/proxy/Makefile.in
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
LTLIBRARY_NAME = libapachemod_proxy.la
|
||||||
|
LTLIBRARY_SOURCES = mod_proxy.lo proxy_connect.lo proxy_ftp.lo proxy_http.lo proxy_util.lo
|
||||||
|
|
||||||
|
include $(top_srcdir)/build/ltlib.mk
|
32
modules/proxy/config.m4
Normal file
32
modules/proxy/config.m4
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
dnl modules enabled in this directory by default
|
||||||
|
|
||||||
|
dnl AC_DEFUN(modulename, modulestructname, defaultonoroff, configmacros)
|
||||||
|
dnl XXX - Need to add help text to --enable-module flags
|
||||||
|
dnl XXX - Need to allow --enable-module to fail if optional config fails
|
||||||
|
|
||||||
|
AC_DEFUN(APACHE_CHECK_PROXY_MODULE, [
|
||||||
|
APACHE_MODULE($1,,,$2,$3,$4)
|
||||||
|
])
|
||||||
|
|
||||||
|
APACHE_MODPATH_INIT(proxy)
|
||||||
|
|
||||||
|
APACHE_CHECK_PROXY_MODULE(proxy, , yes)
|
||||||
|
|
||||||
|
dnl APACHE_CHECK_STANDARD_MODULE(auth_db, , no, [
|
||||||
|
dnl AC_CHECK_HEADERS(db.h)
|
||||||
|
dnl AC_CHECK_LIB(db,main)
|
||||||
|
dnl ])
|
||||||
|
|
||||||
|
dnl APACHE_CHECK_STANDARD_MODULE(usertrack, , no, [
|
||||||
|
dnl AC_CHECK_HEADERS(sys/times.h)
|
||||||
|
dnl AC_CHECK_FUNCS(times)
|
||||||
|
dnl ])
|
||||||
|
|
||||||
|
APACHE_MODPATH_FINISH
|
||||||
|
|
||||||
|
if test "$sharedobjs" = "yes"; then
|
||||||
|
LIBS="$LIBS -ldl"
|
||||||
|
LTFLAGS="$LTFLAGS -export-dynamic"
|
||||||
|
fi
|
||||||
|
|
||||||
|
APACHE_SUBST(STANDARD_LIBS)
|
@@ -63,6 +63,7 @@
|
|||||||
#include "http_log.h"
|
#include "http_log.h"
|
||||||
#include "http_vhost.h"
|
#include "http_vhost.h"
|
||||||
#include "http_request.h"
|
#include "http_request.h"
|
||||||
|
#include "util_date.h"
|
||||||
|
|
||||||
/* Some WWW schemes and their default ports; this is basically /etc/services */
|
/* Some WWW schemes and their default ports; this is basically /etc/services */
|
||||||
/* This will become global when the protocol abstraction comes */
|
/* This will become global when the protocol abstraction comes */
|
||||||
@@ -234,19 +235,13 @@ static int proxy_fixup(request_rec *r)
|
|||||||
return OK; /* otherwise; we've done the best we can */
|
return OK; /* otherwise; we've done the best we can */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void proxy_init(server_rec *r, ap_pool_t *p)
|
/* Send a redirection if the request contains a hostname which is not
|
||||||
{
|
* fully qualified, i.e. doesn't have a domain name appended. Some proxy
|
||||||
ap_proxy_garbage_init(r, p);
|
* servers like Netscape's allow this and access hosts from the local
|
||||||
}
|
* domain in this case. I think it is better to redirect to a FQDN, since
|
||||||
|
* these will later be found in the bookmarks files.
|
||||||
|
* The "ProxyDomain" directive determines what domain will be appended
|
||||||
|
*/
|
||||||
/* Send a redirection if the request contains a hostname which is not */
|
|
||||||
/* fully qualified, i.e. doesn't have a domain name appended. Some proxy */
|
|
||||||
/* servers like Netscape's allow this and access hosts from the local */
|
|
||||||
/* domain in this case. I think it is better to redirect to a FQDN, since */
|
|
||||||
/* these will later be found in the bookmarks files. */
|
|
||||||
/* The "ProxyDomain" directive determines what domain will be appended */
|
|
||||||
static int proxy_needsdomain(request_rec *r, const char *url, const char *domain)
|
static int proxy_needsdomain(request_rec *r, const char *url, const char *domain)
|
||||||
{
|
{
|
||||||
char *nuri;
|
char *nuri;
|
||||||
@@ -272,7 +267,7 @@ static int proxy_needsdomain(request_rec *r, const char *url, const char *domain
|
|||||||
UNP_REVEALPASSWORD);
|
UNP_REVEALPASSWORD);
|
||||||
|
|
||||||
ap_table_set(r->headers_out, "Location", nuri);
|
ap_table_set(r->headers_out, "Location", nuri);
|
||||||
ap_log_rerror(APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, r,
|
ap_log_rerror(APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, 0, r,
|
||||||
"Domain missing: %s sent to %s%s%s", r->uri,
|
"Domain missing: %s sent to %s%s%s", r->uri,
|
||||||
ap_unparse_uri_components(r->pool, &r->parsed_uri,
|
ap_unparse_uri_components(r->pool, &r->parsed_uri,
|
||||||
UNP_OMITUSERINFO),
|
UNP_OMITUSERINFO),
|
||||||
@@ -288,20 +283,21 @@ static int proxy_handler(request_rec *r)
|
|||||||
{
|
{
|
||||||
char *url, *scheme, *p;
|
char *url, *scheme, *p;
|
||||||
void *sconf = r->server->module_config;
|
void *sconf = r->server->module_config;
|
||||||
proxy_server_conf *conf =
|
proxy_server_conf *conf = (proxy_server_conf *)
|
||||||
(proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
|
ap_get_module_config(sconf, &proxy_module);
|
||||||
ap_array_header_t *proxies = conf->proxies;
|
ap_array_header_t *proxies = conf->proxies;
|
||||||
struct proxy_remote *ents = (struct proxy_remote *) proxies->elts;
|
struct proxy_remote *ents = (struct proxy_remote *) proxies->elts;
|
||||||
int i, rc;
|
int i, rc;
|
||||||
cache_req *cr;
|
ap_cache_el *cr=NULL;
|
||||||
int direct_connect = 0;
|
int direct_connect = 0;
|
||||||
const char *maxfwd_str;
|
const char *maxfwd_str;
|
||||||
|
const char *pragma, *auth, *imstr;
|
||||||
|
|
||||||
if (!r->proxyreq || strncmp(r->filename, "proxy:", 6) != 0)
|
if (!r->proxyreq || strncmp(r->filename, "proxy:", 6) != 0)
|
||||||
return DECLINED;
|
return DECLINED;
|
||||||
|
|
||||||
if (r->method_number == M_TRACE &&
|
if (r->method_number == M_TRACE && (maxfwd_str =
|
||||||
(maxfwd_str = ap_table_get(r->headers_in, "Max-Forwards")) != NULL) {
|
ap_table_get(r->headers_in, "Max-Forwards")) != NULL) {
|
||||||
int maxfwd = strtol(maxfwd_str, NULL, 10);
|
int maxfwd = strtol(maxfwd_str, NULL, 10);
|
||||||
if (maxfwd < 1) {
|
if (maxfwd < 1) {
|
||||||
int access_status;
|
int access_status;
|
||||||
@@ -324,9 +320,56 @@ static int proxy_handler(request_rec *r)
|
|||||||
if (p == NULL)
|
if (p == NULL)
|
||||||
return HTTP_BAD_REQUEST;
|
return HTTP_BAD_REQUEST;
|
||||||
|
|
||||||
rc = ap_proxy_cache_check(r, url, &conf->cache, &cr);
|
pragma = ap_table_get(r->headers_in, "Pragma");
|
||||||
if (rc != DECLINED)
|
auth = ap_table_get(r->headers_in, "Authorization");
|
||||||
return rc;
|
imstr = ap_table_get(r->headers_in, "If-Modified-Since");
|
||||||
|
|
||||||
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"Request for %s, pragma=%s, auth=%s, imstr=%s", url,
|
||||||
|
pragma, auth, imstr);
|
||||||
|
|
||||||
|
/* can this request be cached at all? */
|
||||||
|
if (r->method_number == M_GET && strlen(url) < 1024 &&
|
||||||
|
!ap_proxy_liststr(pragma, "no-cache") && auth == NULL)
|
||||||
|
{
|
||||||
|
if(ap_cache_seek(conf->cache, url, &cr) == APR_SUCCESS)
|
||||||
|
{
|
||||||
|
int has_m = 0;
|
||||||
|
/* now we need to check if the last modified date is write if */
|
||||||
|
|
||||||
|
if(imstr)
|
||||||
|
{
|
||||||
|
time_t ims = (time_t)ap_parseHTTPdate(ap_proxy_date_canon(r->pool, imstr));
|
||||||
|
if(ims == BAD_DATE)
|
||||||
|
ap_table_unset(r->headers_in, "If-Modified-Since");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* ok we were asked to check, so let's do that */
|
||||||
|
if(ap_cache_el_header(cr, "Last-Modified",
|
||||||
|
(char **)&imstr) == APR_SUCCESS)
|
||||||
|
{
|
||||||
|
time_t lm =
|
||||||
|
ap_parseHTTPdate(ap_proxy_date_canon(r->pool, imstr));
|
||||||
|
if(lm != BAD_DATE)
|
||||||
|
{
|
||||||
|
if(ims < lm)
|
||||||
|
ap_table_set(r->headers_in,
|
||||||
|
"If-Modified-Since", imstr);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
has_m = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return has_m ? HTTP_NOT_MODIFIED : ap_proxy_cache_send(r, cr);
|
||||||
|
}
|
||||||
|
/* if there wasn't an entry in the cache we get here,
|
||||||
|
we need to create one */
|
||||||
|
ap_cache_create(conf->cache, url, &cr);
|
||||||
|
}
|
||||||
|
|
||||||
/* If the host doesn't have a domain name, add one and redirect. */
|
/* If the host doesn't have a domain name, add one and redirect. */
|
||||||
if (conf->domain != NULL) {
|
if (conf->domain != NULL) {
|
||||||
@@ -351,7 +394,7 @@ static int proxy_handler(request_rec *r)
|
|||||||
direct_connect = list[ii].matcher(&list[ii], r);
|
direct_connect = list[ii].matcher(&list[ii], r);
|
||||||
}
|
}
|
||||||
#if DEBUGGING
|
#if DEBUGGING
|
||||||
ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, r,
|
ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
|
||||||
(direct_connect) ? "NoProxy for %s" : "UseProxy for %s",
|
(direct_connect) ? "NoProxy for %s" : "UseProxy for %s",
|
||||||
r->uri);
|
r->uri);
|
||||||
#endif
|
#endif
|
||||||
@@ -404,8 +447,7 @@ static int proxy_handler(request_rec *r)
|
|||||||
/* -------------------------------------------------------------- */
|
/* -------------------------------------------------------------- */
|
||||||
/* Setup configurable data */
|
/* Setup configurable data */
|
||||||
|
|
||||||
static void *
|
static void *create_proxy_config(ap_pool_t *p, server_rec *s)
|
||||||
create_proxy_config(ap_pool_t *p, server_rec *s)
|
|
||||||
{
|
{
|
||||||
proxy_server_conf *ps = ap_pcalloc(p, sizeof(proxy_server_conf));
|
proxy_server_conf *ps = ap_pcalloc(p, sizeof(proxy_server_conf));
|
||||||
|
|
||||||
@@ -416,21 +458,12 @@ static void *
|
|||||||
ps->dirconn = ap_make_array(p, 10, sizeof(struct dirconn_entry));
|
ps->dirconn = ap_make_array(p, 10, sizeof(struct dirconn_entry));
|
||||||
ps->nocaches = ap_make_array(p, 10, sizeof(struct nocache_entry));
|
ps->nocaches = ap_make_array(p, 10, sizeof(struct nocache_entry));
|
||||||
ps->allowed_connect_ports = ap_make_array(p, 10, sizeof(int));
|
ps->allowed_connect_ports = ap_make_array(p, 10, sizeof(int));
|
||||||
|
ps->cache_completion = DEFAULT_CACHE_COMPLETION;
|
||||||
ps->domain = NULL;
|
ps->domain = NULL;
|
||||||
ps->viaopt = via_off; /* initially backward compatible with 1.3.1 */
|
ps->viaopt = via_off; /* initially backward compatible with 1.3.1 */
|
||||||
ps->req = 0;
|
ps->req = 0;
|
||||||
|
|
||||||
ps->cache.root = NULL;
|
ap_cache_init(&ps->cache, "mod_proxy cache", s);
|
||||||
ps->cache.space = DEFAULT_CACHE_SPACE;
|
|
||||||
ps->cache.maxexpire = DEFAULT_CACHE_MAXEXPIRE;
|
|
||||||
ps->cache.defaultexpire = DEFAULT_CACHE_EXPIRE;
|
|
||||||
ps->cache.lmfactor = DEFAULT_CACHE_LMFACTOR;
|
|
||||||
ps->cache.gcinterval = -1;
|
|
||||||
/* at these levels, the cache can have 2^18 directories (256,000) */
|
|
||||||
ps->cache.dirlevels = 3;
|
|
||||||
ps->cache.dirlength = 1;
|
|
||||||
ps->cache.cache_completion = DEFAULT_CACHE_COMPLETION;
|
|
||||||
|
|
||||||
return ps;
|
return ps;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -476,6 +509,36 @@ static const char *
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
set_cache_exclude(cmd_parms *cmd, void *dummy, char *arg)
|
||||||
|
{
|
||||||
|
server_rec *s = cmd->server;
|
||||||
|
proxy_server_conf *psf = (proxy_server_conf *) ap_get_module_config(s->module_config, &proxy_module);
|
||||||
|
struct nocache_entry *new;
|
||||||
|
struct nocache_entry *list = (struct nocache_entry *) psf->nocaches->elts;
|
||||||
|
struct hostent hp;
|
||||||
|
int found = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Don't duplicate entries */
|
||||||
|
for (i = 0; i < psf->nocaches->nelts; i++) {
|
||||||
|
if (strcasecmp(arg, list[i].name) == 0) /* ignore case for host names */
|
||||||
|
found = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
new = ap_push_array(psf->nocaches);
|
||||||
|
new->name = arg;
|
||||||
|
/* Don't do name lookups on things that aren't dotted */
|
||||||
|
if (strchr(arg, '.') != NULL && ap_proxy_host2addr(new->name, &hp) == NULL)
|
||||||
|
/*@@@FIXME: This copies only the first of (possibly many) IP addrs */
|
||||||
|
memcpy(&new->addr, hp.h_addr, sizeof(struct in_addr));
|
||||||
|
else
|
||||||
|
new->addr.s_addr = 0;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
add_pass(cmd_parms *cmd, void *dummy, char *f, char *r)
|
add_pass(cmd_parms *cmd, void *dummy, char *f, char *r)
|
||||||
{
|
{
|
||||||
@@ -505,8 +568,7 @@ static const char *
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *
|
static const char *set_proxy_exclude(cmd_parms *parms, void *dummy, char *arg)
|
||||||
set_proxy_exclude(cmd_parms *parms, void *dummy, char *arg)
|
|
||||||
{
|
{
|
||||||
server_rec *s = parms->server;
|
server_rec *s = parms->server;
|
||||||
proxy_server_conf *conf =
|
proxy_server_conf *conf =
|
||||||
@@ -582,30 +644,30 @@ static const char *
|
|||||||
|
|
||||||
if (ap_proxy_is_ipaddr(New, parms->pool)) {
|
if (ap_proxy_is_ipaddr(New, parms->pool)) {
|
||||||
#if DEBUGGING
|
#if DEBUGGING
|
||||||
ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
|
ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, 0, NULL,
|
||||||
"Parsed addr %s", inet_ntoa(New->addr));
|
"Parsed addr %s", inet_ntoa(New->addr));
|
||||||
ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
|
ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, 0, NULL,
|
||||||
"Parsed mask %s", inet_ntoa(New->mask));
|
"Parsed mask %s", inet_ntoa(New->mask));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else if (ap_proxy_is_domainname(New, parms->pool)) {
|
else if (ap_proxy_is_domainname(New, parms->pool)) {
|
||||||
ap_str_tolower(New->name);
|
ap_str_tolower(New->name);
|
||||||
#if DEBUGGING
|
#if DEBUGGING
|
||||||
ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
|
ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, 0, NULL,
|
||||||
"Parsed domain %s", New->name);
|
"Parsed domain %s", New->name);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else if (ap_proxy_is_hostname(New, parms->pool)) {
|
else if (ap_proxy_is_hostname(New, parms->pool)) {
|
||||||
ap_str_tolower(New->name);
|
ap_str_tolower(New->name);
|
||||||
#if DEBUGGING
|
#if DEBUGGING
|
||||||
ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
|
ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, 0, NULL,
|
||||||
"Parsed host %s", New->name);
|
"Parsed host %s", New->name);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ap_proxy_is_word(New, parms->pool);
|
ap_proxy_is_word(New, parms->pool);
|
||||||
#if DEBUGGING
|
#if DEBUGGING
|
||||||
ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
|
ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, 0, NULL,
|
||||||
"Parsed word %s", New->name);
|
"Parsed word %s", New->name);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -637,146 +699,6 @@ static const char *
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const char *
|
|
||||||
set_cache_size(cmd_parms *parms, char *struct_ptr, char *arg)
|
|
||||||
{
|
|
||||||
proxy_server_conf *psf =
|
|
||||||
ap_get_module_config(parms->server->module_config, &proxy_module);
|
|
||||||
int val;
|
|
||||||
|
|
||||||
if (sscanf(arg, "%d", &val) != 1)
|
|
||||||
return "CacheSize value must be an integer (kBytes)";
|
|
||||||
psf->cache.space = val;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *
|
|
||||||
set_cache_root(cmd_parms *parms, void *dummy, char *arg)
|
|
||||||
{
|
|
||||||
proxy_server_conf *psf =
|
|
||||||
ap_get_module_config(parms->server->module_config, &proxy_module);
|
|
||||||
|
|
||||||
psf->cache.root = arg;
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *
|
|
||||||
set_cache_factor(cmd_parms *parms, void *dummy, char *arg)
|
|
||||||
{
|
|
||||||
proxy_server_conf *psf =
|
|
||||||
ap_get_module_config(parms->server->module_config, &proxy_module);
|
|
||||||
double val;
|
|
||||||
|
|
||||||
if (sscanf(arg, "%lg", &val) != 1)
|
|
||||||
return "CacheLastModifiedFactor value must be a float";
|
|
||||||
psf->cache.lmfactor = val;
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *
|
|
||||||
set_cache_maxex(cmd_parms *parms, void *dummy, char *arg)
|
|
||||||
{
|
|
||||||
proxy_server_conf *psf =
|
|
||||||
ap_get_module_config(parms->server->module_config, &proxy_module);
|
|
||||||
double val;
|
|
||||||
|
|
||||||
if (sscanf(arg, "%lg", &val) != 1)
|
|
||||||
return "CacheMaxExpire value must be a float";
|
|
||||||
psf->cache.maxexpire = (int) (val * (double) SEC_ONE_HR);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *
|
|
||||||
set_cache_defex(cmd_parms *parms, void *dummy, char *arg)
|
|
||||||
{
|
|
||||||
proxy_server_conf *psf =
|
|
||||||
ap_get_module_config(parms->server->module_config, &proxy_module);
|
|
||||||
double val;
|
|
||||||
|
|
||||||
if (sscanf(arg, "%lg", &val) != 1)
|
|
||||||
return "CacheDefaultExpire value must be a float";
|
|
||||||
psf->cache.defaultexpire = (int) (val * (double) SEC_ONE_HR);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *
|
|
||||||
set_cache_gcint(cmd_parms *parms, void *dummy, char *arg)
|
|
||||||
{
|
|
||||||
proxy_server_conf *psf =
|
|
||||||
ap_get_module_config(parms->server->module_config, &proxy_module);
|
|
||||||
double val;
|
|
||||||
|
|
||||||
if (sscanf(arg, "%lg", &val) != 1)
|
|
||||||
return "CacheGcInterval value must be a float";
|
|
||||||
psf->cache.gcinterval = (int) (val * (double) SEC_ONE_HR);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *
|
|
||||||
set_cache_dirlevels(cmd_parms *parms, char *struct_ptr, char *arg)
|
|
||||||
{
|
|
||||||
proxy_server_conf *psf =
|
|
||||||
ap_get_module_config(parms->server->module_config, &proxy_module);
|
|
||||||
int val;
|
|
||||||
|
|
||||||
val = atoi(arg);
|
|
||||||
if (val < 1)
|
|
||||||
return "CacheDirLevels value must be an integer greater than 0";
|
|
||||||
if (val * psf->cache.dirlength > CACHEFILE_LEN)
|
|
||||||
return "CacheDirLevels*CacheDirLength value must not be higher than 20";
|
|
||||||
psf->cache.dirlevels = val;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *
|
|
||||||
set_cache_dirlength(cmd_parms *parms, char *struct_ptr, char *arg)
|
|
||||||
{
|
|
||||||
proxy_server_conf *psf =
|
|
||||||
ap_get_module_config(parms->server->module_config, &proxy_module);
|
|
||||||
int val;
|
|
||||||
|
|
||||||
val = atoi(arg);
|
|
||||||
if (val < 1)
|
|
||||||
return "CacheDirLength value must be an integer greater than 0";
|
|
||||||
if (val * psf->cache.dirlevels > CACHEFILE_LEN)
|
|
||||||
return "CacheDirLevels*CacheDirLength value must not be higher than 20";
|
|
||||||
psf->cache.dirlength = val;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *
|
|
||||||
set_cache_exclude(cmd_parms *parms, void *dummy, char *arg)
|
|
||||||
{
|
|
||||||
server_rec *s = parms->server;
|
|
||||||
proxy_server_conf *conf =
|
|
||||||
ap_get_module_config(s->module_config, &proxy_module);
|
|
||||||
struct nocache_entry *new;
|
|
||||||
struct nocache_entry *list = (struct nocache_entry *) conf->nocaches->elts;
|
|
||||||
struct hostent hp;
|
|
||||||
int found = 0;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* Don't duplicate entries */
|
|
||||||
for (i = 0; i < conf->nocaches->nelts; i++) {
|
|
||||||
if (strcasecmp(arg, list[i].name) == 0) /* ignore case for host names */
|
|
||||||
found = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found) {
|
|
||||||
new = ap_push_array(conf->nocaches);
|
|
||||||
new->name = arg;
|
|
||||||
/* Don't do name lookups on things that aren't dotted */
|
|
||||||
if (strchr(arg, '.') != NULL && ap_proxy_host2addr(new->name, &hp) == NULL)
|
|
||||||
/*@@@FIXME: This copies only the first of (possibly many) IP addrs */
|
|
||||||
memcpy(&new->addr, hp.h_addr, sizeof(struct in_addr));
|
|
||||||
else
|
|
||||||
new->addr.s_addr = 0;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
set_recv_buffer_size(cmd_parms *parms, void *dummy, char *arg)
|
set_recv_buffer_size(cmd_parms *parms, void *dummy, char *arg)
|
||||||
{
|
{
|
||||||
@@ -791,27 +713,10 @@ static const char *
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char*
|
|
||||||
set_cache_completion(cmd_parms *parms, void *dummy, char *arg)
|
|
||||||
{
|
|
||||||
proxy_server_conf *psf =
|
|
||||||
ap_get_module_config(parms->server->module_config, &proxy_module);
|
|
||||||
int s = atoi(arg);
|
|
||||||
if (s > 100 || s < 0) {
|
|
||||||
return "CacheForceCompletion must be <= 100 percent, "
|
|
||||||
"or 0 for system default.";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s > 0)
|
|
||||||
psf->cache.cache_completion = ((float)s / 100);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char*
|
static const char*
|
||||||
set_via_opt(cmd_parms *parms, void *dummy, char *arg)
|
set_via_opt(cmd_parms *parms, void *dummy, char *arg)
|
||||||
{
|
{
|
||||||
proxy_server_conf *psf =
|
proxy_server_conf *psf = ap_get_module_config(parms->server->module_config, &proxy_module);
|
||||||
ap_get_module_config(parms->server->module_config, &proxy_module);
|
|
||||||
|
|
||||||
if (strcasecmp(arg, "Off") == 0)
|
if (strcasecmp(arg, "Off") == 0)
|
||||||
psf->viaopt = via_off;
|
psf->viaopt = via_off;
|
||||||
@@ -829,6 +734,21 @@ static const char*
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char*
|
||||||
|
set_cache_completion(cmd_parms *parms, void *dummy, char *arg)
|
||||||
|
{
|
||||||
|
proxy_server_conf *psf = ap_get_module_config(parms->server->module_config, &proxy_module);
|
||||||
|
int s = atoi(arg);
|
||||||
|
if (s > 100 || s < 0) {
|
||||||
|
return "CacheForceCompletion must be <= 100 percent, "
|
||||||
|
"or 0 for system default.";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s > 0)
|
||||||
|
psf->cache_completion = ((float)s / 100);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static const handler_rec proxy_handlers[] =
|
static const handler_rec proxy_handlers[] =
|
||||||
{
|
{
|
||||||
{"proxy-server", proxy_handler},
|
{"proxy-server", proxy_handler},
|
||||||
@@ -855,50 +775,34 @@ static const command_rec proxy_cmds[] =
|
|||||||
"The default intranet domain name (in absence of a domain in the URL)"},
|
"The default intranet domain name (in absence of a domain in the URL)"},
|
||||||
{"AllowCONNECT", set_allowed_ports, NULL, RSRC_CONF, ITERATE,
|
{"AllowCONNECT", set_allowed_ports, NULL, RSRC_CONF, ITERATE,
|
||||||
"A list of ports which CONNECT may connect to"},
|
"A list of ports which CONNECT may connect to"},
|
||||||
{"CacheRoot", set_cache_root, NULL, RSRC_CONF, TAKE1,
|
|
||||||
"The directory to store cache files"},
|
|
||||||
{"CacheSize", set_cache_size, NULL, RSRC_CONF, TAKE1,
|
|
||||||
"The maximum disk space used by the cache in Kb"},
|
|
||||||
{"CacheMaxExpire", set_cache_maxex, NULL, RSRC_CONF, TAKE1,
|
|
||||||
"The maximum time in hours to cache a document"},
|
|
||||||
{"CacheDefaultExpire", set_cache_defex, NULL, RSRC_CONF, TAKE1,
|
|
||||||
"The default time in hours to cache a document"},
|
|
||||||
{"CacheLastModifiedFactor", set_cache_factor, NULL, RSRC_CONF, TAKE1,
|
|
||||||
"The factor used to estimate Expires date from LastModified date"},
|
|
||||||
{"CacheGcInterval", set_cache_gcint, NULL, RSRC_CONF, TAKE1,
|
|
||||||
"The interval between garbage collections, in hours"},
|
|
||||||
{"CacheDirLevels", set_cache_dirlevels, NULL, RSRC_CONF, TAKE1,
|
|
||||||
"The number of levels of subdirectories in the cache"},
|
|
||||||
{"CacheDirLength", set_cache_dirlength, NULL, RSRC_CONF, TAKE1,
|
|
||||||
"The number of characters in subdirectory names"},
|
|
||||||
{"NoCache", set_cache_exclude, NULL, RSRC_CONF, ITERATE,
|
|
||||||
"A list of names, hosts or domains for which caching is *not* provided"},
|
|
||||||
{"CacheForceCompletion", set_cache_completion, NULL, RSRC_CONF, TAKE1,
|
|
||||||
"Force a http cache completion after this percentage is loaded"},
|
|
||||||
{"ProxyVia", set_via_opt, NULL, RSRC_CONF, TAKE1,
|
{"ProxyVia", set_via_opt, NULL, RSRC_CONF, TAKE1,
|
||||||
"Configure Via: proxy header header to one of: on | off | block | full"},
|
"Configure Via: proxy header header to one of: on | off | block | full"},
|
||||||
|
{"ProxyNoCache", set_cache_exclude, NULL, RSRC_CONF, ITERATE,
|
||||||
|
"A list of names, hosts or domains for which caching is *not* provided"},
|
||||||
|
{"ProxyForceCacheCompletion", set_cache_completion, NULL, RSRC_CONF, TAKE1,
|
||||||
|
"Force a http cache completion after this percentage is loaded"},
|
||||||
|
|
||||||
{NULL}
|
{NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void register_hooks(void)
|
||||||
|
{
|
||||||
|
/* [2] filename-to-URI translation */
|
||||||
|
ap_hook_translate_name(proxy_trans, NULL, NULL, AP_HOOK_FIRST);
|
||||||
|
/* [8] fixups */
|
||||||
|
ap_hook_fixups(proxy_fixup, NULL, NULL, AP_HOOK_FIRST);
|
||||||
|
/* [1] post read_request handling */
|
||||||
|
ap_hook_post_read_request(proxy_detect, NULL, NULL, AP_HOOK_FIRST);
|
||||||
|
}
|
||||||
|
|
||||||
module MODULE_VAR_EXPORT proxy_module =
|
module MODULE_VAR_EXPORT proxy_module =
|
||||||
{
|
{
|
||||||
STANDARD_MODULE_STUFF,
|
STANDARD20_MODULE_STUFF,
|
||||||
proxy_init, /* initializer */
|
|
||||||
NULL, /* create per-directory config structure */
|
NULL, /* create per-directory config structure */
|
||||||
NULL, /* merge per-directory config structures */
|
NULL, /* merge per-directory config structures */
|
||||||
create_proxy_config, /* create per-server config structure */
|
create_proxy_config, /* create per-server config structure */
|
||||||
NULL, /* merge per-server config structures */
|
NULL, /* merge per-server config structures */
|
||||||
proxy_cmds, /* command ap_table_t */
|
proxy_cmds, /* command ap_table_t */
|
||||||
proxy_handlers, /* handlers */
|
proxy_handlers, /* handlers */
|
||||||
proxy_trans, /* translate_handler */
|
register_hooks
|
||||||
NULL, /* check_user_id */
|
|
||||||
NULL, /* check auth */
|
|
||||||
NULL, /* check access */
|
|
||||||
NULL, /* type_checker */
|
|
||||||
proxy_fixup, /* pre-run fixups */
|
|
||||||
NULL, /* logger */
|
|
||||||
NULL, /* header parser */
|
|
||||||
NULL, /* child_init */
|
|
||||||
NULL, /* child_exit */
|
|
||||||
proxy_detect /* post read-request */
|
|
||||||
};
|
};
|
||||||
|
@@ -75,13 +75,13 @@
|
|||||||
|
|
||||||
Things to do:
|
Things to do:
|
||||||
|
|
||||||
1. Make it garbage collect in the background, not while someone is waiting for
|
1. Make it garbage collect in the background, not while someone is
|
||||||
a response!
|
waiting for a response!
|
||||||
|
|
||||||
2. Check the logic thoroughly.
|
2. Check the logic thoroughly.
|
||||||
|
|
||||||
3. Empty directories are only removed the next time round (but this does avoid
|
3. Empty directories are only removed the next time round (but this does
|
||||||
two passes). Consider doing them the first time round.
|
avoid two passes). Consider doing them the first time round.
|
||||||
|
|
||||||
Ben Laurie <ben@algroup.co.uk> 30 Mar 96
|
Ben Laurie <ben@algroup.co.uk> 30 Mar 96
|
||||||
|
|
||||||
@@ -109,6 +109,7 @@
|
|||||||
#include "httpd.h"
|
#include "httpd.h"
|
||||||
#include "http_config.h"
|
#include "http_config.h"
|
||||||
#include "http_protocol.h"
|
#include "http_protocol.h"
|
||||||
|
#include "ap_cache.h"
|
||||||
|
|
||||||
#include "explain.h"
|
#include "explain.h"
|
||||||
|
|
||||||
@@ -123,14 +124,11 @@ enum enctype {
|
|||||||
#define HDR_APP (0) /* append header, for proxy_add_header() */
|
#define HDR_APP (0) /* append header, for proxy_add_header() */
|
||||||
#define HDR_REP (1) /* replace header, for proxy_add_header() */
|
#define HDR_REP (1) /* replace header, for proxy_add_header() */
|
||||||
|
|
||||||
/* number of characters in the hash */
|
#ifdef CHARSET_EBCDIC
|
||||||
#define HASH_LEN (22*2)
|
#define CRLF "\r\n"
|
||||||
|
#else /*CHARSET_EBCDIC*/
|
||||||
/* maximum 'CacheDirLevels*CacheDirLength' value */
|
#define CRLF "\015\012"
|
||||||
#define CACHEFILE_LEN 20 /* must be less than HASH_LEN/2 */
|
#endif /*CHARSET_EBCDIC*/
|
||||||
|
|
||||||
#define SEC_ONE_DAY 86400 /* one day, in seconds */
|
|
||||||
#define SEC_ONE_HR 3600 /* one hour, in seconds */
|
|
||||||
|
|
||||||
#define DEFAULT_FTP_DATA_PORT 20
|
#define DEFAULT_FTP_DATA_PORT 20
|
||||||
#define DEFAULT_FTP_PORT 21
|
#define DEFAULT_FTP_PORT 21
|
||||||
@@ -141,6 +139,7 @@ enum enctype {
|
|||||||
#define DEFAULT_SNEWS_PORT 563
|
#define DEFAULT_SNEWS_PORT 563
|
||||||
#define DEFAULT_PROSPERO_PORT 1525 /* WARNING: conflict w/Oracle */
|
#define DEFAULT_PROSPERO_PORT 1525 /* WARNING: conflict w/Oracle */
|
||||||
|
|
||||||
|
#define DEFAULT_CACHE_COMPLETION (0.9)
|
||||||
/* Some WWW schemes and their default ports; this is basically /etc/services */
|
/* Some WWW schemes and their default ports; this is basically /etc/services */
|
||||||
struct proxy_services {
|
struct proxy_services {
|
||||||
const char *scheme;
|
const char *scheme;
|
||||||
@@ -177,27 +176,7 @@ struct nocache_entry {
|
|||||||
struct in_addr addr;
|
struct in_addr addr;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DEFAULT_CACHE_SPACE 5
|
|
||||||
#define DEFAULT_CACHE_MAXEXPIRE SEC_ONE_DAY
|
|
||||||
#define DEFAULT_CACHE_EXPIRE SEC_ONE_HR
|
|
||||||
#define DEFAULT_CACHE_LMFACTOR (0.1)
|
|
||||||
#define DEFAULT_CACHE_COMPLETION (0.9)
|
|
||||||
|
|
||||||
/* static information about the local cache */
|
|
||||||
struct cache_conf {
|
|
||||||
const char *root; /* the location of the cache directory */
|
|
||||||
off_t space; /* Maximum cache size (in 1024 bytes) */
|
|
||||||
time_t maxexpire; /* Maximum time to keep cached files in secs */
|
|
||||||
time_t defaultexpire; /* default time to keep cached file in secs */
|
|
||||||
double lmfactor; /* factor for estimating expires date */
|
|
||||||
time_t gcinterval; /* garbage collection interval, in seconds */
|
|
||||||
int dirlevels; /* Number of levels of subdirectories */
|
|
||||||
int dirlength; /* Length of subdirectory names */
|
|
||||||
float cache_completion; /* Force cache completion after this point */
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
struct cache_conf cache; /* cache configuration */
|
|
||||||
ap_array_header_t *proxies;
|
ap_array_header_t *proxies;
|
||||||
ap_array_header_t *aliases;
|
ap_array_header_t *aliases;
|
||||||
ap_array_header_t *raliases;
|
ap_array_header_t *raliases;
|
||||||
@@ -205,8 +184,10 @@ typedef struct {
|
|||||||
ap_array_header_t *dirconn;
|
ap_array_header_t *dirconn;
|
||||||
ap_array_header_t *nocaches;
|
ap_array_header_t *nocaches;
|
||||||
ap_array_header_t *allowed_connect_ports;
|
ap_array_header_t *allowed_connect_ports;
|
||||||
char *domain; /* domain name to use in absence of a domain name in the request */
|
char *domain; /* domain name to use in absence of
|
||||||
|
a domain name in the request */
|
||||||
int req; /* true if proxy requests are enabled */
|
int req; /* true if proxy requests are enabled */
|
||||||
|
float cache_completion; /* Force cache completion after this point */
|
||||||
enum {
|
enum {
|
||||||
via_off,
|
via_off,
|
||||||
via_on,
|
via_on,
|
||||||
@@ -214,68 +195,31 @@ typedef struct {
|
|||||||
via_full
|
via_full
|
||||||
} viaopt; /* how to deal with proxy Via: headers */
|
} viaopt; /* how to deal with proxy Via: headers */
|
||||||
size_t recv_buffer_size;
|
size_t recv_buffer_size;
|
||||||
|
ap_cache_handle_t *cache;
|
||||||
} proxy_server_conf;
|
} proxy_server_conf;
|
||||||
|
|
||||||
struct hdr_entry {
|
|
||||||
const char *field;
|
|
||||||
const char *value;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* caching information about a request */
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
request_rec *req; /* the request */
|
float cache_completion; /* completion percentage */
|
||||||
char *url; /* the URL requested */
|
int content_length; /* length of the content */
|
||||||
char *filename; /* name of the cache file, or NULL if no cache */
|
} proxy_completion;
|
||||||
char *tempfile; /* name of the temporary file, of NULL if not caching */
|
|
||||||
time_t ims; /* if-modified-since date of request; -1 if no header */
|
|
||||||
BUFF *fp; /* the cache file descriptor if the file is cached
|
|
||||||
and may be returned, or NULL if the file is
|
|
||||||
not cached (or must be reloaded) */
|
|
||||||
time_t expire; /* calculated expire date of cached entity */
|
|
||||||
time_t lmod; /* last-modified date of cached entity */
|
|
||||||
time_t date; /* the date the cached file was last touched */
|
|
||||||
int version; /* update count of the file */
|
|
||||||
off_t len; /* content length */
|
|
||||||
char *protocol; /* Protocol, and major/minor number, e.g. HTTP/1.1 */
|
|
||||||
int status; /* the status of the cached file */
|
|
||||||
unsigned int written; /* total *content* bytes written to cache */
|
|
||||||
float cache_completion; /* specific to this request */
|
|
||||||
char *resp_line; /* the whole status like (protocol, code + message) */
|
|
||||||
ap_table_t *hdrs; /* the HTTP headers of the file */
|
|
||||||
} cache_req;
|
|
||||||
|
|
||||||
/* Additional information passed to the function called by ap_table_do() */
|
|
||||||
struct tbl_do_args {
|
|
||||||
request_rec *req;
|
|
||||||
cache_req *cache;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Function prototypes */
|
/* Function prototypes */
|
||||||
|
|
||||||
/* proxy_cache.c */
|
|
||||||
|
|
||||||
void ap_proxy_cache_tidy(cache_req *c);
|
|
||||||
int ap_proxy_cache_check(request_rec *r, char *url, struct cache_conf *conf,
|
|
||||||
cache_req **cr);
|
|
||||||
int ap_proxy_cache_update(cache_req *c, ap_table_t *resp_hdrs,
|
|
||||||
const int is_HTTP1, int nocache);
|
|
||||||
void ap_proxy_garbage_coll(request_rec *r);
|
|
||||||
|
|
||||||
/* proxy_connect.c */
|
/* proxy_connect.c */
|
||||||
|
|
||||||
int ap_proxy_connect_handler(request_rec *r, cache_req *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);
|
||||||
|
|
||||||
/* proxy_ftp.c */
|
/* proxy_ftp.c */
|
||||||
|
|
||||||
int ap_proxy_ftp_canon(request_rec *r, char *url);
|
int ap_proxy_ftp_canon(request_rec *r, char *url);
|
||||||
int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url);
|
int ap_proxy_ftp_handler(request_rec *r, ap_cache_el *c, char *url);
|
||||||
|
|
||||||
/* proxy_http.c */
|
/* proxy_http.c */
|
||||||
|
|
||||||
int ap_proxy_http_canon(request_rec *r, char *url, const char *scheme,
|
int ap_proxy_http_canon(request_rec *r, char *url, const char *scheme,
|
||||||
int def_port);
|
int def_port);
|
||||||
int ap_proxy_http_handler(request_rec *r, cache_req *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);
|
||||||
|
|
||||||
/* proxy_util.c */
|
/* proxy_util.c */
|
||||||
@@ -287,24 +231,24 @@ char *ap_proxy_canonenc(ap_pool_t *p, const char *x, int len, enum enctype t,
|
|||||||
char *ap_proxy_canon_netloc(ap_pool_t *p, char **const urlp, char **userp,
|
char *ap_proxy_canon_netloc(ap_pool_t *p, char **const urlp, char **userp,
|
||||||
char **passwordp, char **hostp, int *port);
|
char **passwordp, char **hostp, int *port);
|
||||||
const char *ap_proxy_date_canon(ap_pool_t *p, const char *x);
|
const char *ap_proxy_date_canon(ap_pool_t *p, const char *x);
|
||||||
table *ap_proxy_read_headers(request_rec *r, char *buffer, int size, BUFF *f);
|
ap_table_t *ap_proxy_read_headers(request_rec *r, char *buffer, int size, BUFF *f);
|
||||||
long int ap_proxy_send_fb(BUFF *f, request_rec *r, cache_req *c);
|
long int ap_proxy_send_fb(proxy_completion *, BUFF *f, request_rec *r, ap_cache_el *c);
|
||||||
void ap_proxy_send_headers(request_rec *r, const char *respline, ap_table_t *hdrs);
|
void ap_proxy_send_headers(request_rec *r, const char *respline, ap_table_t *hdrs);
|
||||||
int ap_proxy_liststr(const char *list, const char *val);
|
int ap_proxy_liststr(const char *list, const char *val);
|
||||||
void ap_proxy_hash(const char *it, char *val, int ndepth, int nlength);
|
void ap_proxy_hash(const char *it, char *val, int ndepth, int nlength);
|
||||||
int ap_proxy_hex2sec(const char *x);
|
int ap_proxy_hex2sec(const char *x);
|
||||||
void ap_proxy_sec2hex(int t, char *y);
|
void ap_proxy_sec2hex(int t, char *y);
|
||||||
cache_req *ap_proxy_cache_error(cache_req *r);
|
|
||||||
int ap_proxyerror(request_rec *r, int statuscode, const char *message);
|
|
||||||
const char *ap_proxy_host2addr(const char *host, struct hostent *reqhp);
|
const char *ap_proxy_host2addr(const char *host, struct hostent *reqhp);
|
||||||
|
void ap_proxy_cache_error(ap_cache_el **r);
|
||||||
|
int ap_proxyerror(request_rec *r, int statuscode, const char *message);
|
||||||
int ap_proxy_is_ipaddr(struct dirconn_entry *This, ap_pool_t *p);
|
int ap_proxy_is_ipaddr(struct dirconn_entry *This, ap_pool_t *p);
|
||||||
int ap_proxy_is_domainname(struct dirconn_entry *This, ap_pool_t *p);
|
int ap_proxy_is_domainname(struct dirconn_entry *This, ap_pool_t *p);
|
||||||
int ap_proxy_is_hostname(struct dirconn_entry *This, ap_pool_t *p);
|
int ap_proxy_is_hostname(struct dirconn_entry *This, ap_pool_t *p);
|
||||||
int ap_proxy_is_word(struct dirconn_entry *This, ap_pool_t *p);
|
int ap_proxy_is_word(struct dirconn_entry *This, ap_pool_t *p);
|
||||||
int ap_proxy_doconnect(int sock, struct sockaddr_in *addr, request_rec *r);
|
int ap_proxy_doconnect(ap_socket_t *sock, char *host, ap_uint32_t port, request_rec *r);
|
||||||
int ap_proxy_garbage_init(server_rec *, ap_pool_t *);
|
int ap_proxy_garbage_init(server_rec *, ap_pool_t *);
|
||||||
/* This function is called by ap_table_do() for all header lines */
|
/* This function is called by ap_table_do() for all header lines */
|
||||||
int ap_proxy_send_hdr_line(void *p, const char *key, const char *value);
|
int ap_proxy_send_hdr_line(void *p, const char *key, const char *value);
|
||||||
unsigned ap_proxy_bputs2(const char *data, BUFF *client, cache_req *cache);
|
unsigned ap_proxy_bputs2(const char *data, BUFF *client, ap_cache_el *cache);
|
||||||
|
|
||||||
#endif /*MOD_PROXY_H*/
|
#endif /*MOD_PROXY_H*/
|
||||||
|
@@ -61,13 +61,12 @@
|
|||||||
#include "mod_proxy.h"
|
#include "mod_proxy.h"
|
||||||
#include "http_log.h"
|
#include "http_log.h"
|
||||||
#include "http_main.h"
|
#include "http_main.h"
|
||||||
|
#include "iol_socket.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
|
||||||
|
|
||||||
DEF_Explain
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This handles Netscape CONNECT method secure proxy requests.
|
* This handles Netscape CONNECT method secure proxy requests.
|
||||||
* A connection is opened to the specified host and data is
|
* A connection is opened to the specified host and data is
|
||||||
@@ -112,29 +111,29 @@ allowed_port(proxy_server_conf *conf, int port)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int ap_proxy_connect_handler(request_rec *r, cache_req *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 sockaddr_in server;
|
|
||||||
struct in_addr destaddr;
|
struct in_addr destaddr;
|
||||||
struct hostent server_hp;
|
|
||||||
const char *host, *err;
|
const char *host, *err;
|
||||||
char *p;
|
char *p;
|
||||||
int port, sock;
|
int port;
|
||||||
|
ap_socket_t *sock;
|
||||||
char buffer[HUGE_STRING_LEN];
|
char buffer[HUGE_STRING_LEN];
|
||||||
int nbytes, i, j;
|
int nbytes, i, j;
|
||||||
fd_set fds;
|
|
||||||
|
BUFF *sock_buff;
|
||||||
|
ap_socket_t *client_sock;
|
||||||
|
ap_pollfd_t *pollfd;
|
||||||
|
ap_int32_t pollcnt;
|
||||||
|
ap_int16_t pollevent;
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
memset(&server, '\0', sizeof(server));
|
|
||||||
server.sin_family = AF_INET;
|
|
||||||
|
|
||||||
/* Break the URL into host:port pairs */
|
/* Break the URL into host:port pairs */
|
||||||
|
|
||||||
host = url;
|
host = url;
|
||||||
p = strchr(url, ':');
|
p = strchr(url, ':');
|
||||||
if (p == NULL)
|
if (p == NULL)
|
||||||
@@ -167,55 +166,25 @@ int ap_proxy_connect_handler(request_rec *r, cache_req *c, char *url,
|
|||||||
return HTTP_FORBIDDEN;
|
return HTTP_FORBIDDEN;
|
||||||
|
|
||||||
if (proxyhost) {
|
if (proxyhost) {
|
||||||
Explain2("CONNECT to remote proxy %s on port %d", proxyhost, proxyport);
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"CONNECT to remote proxy %s on port %d", proxyhost, proxyport);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Explain2("CONNECT to %s on port %d", host, port);
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"CONNECT to %s on port %d", host, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
server.sin_port = (proxyport ? htons(proxyport) : htons(port));
|
if ((ap_create_tcp_socket(&sock, r->pool)) != APR_SUCCESS) {
|
||||||
err = ap_proxy_host2addr(proxyhost ? proxyhost : host, &server_hp);
|
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||||
|
|
||||||
if (err != NULL)
|
|
||||||
return ap_proxyerror(r,
|
|
||||||
proxyhost ? HTTP_BAD_GATEWAY : HTTP_INTERNAL_SERVER_ERROR,
|
|
||||||
err);
|
|
||||||
|
|
||||||
sock = ap_psocket(r->pool, PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
||||||
if (sock == -1) {
|
|
||||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
|
|
||||||
"proxy: error creating socket");
|
"proxy: error creating socket");
|
||||||
return HTTP_INTERNAL_SERVER_ERROR;
|
return HTTP_INTERNAL_SERVER_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CHECK_FD_SETSIZE
|
if (ap_proxy_doconnect(sock, (char *)(proxyhost ? proxyhost : host), proxyport ? proxyport : port, r) == -1) {
|
||||||
if (sock >= FD_SETSIZE) {
|
ap_close_socket(sock);
|
||||||
ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, NULL,
|
return ap_proxyerror(r, HTTP_INTERNAL_SERVER_ERROR,
|
||||||
"proxy_connect_handler: filedescriptor (%u) "
|
ap_pstrcat(r->pool, "Could not connect to remote machine:<br>",
|
||||||
"larger than FD_SETSIZE (%u) "
|
strerror(errno), NULL));
|
||||||
"found, you probably need to rebuild Apache with a "
|
|
||||||
"larger FD_SETSIZE", sock, FD_SETSIZE);
|
|
||||||
ap_pclosesocket(r->pool, sock);
|
|
||||||
return HTTP_INTERNAL_SERVER_ERROR;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
j = 0;
|
|
||||||
while (server_hp.h_addr_list[j] != NULL) {
|
|
||||||
memcpy(&server.sin_addr, server_hp.h_addr_list[j],
|
|
||||||
sizeof(struct in_addr));
|
|
||||||
i = ap_proxy_doconnect(sock, &server, r);
|
|
||||||
if (i == 0)
|
|
||||||
break;
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
if (i == -1) {
|
|
||||||
char buf[120];
|
|
||||||
ap_pclosesocket(r->pool, sock);
|
|
||||||
return ap_proxyerror(r, HTTP_INTERNAL_SERVER_ERROR, ap_pstrcat(r->pool,
|
|
||||||
"Could not connect to remote machine:<br>",
|
|
||||||
ap_strerror(errno, buf, sizeof(buf)),
|
|
||||||
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
|
||||||
@@ -226,66 +195,104 @@ int ap_proxy_connect_handler(request_rec *r, cache_req *c, char *url,
|
|||||||
* 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.
|
||||||
*/
|
*/
|
||||||
Explain0("Sending the CONNECT request to the remote proxy");
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
ap_snprintf(buffer, sizeof(buffer), "CONNECT %s HTTP/1.0" CRLF,
|
"Sending the CONNECT request to the remote proxy");
|
||||||
r->uri);
|
nbytes = ap_snprintf(buffer, sizeof(buffer), "CONNECT %s HTTP/1.0" CRLF, r->uri);
|
||||||
write(sock, buffer, strlen(buffer));
|
ap_send(sock, buffer, &nbytes);
|
||||||
ap_snprintf(buffer, sizeof(buffer),
|
nbytes = ap_snprintf(buffer, sizeof(buffer),"Proxy-agent: %s" CRLF CRLF, ap_get_server_version());
|
||||||
"Proxy-agent: %s" CRLF CRLF, ap_get_server_version());
|
ap_send(sock, buffer, &nbytes);
|
||||||
write(sock, buffer, strlen(buffer));
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Explain0("Returning 200 OK Status");
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"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);
|
||||||
|
ap_bpush_iol(sock_buff, unix_attach_socket(sock));
|
||||||
|
|
||||||
|
if(ap_setup_poll(&pollfd, 2, r->pool) != APR_SUCCESS)
|
||||||
|
{
|
||||||
|
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "proxy: error ap_setup_poll()");
|
||||||
|
return HTTP_INTERNAL_SERVER_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add client side to the poll */
|
||||||
|
#if 0
|
||||||
|
/* FIXME !!!! SDM !!! If someone can figure out how to turn a conn_rec into a ap_sock_t or something
|
||||||
|
this code might work. However if we must we can change r->connection->client to non-blocking and
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
if(ap_put_os_sock(&client_sock, (ap_os_sock_t *)get_socket(r->connection->client),
|
||||||
|
r->pool) != APR_SUCCESS)
|
||||||
|
{
|
||||||
|
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "proxy: error creating client ap_socket_t");
|
||||||
|
return HTTP_INTERNAL_SERVER_ERROR;
|
||||||
|
}
|
||||||
|
ap_add_poll_socket(pollfd, client_sock, APR_POLLIN);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Add the server side to the poll */
|
||||||
|
ap_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) */
|
||||||
FD_ZERO(&fds);
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL, "Going to sleep (poll)");
|
||||||
FD_SET(sock, &fds);
|
if(ap_poll(pollfd, &pollcnt, -1) != APR_SUCCESS)
|
||||||
FD_SET(r->connection->client->fd, &fds);
|
{
|
||||||
|
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "proxy: error ap_poll()");
|
||||||
|
return HTTP_INTERNAL_SERVER_ERROR;
|
||||||
|
}
|
||||||
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"Woke from select(), i=%d", pollcnt);
|
||||||
|
|
||||||
Explain0("Going to sleep (select)");
|
if (pollcnt) {
|
||||||
i = ap_select((r->connection->client->fd > sock ?
|
ap_get_revents(&pollevent, sock, pollfd);
|
||||||
r->connection->client->fd + 1 :
|
if (pollevent & APR_POLLIN) {
|
||||||
sock + 1), &fds, NULL, NULL, NULL);
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
Explain1("Woke from select(), i=%d", i);
|
"sock was set");
|
||||||
|
if(ap_bread(sock_buff, buffer, HUGE_STRING_LEN, &nbytes) == APR_SUCCESS) {
|
||||||
if (i) {
|
int o = 0;
|
||||||
if (FD_ISSET(sock, &fds)) {
|
while(nbytes)
|
||||||
Explain0("sock was set");
|
{
|
||||||
if ((nbytes = read(sock, buffer, HUGE_STRING_LEN)) != 0) {
|
ap_bwrite(r->connection->client, buffer + o, nbytes, &i);
|
||||||
if (nbytes == -1)
|
o += i;
|
||||||
break;
|
nbytes -= i;
|
||||||
if (write(r->connection->client->fd, buffer, nbytes) == EOF)
|
|
||||||
break;
|
|
||||||
Explain1("Wrote %d bytes to client", nbytes);
|
|
||||||
}
|
}
|
||||||
else
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
break;
|
"Wrote %d bytes to client", nbytes);
|
||||||
}
|
|
||||||
else if (FD_ISSET(r->connection->client->fd, &fds)) {
|
|
||||||
Explain0("client->fd was set");
|
|
||||||
if ((nbytes = read(r->connection->client->fd, buffer,
|
|
||||||
HUGE_STRING_LEN)) != 0) {
|
|
||||||
if (nbytes == -1)
|
|
||||||
break;
|
|
||||||
if (write(sock, buffer, nbytes) == EOF)
|
|
||||||
break;
|
|
||||||
Explain1("Wrote %d bytes to server", nbytes);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
break; /* Must be done waiting */
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ap_pclosesocket(r->pool, sock);
|
ap_get_revents(&pollevent, client_sock, pollfd);
|
||||||
|
if (pollevent & APR_POLLIN) {
|
||||||
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"client was set");
|
||||||
|
if(ap_bread(r->connection->client, buffer, HUGE_STRING_LEN, &nbytes) == APR_SUCCESS) {
|
||||||
|
int o = 0;
|
||||||
|
while(nbytes)
|
||||||
|
{
|
||||||
|
ap_bwrite(sock_buff, buffer + o, nbytes, &i);
|
||||||
|
o += i;
|
||||||
|
nbytes -= i;
|
||||||
|
}
|
||||||
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"Wrote %d bytes to server", nbytes);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ap_close_socket(sock);
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
@@ -62,10 +62,18 @@
|
|||||||
#include "http_main.h"
|
#include "http_main.h"
|
||||||
#include "http_log.h"
|
#include "http_log.h"
|
||||||
#include "http_core.h"
|
#include "http_core.h"
|
||||||
|
#include "iol_socket.h"
|
||||||
|
|
||||||
#define AUTODETECT_PWD
|
#define AUTODETECT_PWD
|
||||||
|
|
||||||
DEF_Explain
|
static void skiplf(BUFF *foo)
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
c = ap_bgetc(foo);
|
||||||
|
} while(c != '\n');
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Decodes a '%' escaped string, and returns the number of characters
|
* Decodes a '%' escaped string, and returns the number of characters
|
||||||
@@ -206,7 +214,7 @@ static int ftp_getrc(BUFF *f)
|
|||||||
status = 100 * linebuff[0] + 10 * linebuff[1] + linebuff[2] - 111 * '0';
|
status = 100 * linebuff[0] + 10 * linebuff[1] + linebuff[2] - 111 * '0';
|
||||||
|
|
||||||
if (linebuff[len - 1] != '\n') {
|
if (linebuff[len - 1] != '\n') {
|
||||||
(void)ap_bskiplf(f);
|
skiplf(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* skip continuation lines */
|
/* skip continuation lines */
|
||||||
@@ -218,7 +226,7 @@ static int ftp_getrc(BUFF *f)
|
|||||||
if (len == -1)
|
if (len == -1)
|
||||||
return -1;
|
return -1;
|
||||||
if (linebuff[len - 1] != '\n') {
|
if (linebuff[len - 1] != '\n') {
|
||||||
(void)ap_bskiplf(f);
|
skiplf(f);
|
||||||
}
|
}
|
||||||
} while (memcmp(linebuff, buff, 4) != 0);
|
} while (memcmp(linebuff, buff, 4) != 0);
|
||||||
}
|
}
|
||||||
@@ -249,7 +257,7 @@ static int ftp_getrc_msg(BUFF *f, char *msgbuf, int msglen)
|
|||||||
mb = ap_cpystrn(mb, linebuff+4, me - mb);
|
mb = ap_cpystrn(mb, linebuff+4, me - mb);
|
||||||
|
|
||||||
if (linebuff[len - 1] != '\n')
|
if (linebuff[len - 1] != '\n')
|
||||||
(void)ap_bskiplf(f);
|
skiplf(f);
|
||||||
|
|
||||||
if (linebuff[3] == '-') {
|
if (linebuff[3] == '-') {
|
||||||
memcpy(buff, linebuff, 3);
|
memcpy(buff, linebuff, 3);
|
||||||
@@ -259,7 +267,7 @@ static int ftp_getrc_msg(BUFF *f, char *msgbuf, int msglen)
|
|||||||
if (len == -1)
|
if (len == -1)
|
||||||
return -1;
|
return -1;
|
||||||
if (linebuff[len - 1] != '\n') {
|
if (linebuff[len - 1] != '\n') {
|
||||||
(void)ap_bskiplf(f);
|
skiplf(f);
|
||||||
}
|
}
|
||||||
mb = ap_cpystrn(mb, linebuff+4, me - mb);
|
mb = ap_cpystrn(mb, linebuff+4, me - mb);
|
||||||
} while (memcmp(linebuff, buff, 4) != 0);
|
} while (memcmp(linebuff, buff, 4) != 0);
|
||||||
@@ -267,7 +275,7 @@ static int ftp_getrc_msg(BUFF *f, char *msgbuf, int msglen)
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static long int send_dir(BUFF *f, request_rec *r, cache_req *c, char *cwd)
|
static long int send_dir(BUFF *f, request_rec *r, ap_cache_el *c, char *cwd)
|
||||||
{
|
{
|
||||||
char buf[IOBUFSIZE];
|
char buf[IOBUFSIZE];
|
||||||
char buf2[IOBUFSIZE];
|
char buf2[IOBUFSIZE];
|
||||||
@@ -275,10 +283,14 @@ static long int send_dir(BUFF *f, request_rec *r, cache_req *c, char *cwd)
|
|||||||
int searchidx = 0;
|
int searchidx = 0;
|
||||||
char *searchptr = NULL;
|
char *searchptr = NULL;
|
||||||
int firstfile = 1;
|
int firstfile = 1;
|
||||||
|
ap_ssize_t cntr;
|
||||||
unsigned long total_bytes_sent = 0;
|
unsigned long total_bytes_sent = 0;
|
||||||
register int n, o, w;
|
register int n, o, w;
|
||||||
conn_rec *con = r->connection;
|
conn_rec *con = r->connection;
|
||||||
char *dir, *path, *reldir, *site;
|
char *dir, *path, *reldir, *site;
|
||||||
|
BUFF *cachefp = NULL;
|
||||||
|
|
||||||
|
if(c) ap_cache_el_data(c, &cachefp);
|
||||||
|
|
||||||
/* Save "scheme://site" prefix without password */
|
/* Save "scheme://site" prefix without password */
|
||||||
site = ap_unparse_uri_components(r->pool, &r->parsed_uri, UNP_OMITPASSWORD|UNP_OMITPATHINFO);
|
site = ap_unparse_uri_components(r->pool, &r->parsed_uri, UNP_OMITPASSWORD|UNP_OMITPATHINFO);
|
||||||
@@ -325,9 +337,9 @@ static long int send_dir(BUFF *f, request_rec *r, cache_req *c, char *cwd)
|
|||||||
n = ap_bgets(buf, sizeof buf, f);
|
n = ap_bgets(buf, sizeof buf, f);
|
||||||
if (n == -1) { /* input error */
|
if (n == -1) { /* input error */
|
||||||
if (c != NULL) {
|
if (c != NULL) {
|
||||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
|
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||||
"proxy: error reading from %s", c->url);
|
"proxy: error reading from cache");
|
||||||
c = ap_proxy_cache_error(c);
|
ap_proxy_cache_error(&c);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -387,14 +399,15 @@ static long int send_dir(BUFF *f, request_rec *r, cache_req *c, char *cwd)
|
|||||||
o = 0;
|
o = 0;
|
||||||
total_bytes_sent += n;
|
total_bytes_sent += n;
|
||||||
|
|
||||||
if (c != NULL && c->fp && ap_bwrite(c->fp, buf, n) != n) {
|
if (cachefp && ap_bwrite(cachefp, buf, n, &cntr) != n) {
|
||||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
|
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||||
"proxy: error writing to %s", c->tempfile);
|
"proxy: error writing to cache");
|
||||||
c = ap_proxy_cache_error(c);
|
ap_proxy_cache_error(&c);
|
||||||
|
cachefp = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (n && !r->connection->aborted) {
|
while (n && !r->connection->aborted) {
|
||||||
w = ap_bwrite(con->client, &buf[o], n);
|
w = ap_bwrite(con->client, &buf[o], n, &cntr);
|
||||||
if (w <= 0)
|
if (w <= 0)
|
||||||
break;
|
break;
|
||||||
n -= w;
|
n -= w;
|
||||||
@@ -425,7 +438,7 @@ static int ftp_unauthorized (request_rec *r, int log_it)
|
|||||||
* (log username/password guessing attempts)
|
* (log username/password guessing attempts)
|
||||||
*/
|
*/
|
||||||
if (log_it)
|
if (log_it)
|
||||||
ap_log_rerror(APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, r,
|
ap_log_rerror(APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, 0, r,
|
||||||
"proxy: missing or failed auth to %s",
|
"proxy: missing or failed auth to %s",
|
||||||
ap_unparse_uri_components(r->pool,
|
ap_unparse_uri_components(r->pool,
|
||||||
&r->parsed_uri, UNP_OMITPATHINFO));
|
&r->parsed_uri, UNP_OMITPATHINFO));
|
||||||
@@ -445,27 +458,24 @@ static int ftp_unauthorized (request_rec *r, int log_it)
|
|||||||
* Troy Morrison <spiffnet@zoom.com>
|
* Troy Morrison <spiffnet@zoom.com>
|
||||||
* PASV added by Chuck
|
* PASV added by Chuck
|
||||||
*/
|
*/
|
||||||
int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url)
|
int ap_proxy_ftp_handler(request_rec *r, ap_cache_el *c, char *url)
|
||||||
{
|
{
|
||||||
char *host, *path, *strp, *parms;
|
char *host, *path, *strp, *parms, *server_addr;
|
||||||
char *cwd = NULL;
|
char *cwd = NULL;
|
||||||
char *user = NULL;
|
char *user = NULL;
|
||||||
/* char *account = NULL; how to supply an account in a URL? */
|
/* char *account = NULL; how to supply an account in a URL? */
|
||||||
const char *password = NULL;
|
const char *password = NULL;
|
||||||
const char *err;
|
const char *err;
|
||||||
int port, i, j, len, sock, dsock, rc, nocache = 0;
|
ap_socket_t *sock, *dsock, *inc;
|
||||||
int csd = 0;
|
int port, i, j, len, rc, nocache = 0;
|
||||||
struct sockaddr_in server;
|
ap_socket_t *csd;
|
||||||
struct hostent server_hp;
|
|
||||||
struct in_addr destaddr;
|
struct in_addr destaddr;
|
||||||
ap_table_t *resp_hdrs;
|
BUFF *f, *cachefp = NULL;
|
||||||
BUFF *f;
|
|
||||||
BUFF *data = NULL;
|
BUFF *data = NULL;
|
||||||
ap_pool_t *p = r->pool;
|
ap_pool_t *p = r->pool;
|
||||||
int one = 1;
|
int one = 1;
|
||||||
const long int zero = 0L;
|
const long int zero = 0L;
|
||||||
NET_SIZE_T clen;
|
ap_table_t *resp_hdrs;
|
||||||
struct tbl_do_args tdo;
|
|
||||||
|
|
||||||
void *sconf = r->server->module_config;
|
void *sconf = r->server->module_config;
|
||||||
proxy_server_conf *conf =
|
proxy_server_conf *conf =
|
||||||
@@ -480,7 +490,10 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url)
|
|||||||
struct sockaddr_in data_addr;
|
struct sockaddr_in data_addr;
|
||||||
int pasvmode = 0;
|
int pasvmode = 0;
|
||||||
char pasv[64];
|
char pasv[64];
|
||||||
char *pstr;
|
char *pstr, dates[AP_RFC822_DATE_LEN];
|
||||||
|
|
||||||
|
char *npaddr;
|
||||||
|
ap_uint32_t npport;
|
||||||
|
|
||||||
/* stuff for responses */
|
/* stuff for responses */
|
||||||
char resp[MAX_STRING_LEN];
|
char resp[MAX_STRING_LEN];
|
||||||
@@ -544,76 +557,42 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url)
|
|||||||
"Connect to remote machine blocked");
|
"Connect to remote machine blocked");
|
||||||
}
|
}
|
||||||
|
|
||||||
Explain2("FTP: connect to %s:%d", host, port);
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"FTP: connect to %s:%d", host, port);
|
||||||
|
|
||||||
parms = strchr(path, ';');
|
parms = strchr(path, ';');
|
||||||
if (parms != NULL)
|
if (parms != NULL)
|
||||||
*(parms++) = '\0';
|
*(parms++) = '\0';
|
||||||
|
|
||||||
memset(&server, 0, sizeof(struct sockaddr_in));
|
if ((ap_create_tcp_socket(&sock, r->pool)) != APR_SUCCESS) {
|
||||||
server.sin_family = AF_INET;
|
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||||
server.sin_port = htons(port);
|
|
||||||
err = ap_proxy_host2addr(host, &server_hp);
|
|
||||||
if (err != NULL)
|
|
||||||
return ap_proxyerror(r, HTTP_INTERNAL_SERVER_ERROR, err);
|
|
||||||
|
|
||||||
sock = ap_psocket(p, PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
||||||
if (sock == -1) {
|
|
||||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
|
|
||||||
"proxy: error creating socket");
|
"proxy: error creating socket");
|
||||||
return HTTP_INTERNAL_SERVER_ERROR;
|
return HTTP_INTERNAL_SERVER_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conf->recv_buffer_size > 0
|
if (conf->recv_buffer_size > 0 && ap_setsocketopt(sock, APR_SO_RCVBUF,conf->recv_buffer_size)) {
|
||||||
&& setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
|
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||||
(const char *) &conf->recv_buffer_size, sizeof(int))
|
|
||||||
== -1) {
|
|
||||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
|
|
||||||
"setsockopt(SO_RCVBUF): Failed to set ProxyReceiveBufferSize, using default");
|
"setsockopt(SO_RCVBUF): Failed to set ProxyReceiveBufferSize, using default");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &one,
|
if (ap_setsocketopt(sock, APR_SO_REUSEADDR, one)) {
|
||||||
sizeof(one)) == -1) {
|
|
||||||
#ifndef _OSD_POSIX /* BS2000 has this option "always on" */
|
#ifndef _OSD_POSIX /* BS2000 has this option "always on" */
|
||||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
|
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||||
"proxy: error setting reuseaddr option: setsockopt(SO_REUSEADDR)");
|
"proxy: error setting reuseaddr option: setsockopt(SO_REUSEADDR)");
|
||||||
ap_pclosesocket(p, sock);
|
ap_close_socket(sock);
|
||||||
return HTTP_INTERNAL_SERVER_ERROR;
|
return HTTP_INTERNAL_SERVER_ERROR;
|
||||||
#endif /*_OSD_POSIX*/
|
#endif /*_OSD_POSIX*/
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SINIX_D_RESOLVER_BUG
|
if (ap_proxy_doconnect(sock, host, port, r) == -1) {
|
||||||
{
|
ap_close_socket(sock);
|
||||||
struct in_addr *ip_addr = (struct in_addr *) *server_hp.h_addr_list;
|
return ap_proxyerror(r, HTTP_BAD_GATEWAY,
|
||||||
|
ap_pstrcat(r->pool, "Could not connect to remote machine: ",
|
||||||
for (; ip_addr->s_addr != 0; ++ip_addr) {
|
strerror(errno), NULL));
|
||||||
memcpy(&server.sin_addr, ip_addr, sizeof(struct in_addr));
|
|
||||||
i = ap_proxy_doconnect(sock, &server, r);
|
|
||||||
if (i == 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
j = 0;
|
|
||||||
while (server_hp.h_addr_list[j] != NULL) {
|
|
||||||
memcpy(&server.sin_addr, server_hp.h_addr_list[j],
|
|
||||||
sizeof(struct in_addr));
|
|
||||||
i = ap_proxy_doconnect(sock, &server, r);
|
|
||||||
if (i == 0)
|
|
||||||
break;
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (i == -1) {
|
|
||||||
char buf[120];
|
|
||||||
ap_pclosesocket(p, sock);
|
|
||||||
return ap_proxyerror(r, HTTP_BAD_GATEWAY, ap_pstrcat(r->pool,
|
|
||||||
"Could not connect to remote machine: ",
|
|
||||||
ap_strerror(errno, buf, sizeof(buf)), NULL));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
f = ap_bcreate(p, B_RDWR | B_SOCKET);
|
f = ap_bcreate(p, B_RDWR);
|
||||||
ap_bpushfd(f, sock);
|
ap_bpush_iol(f, unix_attach_socket(sock));
|
||||||
/* shouldn't we implement telnet control options here? */
|
/* shouldn't we implement telnet control options here? */
|
||||||
|
|
||||||
#ifdef CHARSET_EBCDIC
|
#ifdef CHARSET_EBCDIC
|
||||||
@@ -625,7 +604,8 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url)
|
|||||||
/* 220 Service ready for new user. */
|
/* 220 Service ready for new user. */
|
||||||
/* 421 Service not available, closing control connection. */
|
/* 421 Service not available, closing control connection. */
|
||||||
i = ftp_getrc_msg(f, resp, sizeof resp);
|
i = ftp_getrc_msg(f, resp, sizeof resp);
|
||||||
Explain1("FTP: returned status %d", i);
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"FTP: returned status %d", i);
|
||||||
if (i == -1) {
|
if (i == -1) {
|
||||||
return ap_proxyerror(r, HTTP_BAD_GATEWAY,
|
return ap_proxyerror(r, HTTP_BAD_GATEWAY,
|
||||||
"Error reading from remote server");
|
"Error reading from remote server");
|
||||||
@@ -650,11 +630,13 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url)
|
|||||||
return ap_proxyerror(r, HTTP_BAD_GATEWAY, resp);
|
return ap_proxyerror(r, HTTP_BAD_GATEWAY, resp);
|
||||||
}
|
}
|
||||||
|
|
||||||
Explain0("FTP: connected.");
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"FTP: connected.");
|
||||||
|
|
||||||
ap_bvputs(f, "USER ", user, CRLF, NULL);
|
ap_bvputs(f, "USER ", user, CRLF, NULL);
|
||||||
ap_bflush(f); /* capture any errors */
|
ap_bflush(f); /* capture any errors */
|
||||||
Explain1("FTP: USER %s", user);
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"FTP: USER %s", user);
|
||||||
|
|
||||||
/* possible results; 230, 331, 332, 421, 500, 501, 530 */
|
/* possible results; 230, 331, 332, 421, 500, 501, 530 */
|
||||||
/* states: 1 - error, 2 - success; 3 - send password, 4,5 fail */
|
/* states: 1 - error, 2 - success; 3 - send password, 4,5 fail */
|
||||||
@@ -667,7 +649,8 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url)
|
|||||||
/* 501 Syntax error in parameters or arguments. */
|
/* 501 Syntax error in parameters or arguments. */
|
||||||
/* 530 Not logged in. */
|
/* 530 Not logged in. */
|
||||||
i = ftp_getrc(f);
|
i = ftp_getrc(f);
|
||||||
Explain1("FTP: returned status %d", i);
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"FTP: returned status %d", i);
|
||||||
if (i == -1) {
|
if (i == -1) {
|
||||||
return ap_proxyerror(r, HTTP_BAD_GATEWAY,
|
return ap_proxyerror(r, HTTP_BAD_GATEWAY,
|
||||||
"Error reading from remote server");
|
"Error reading from remote server");
|
||||||
@@ -685,7 +668,8 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url)
|
|||||||
}
|
}
|
||||||
ap_bvputs(f, "PASS ", password, CRLF, NULL);
|
ap_bvputs(f, "PASS ", password, CRLF, NULL);
|
||||||
ap_bflush(f);
|
ap_bflush(f);
|
||||||
Explain1("FTP: PASS %s", password);
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"FTP: PASS %s", password);
|
||||||
/* possible results 202, 230, 332, 421, 500, 501, 503, 530 */
|
/* possible results 202, 230, 332, 421, 500, 501, 503, 530 */
|
||||||
/* 230 User logged in, proceed. */
|
/* 230 User logged in, proceed. */
|
||||||
/* 332 Need account for login. */
|
/* 332 Need account for login. */
|
||||||
@@ -695,7 +679,8 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url)
|
|||||||
/* 503 Bad sequence of commands. */
|
/* 503 Bad sequence of commands. */
|
||||||
/* 530 Not logged in. */
|
/* 530 Not logged in. */
|
||||||
i = ftp_getrc(f);
|
i = ftp_getrc(f);
|
||||||
Explain1("FTP: returned status %d", i);
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"FTP: returned status %d", i);
|
||||||
if (i == -1) {
|
if (i == -1) {
|
||||||
return ap_proxyerror(r, HTTP_BAD_GATEWAY, "Error reading from remote server");
|
return ap_proxyerror(r, HTTP_BAD_GATEWAY, "Error reading from remote server");
|
||||||
}
|
}
|
||||||
@@ -724,7 +709,8 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url)
|
|||||||
len = decodeenc(path);
|
len = decodeenc(path);
|
||||||
ap_bvputs(f, "CWD ", path, CRLF, NULL);
|
ap_bvputs(f, "CWD ", path, CRLF, NULL);
|
||||||
ap_bflush(f);
|
ap_bflush(f);
|
||||||
Explain1("FTP: CWD %s", path);
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"FTP: CWD %s", path);
|
||||||
*strp = '/';
|
*strp = '/';
|
||||||
/* responses: 250, 421, 500, 501, 502, 530, 550 */
|
/* responses: 250, 421, 500, 501, 502, 530, 550 */
|
||||||
/* 250 Requested file action okay, completed. */
|
/* 250 Requested file action okay, completed. */
|
||||||
@@ -735,7 +721,8 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url)
|
|||||||
/* 530 Not logged in. */
|
/* 530 Not logged in. */
|
||||||
/* 550 Requested action not taken. */
|
/* 550 Requested action not taken. */
|
||||||
i = ftp_getrc(f);
|
i = ftp_getrc(f);
|
||||||
Explain1("FTP: returned status %d", i);
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"FTP: returned status %d", i);
|
||||||
if (i == -1) {
|
if (i == -1) {
|
||||||
return ap_proxyerror(r, HTTP_BAD_GATEWAY,
|
return ap_proxyerror(r, HTTP_BAD_GATEWAY,
|
||||||
"Error reading from remote server");
|
"Error reading from remote server");
|
||||||
@@ -767,7 +754,8 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url)
|
|||||||
connection */
|
connection */
|
||||||
ap_bputs("TYPE I" CRLF, f);
|
ap_bputs("TYPE I" CRLF, f);
|
||||||
ap_bflush(f);
|
ap_bflush(f);
|
||||||
Explain0("FTP: TYPE I");
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"FTP: TYPE I");
|
||||||
/* responses: 200, 421, 500, 501, 504, 530 */
|
/* responses: 200, 421, 500, 501, 504, 530 */
|
||||||
/* 200 Command okay. */
|
/* 200 Command okay. */
|
||||||
/* 421 Service not available, closing control connection. */
|
/* 421 Service not available, closing control connection. */
|
||||||
@@ -776,7 +764,8 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url)
|
|||||||
/* 504 Command not implemented for that parameter. */
|
/* 504 Command not implemented for that parameter. */
|
||||||
/* 530 Not logged in. */
|
/* 530 Not logged in. */
|
||||||
i = ftp_getrc(f);
|
i = ftp_getrc(f);
|
||||||
Explain1("FTP: returned status %d", i);
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"FTP: returned status %d", i);
|
||||||
if (i == -1) {
|
if (i == -1) {
|
||||||
return ap_proxyerror(r, HTTP_BAD_GATEWAY,
|
return ap_proxyerror(r, HTTP_BAD_GATEWAY,
|
||||||
"Error reading from remote server");
|
"Error reading from remote server");
|
||||||
@@ -790,25 +779,22 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* try to set up PASV data connection first */
|
/* try to set up PASV data connection first */
|
||||||
dsock = ap_psocket(p, PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
if ((ap_create_tcp_socket(&dsock, r->pool)) != APR_SUCCESS) {
|
||||||
if (dsock == -1) {
|
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
|
|
||||||
"proxy: error creating PASV socket");
|
"proxy: error creating PASV socket");
|
||||||
ap_bclose(f);
|
ap_bclose(f);
|
||||||
return HTTP_INTERNAL_SERVER_ERROR;
|
return HTTP_INTERNAL_SERVER_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conf->recv_buffer_size) {
|
if (conf->recv_buffer_size > 0 && ap_setsocketopt(dsock, APR_SO_RCVBUF,conf->recv_buffer_size)) {
|
||||||
if (setsockopt(dsock, SOL_SOCKET, SO_RCVBUF,
|
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||||
(const char *) &conf->recv_buffer_size, sizeof(int)) == -1) {
|
|
||||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
|
|
||||||
"setsockopt(SO_RCVBUF): Failed to set ProxyReceiveBufferSize, using default");
|
"setsockopt(SO_RCVBUF): Failed to set ProxyReceiveBufferSize, using default");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ap_bputs("PASV" CRLF, f);
|
ap_bputs("PASV" CRLF, f);
|
||||||
ap_bflush(f);
|
ap_bflush(f);
|
||||||
Explain0("FTP: PASV command issued");
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"FTP: PASV command issued");
|
||||||
/* possible results: 227, 421, 500, 501, 502, 530 */
|
/* possible results: 227, 421, 500, 501, 502, 530 */
|
||||||
/* 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2). */
|
/* 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2). */
|
||||||
/* 421 Service not available, closing control connection. */
|
/* 421 Service not available, closing control connection. */
|
||||||
@@ -818,13 +804,45 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url)
|
|||||||
/* 530 Not logged in. */
|
/* 530 Not logged in. */
|
||||||
i = ap_bgets(pasv, sizeof(pasv), f);
|
i = ap_bgets(pasv, sizeof(pasv), f);
|
||||||
if (i == -1) {
|
if (i == -1) {
|
||||||
ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, r,
|
ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, r,
|
||||||
"PASV: control connection is toast");
|
"PASV: control connection is toast");
|
||||||
ap_pclosesocket(p, dsock);
|
ap_close_socket(dsock);
|
||||||
ap_bclose(f);
|
ap_bclose(f);
|
||||||
return HTTP_INTERNAL_SERVER_ERROR;
|
return HTTP_INTERNAL_SERVER_ERROR;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
<<<<<<< proxy_ftp.c
|
||||||
|
pasv[i - 1] = '\0';
|
||||||
|
pstr = strtok(pasv, " "); /* separate result code */
|
||||||
|
if (pstr != NULL) {
|
||||||
|
presult = atoi(pstr);
|
||||||
|
if (*(pstr + strlen(pstr) + 1) == '=')
|
||||||
|
pstr += strlen(pstr) + 2;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pstr = strtok(NULL, "("); /* separate address & port params */
|
||||||
|
if (pstr != NULL)
|
||||||
|
pstr = strtok(NULL, ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
presult = atoi(pasv);
|
||||||
|
|
||||||
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"FTP: returned status %d", presult);
|
||||||
|
|
||||||
|
if (presult == 227 && pstr != NULL && (sscanf(pstr,
|
||||||
|
"%d,%d,%d,%d,%d,%d", &h3, &h2, &h1, &h0, &p1, &p0) == 6)) {
|
||||||
|
/* pardon the parens, but it makes gcc happy */
|
||||||
|
destaddr.s_addr = htonl((((((h3 << 8) + h2) << 8) + h1) << 8) + h0);
|
||||||
|
pport = (p1 << 8) + p0;
|
||||||
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"FTP: contacting host %d.%d.%d.%d:%d",
|
||||||
|
h3, h2, h1, h0, pport);
|
||||||
|
|
||||||
|
if (ap_proxy_doconnect(dsock, inet_ntoa(destaddr), pport, r) == -1) {
|
||||||
|
return ap_proxyerror(r, HTTP_BAD_GATEWAY,
|
||||||
|
=======
|
||||||
pasv[i - 1] = '\0';
|
pasv[i - 1] = '\0';
|
||||||
pstr = strtok(pasv, " "); /* separate result code */
|
pstr = strtok(pasv, " "); /* separate result code */
|
||||||
if (pstr != NULL) {
|
if (pstr != NULL) {
|
||||||
@@ -858,8 +876,35 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url)
|
|||||||
if (i == -1) {
|
if (i == -1) {
|
||||||
char buf[120];
|
char buf[120];
|
||||||
return ap_proxyerror(r, HTTP_BAD_GATEWAY,
|
return ap_proxyerror(r, HTTP_BAD_GATEWAY,
|
||||||
|
>>>>>>> 1.8
|
||||||
ap_pstrcat(r->pool,
|
ap_pstrcat(r->pool,
|
||||||
"Could not connect to remote machine: ",
|
"Could not connect to remote machine: ",
|
||||||
|
<<<<<<< proxy_ftp.c
|
||||||
|
strerror(errno), NULL));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pasvmode = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ap_close_socket(dsock); /* and try the regular way */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pasvmode) { /* set up data connection */
|
||||||
|
|
||||||
|
if ((ap_create_tcp_socket(&dsock, r->pool)) != APR_SUCCESS) {
|
||||||
|
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||||
|
"proxy: error creating socket");
|
||||||
|
ap_bclose(f);
|
||||||
|
return HTTP_INTERNAL_SERVER_ERROR;
|
||||||
|
}
|
||||||
|
ap_get_local_port(&npport, sock);
|
||||||
|
ap_get_local_ipaddr(&npaddr, sock);
|
||||||
|
ap_set_local_port(dsock, npport);
|
||||||
|
ap_set_local_ipaddr(dsock, npaddr);
|
||||||
|
|
||||||
|
if (ap_setsocketopt(dsock, APR_SO_REUSEADDR, one) != APR_SUCCESS) {
|
||||||
|
=======
|
||||||
ap_strerror(errno, buf,
|
ap_strerror(errno, buf,
|
||||||
sizeof(buf)), NULL));
|
sizeof(buf)), NULL));
|
||||||
}
|
}
|
||||||
@@ -890,27 +935,27 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url)
|
|||||||
|
|
||||||
if (setsockopt(dsock, SOL_SOCKET, SO_REUSEADDR, (void *) &one,
|
if (setsockopt(dsock, SOL_SOCKET, SO_REUSEADDR, (void *) &one,
|
||||||
sizeof(one)) == -1) {
|
sizeof(one)) == -1) {
|
||||||
|
>>>>>>> 1.8
|
||||||
#ifndef _OSD_POSIX /* BS2000 has this option "always on" */
|
#ifndef _OSD_POSIX /* BS2000 has this option "always on" */
|
||||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
|
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||||
"proxy: error setting reuseaddr option");
|
"proxy: error setting reuseaddr option");
|
||||||
ap_pclosesocket(p, dsock);
|
ap_close_socket(dsock);
|
||||||
ap_bclose(f);
|
ap_bclose(f);
|
||||||
return HTTP_INTERNAL_SERVER_ERROR;
|
return HTTP_INTERNAL_SERVER_ERROR;
|
||||||
#endif /*_OSD_POSIX*/
|
#endif /*_OSD_POSIX*/
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bind(dsock, (struct sockaddr *) &server,
|
if (ap_bind(dsock) != APR_SUCCESS) {
|
||||||
sizeof(struct sockaddr_in)) == -1) {
|
|
||||||
char buff[22];
|
char buff[22];
|
||||||
|
|
||||||
ap_snprintf(buff, sizeof(buff), "%s:%d", inet_ntoa(server.sin_addr), server.sin_port);
|
ap_snprintf(buff, sizeof(buff), "%s:%d", npaddr, npport);
|
||||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
|
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||||
"proxy: error binding to ftp data socket %s", buff);
|
"proxy: error binding to ftp data socket %s", buff);
|
||||||
ap_bclose(f);
|
ap_bclose(f);
|
||||||
ap_pclosesocket(p, dsock);
|
ap_close_socket(dsock);
|
||||||
return HTTP_INTERNAL_SERVER_ERROR;
|
return HTTP_INTERNAL_SERVER_ERROR;
|
||||||
}
|
}
|
||||||
listen(dsock, 2); /* only need a short queue */
|
ap_listen(dsock, 2); /* only need a short queue */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set request; "path" holds last path component */
|
/* set request; "path" holds last path component */
|
||||||
@@ -924,16 +969,20 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url)
|
|||||||
else {
|
else {
|
||||||
ap_bvputs(f, "SIZE ", path, CRLF, NULL);
|
ap_bvputs(f, "SIZE ", path, CRLF, NULL);
|
||||||
ap_bflush(f);
|
ap_bflush(f);
|
||||||
Explain1("FTP: SIZE %s", path);
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"FTP: SIZE %s", path);
|
||||||
i = ftp_getrc_msg(f, resp, sizeof resp);
|
i = ftp_getrc_msg(f, resp, sizeof resp);
|
||||||
Explain2("FTP: returned status %d with response %s", i, resp);
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"FTP: returned status %d with response %s", i, resp);
|
||||||
if (i != 500) { /* Size command not recognized */
|
if (i != 500) { /* Size command not recognized */
|
||||||
if (i == 550) { /* Not a regular file */
|
if (i == 550) { /* Not a regular file */
|
||||||
Explain0("FTP: SIZE shows this is a directory");
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"FTP: SIZE shows this is a directory");
|
||||||
parms = "d";
|
parms = "d";
|
||||||
ap_bvputs(f, "CWD ", path, CRLF, NULL);
|
ap_bvputs(f, "CWD ", path, CRLF, NULL);
|
||||||
ap_bflush(f);
|
ap_bflush(f);
|
||||||
Explain1("FTP: CWD %s", path);
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"FTP: CWD %s", path);
|
||||||
i = ftp_getrc(f);
|
i = ftp_getrc(f);
|
||||||
/* possible results: 250, 421, 500, 501, 502, 530, 550 */
|
/* possible results: 250, 421, 500, 501, 502, 530, 550 */
|
||||||
/* 250 Requested file action okay, completed. */
|
/* 250 Requested file action okay, completed. */
|
||||||
@@ -943,7 +992,8 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url)
|
|||||||
/* 502 Command not implemented. */
|
/* 502 Command not implemented. */
|
||||||
/* 530 Not logged in. */
|
/* 530 Not logged in. */
|
||||||
/* 550 Requested action not taken. */
|
/* 550 Requested action not taken. */
|
||||||
Explain1("FTP: returned status %d", i);
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"FTP: returned status %d", i);
|
||||||
if (i == -1) {
|
if (i == -1) {
|
||||||
return ap_proxyerror(r, HTTP_BAD_GATEWAY,
|
return ap_proxyerror(r, HTTP_BAD_GATEWAY,
|
||||||
"Error reading from remote server");
|
"Error reading from remote server");
|
||||||
@@ -970,7 +1020,8 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url)
|
|||||||
#ifdef AUTODETECT_PWD
|
#ifdef AUTODETECT_PWD
|
||||||
ap_bvputs(f, "PWD", CRLF, NULL);
|
ap_bvputs(f, "PWD", CRLF, NULL);
|
||||||
ap_bflush(f);
|
ap_bflush(f);
|
||||||
Explain0("FTP: PWD");
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"FTP: PWD");
|
||||||
/* responses: 257, 500, 501, 502, 421, 550 */
|
/* responses: 257, 500, 501, 502, 421, 550 */
|
||||||
/* 257 "<directory-name>" <commentary> */
|
/* 257 "<directory-name>" <commentary> */
|
||||||
/* 421 Service not available, closing control connection. */
|
/* 421 Service not available, closing control connection. */
|
||||||
@@ -979,7 +1030,8 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url)
|
|||||||
/* 502 Command not implemented. */
|
/* 502 Command not implemented. */
|
||||||
/* 550 Requested action not taken. */
|
/* 550 Requested action not taken. */
|
||||||
i = ftp_getrc_msg(f, resp, sizeof resp);
|
i = ftp_getrc_msg(f, resp, sizeof resp);
|
||||||
Explain1("FTP: PWD returned status %d", i);
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"FTP: PWD returned status %d", i);
|
||||||
if (i == -1 || i == 421) {
|
if (i == -1 || i == 421) {
|
||||||
return ap_proxyerror(r, HTTP_BAD_GATEWAY,
|
return ap_proxyerror(r, HTTP_BAD_GATEWAY,
|
||||||
"Error reading from remote server");
|
"Error reading from remote server");
|
||||||
@@ -998,11 +1050,13 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url)
|
|||||||
ap_bvputs(f, "LIST ", path, CRLF, NULL);
|
ap_bvputs(f, "LIST ", path, CRLF, NULL);
|
||||||
else
|
else
|
||||||
ap_bputs("LIST -lag" CRLF, f);
|
ap_bputs("LIST -lag" CRLF, f);
|
||||||
Explain1("FTP: LIST %s", (len == 0 ? "" : path));
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"FTP: LIST %s", (len == 0 ? "" : path));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ap_bvputs(f, "RETR ", path, CRLF, NULL);
|
ap_bvputs(f, "RETR ", path, CRLF, NULL);
|
||||||
Explain1("FTP: RETR %s", path);
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"FTP: RETR %s", path);
|
||||||
}
|
}
|
||||||
ap_bflush(f);
|
ap_bflush(f);
|
||||||
/* RETR: 110, 125, 150, 226, 250, 421, 425, 426, 450, 451, 500, 501, 530, 550
|
/* RETR: 110, 125, 150, 226, 250, 421, 425, 426, 450, 451, 500, 501, 530, 550
|
||||||
@@ -1022,17 +1076,20 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url)
|
|||||||
/* 530 Not logged in. */
|
/* 530 Not logged in. */
|
||||||
/* 550 Requested action not taken. */
|
/* 550 Requested action not taken. */
|
||||||
rc = ftp_getrc(f);
|
rc = ftp_getrc(f);
|
||||||
Explain1("FTP: returned status %d", rc);
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"FTP: returned status %d", rc);
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
return ap_proxyerror(r, HTTP_BAD_GATEWAY,
|
return ap_proxyerror(r, HTTP_BAD_GATEWAY,
|
||||||
"Error reading from remote server");
|
"Error reading from remote server");
|
||||||
}
|
}
|
||||||
if (rc == 550) {
|
if (rc == 550) {
|
||||||
Explain0("FTP: RETR failed, trying LIST instead");
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"FTP: RETR failed, trying LIST instead");
|
||||||
parms = "d";
|
parms = "d";
|
||||||
ap_bvputs(f, "CWD ", path, CRLF, NULL);
|
ap_bvputs(f, "CWD ", path, CRLF, NULL);
|
||||||
ap_bflush(f);
|
ap_bflush(f);
|
||||||
Explain1("FTP: CWD %s", path);
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"FTP: CWD %s", path);
|
||||||
/* possible results: 250, 421, 500, 501, 502, 530, 550 */
|
/* possible results: 250, 421, 500, 501, 502, 530, 550 */
|
||||||
/* 250 Requested file action okay, completed. */
|
/* 250 Requested file action okay, completed. */
|
||||||
/* 421 Service not available, closing control connection. */
|
/* 421 Service not available, closing control connection. */
|
||||||
@@ -1042,7 +1099,8 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url)
|
|||||||
/* 530 Not logged in. */
|
/* 530 Not logged in. */
|
||||||
/* 550 Requested action not taken. */
|
/* 550 Requested action not taken. */
|
||||||
rc = ftp_getrc(f);
|
rc = ftp_getrc(f);
|
||||||
Explain1("FTP: returned status %d", rc);
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"FTP: returned status %d", rc);
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
return ap_proxyerror(r, HTTP_BAD_GATEWAY,
|
return ap_proxyerror(r, HTTP_BAD_GATEWAY,
|
||||||
"Error reading from remote server");
|
"Error reading from remote server");
|
||||||
@@ -1057,7 +1115,8 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url)
|
|||||||
#ifdef AUTODETECT_PWD
|
#ifdef AUTODETECT_PWD
|
||||||
ap_bvputs(f, "PWD", CRLF, NULL);
|
ap_bvputs(f, "PWD", CRLF, NULL);
|
||||||
ap_bflush(f);
|
ap_bflush(f);
|
||||||
Explain0("FTP: PWD");
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"FTP: PWD");
|
||||||
/* responses: 257, 500, 501, 502, 421, 550 */
|
/* responses: 257, 500, 501, 502, 421, 550 */
|
||||||
/* 257 "<directory-name>" <commentary> */
|
/* 257 "<directory-name>" <commentary> */
|
||||||
/* 421 Service not available, closing control connection. */
|
/* 421 Service not available, closing control connection. */
|
||||||
@@ -1066,7 +1125,8 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url)
|
|||||||
/* 502 Command not implemented. */
|
/* 502 Command not implemented. */
|
||||||
/* 550 Requested action not taken. */
|
/* 550 Requested action not taken. */
|
||||||
i = ftp_getrc_msg(f, resp, sizeof resp);
|
i = ftp_getrc_msg(f, resp, sizeof resp);
|
||||||
Explain1("FTP: PWD returned status %d", i);
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"FTP: PWD returned status %d", i);
|
||||||
if (i == -1 || i == 421) {
|
if (i == -1 || i == 421) {
|
||||||
return ap_proxyerror(r, HTTP_BAD_GATEWAY,
|
return ap_proxyerror(r, HTTP_BAD_GATEWAY,
|
||||||
"Error reading from remote server");
|
"Error reading from remote server");
|
||||||
@@ -1082,9 +1142,11 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url)
|
|||||||
|
|
||||||
ap_bputs("LIST -lag" CRLF, f);
|
ap_bputs("LIST -lag" CRLF, f);
|
||||||
ap_bflush(f);
|
ap_bflush(f);
|
||||||
Explain0("FTP: LIST -lag");
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"FTP: LIST -lag");
|
||||||
rc = ftp_getrc(f);
|
rc = ftp_getrc(f);
|
||||||
Explain1("FTP: returned status %d", rc);
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"FTP: returned status %d", rc);
|
||||||
if (rc == -1)
|
if (rc == -1)
|
||||||
return ap_proxyerror(r, HTTP_BAD_GATEWAY,
|
return ap_proxyerror(r, HTTP_BAD_GATEWAY,
|
||||||
"Error reading from remote server");
|
"Error reading from remote server");
|
||||||
@@ -1094,11 +1156,10 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url)
|
|||||||
|
|
||||||
r->status = HTTP_OK;
|
r->status = HTTP_OK;
|
||||||
r->status_line = "200 OK";
|
r->status_line = "200 OK";
|
||||||
|
|
||||||
resp_hdrs = ap_make_table(p, 2);
|
resp_hdrs = ap_make_table(p, 2);
|
||||||
c->hdrs = resp_hdrs;
|
|
||||||
|
|
||||||
ap_table_setn(resp_hdrs, "Date", ap_gm_timestr_822(r->pool, r->request_time));
|
ap_rfc822_date(dates, r->request_time);
|
||||||
|
ap_table_setn(resp_hdrs, "Date", dates);
|
||||||
ap_table_setn(resp_hdrs, "Server", ap_get_server_version());
|
ap_table_setn(resp_hdrs, "Server", ap_get_server_version());
|
||||||
|
|
||||||
if (parms[0] == 'd')
|
if (parms[0] == 'd')
|
||||||
@@ -1106,21 +1167,25 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url)
|
|||||||
else {
|
else {
|
||||||
if (r->content_type != NULL) {
|
if (r->content_type != NULL) {
|
||||||
ap_table_setn(resp_hdrs, "Content-Type", r->content_type);
|
ap_table_setn(resp_hdrs, "Content-Type", r->content_type);
|
||||||
Explain1("FTP: Content-Type set to %s", r->content_type);
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"FTP: Content-Type set to %s", r->content_type);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ap_table_setn(resp_hdrs, "Content-Type", ap_default_type(r));
|
ap_table_setn(resp_hdrs, "Content-Type", ap_default_type(r));
|
||||||
}
|
}
|
||||||
if (parms[0] != 'a' && size != NULL) {
|
if (parms[0] != 'a' && size != NULL) {
|
||||||
/* We "trust" the ftp server to really serve (size) bytes... */
|
/* We "trust" the ftp server to really serve (size) bytes... */
|
||||||
ap_table_set(resp_hdrs, "Content-Length", size);
|
ap_table_setn(resp_hdrs, "Content-Length", size);
|
||||||
Explain1("FTP: Content-Length set to %s", size);
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"FTP: Content-Length set to %s", size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (r->content_encoding != NULL && r->content_encoding[0] != '\0') {
|
if (r->content_encoding != NULL && r->content_encoding[0] != '\0') {
|
||||||
Explain1("FTP: Content-Encoding set to %s", r->content_encoding);
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"FTP: Content-Encoding set to %s", r->content_encoding);
|
||||||
ap_table_setn(resp_hdrs, "Content-Encoding", r->content_encoding);
|
ap_table_setn(resp_hdrs, "Content-Encoding", r->content_encoding);
|
||||||
}
|
}
|
||||||
|
ap_cache_el_header_merge(c, resp_hdrs);
|
||||||
|
|
||||||
/* check if NoCache directive on this host */
|
/* check if NoCache directive on this host */
|
||||||
for (i = 0; i < conf->nocaches->nelts; i++) {
|
for (i = 0; i < conf->nocaches->nelts; i++) {
|
||||||
@@ -1129,59 +1194,57 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url)
|
|||||||
nocache = 1;
|
nocache = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
i = ap_proxy_cache_update(c, resp_hdrs, 0, nocache);
|
if(nocache || !ap_proxy_cache_should_cache(r, resp_hdrs, 0))
|
||||||
|
ap_proxy_cache_error(&c);
|
||||||
if (i != DECLINED) {
|
else
|
||||||
ap_pclosesocket(p, dsock);
|
ap_cache_el_data(c, &cachefp);
|
||||||
ap_bclose(f);
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pasvmode) { /* wait for connection */
|
if (!pasvmode) { /* wait for connection */
|
||||||
clen = sizeof(struct sockaddr_in);
|
for(;;)
|
||||||
do
|
{
|
||||||
csd = accept(dsock, (struct sockaddr *) &server, &clen);
|
switch(ap_accept(&inc, dsock, r->pool))
|
||||||
while (csd == -1 && errno == EINTR);
|
{
|
||||||
if (csd == -1) {
|
case APR_EINTR:
|
||||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
|
continue;
|
||||||
|
case APR_SUCCESS:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||||
"proxy: failed to accept data connection");
|
"proxy: failed to accept data connection");
|
||||||
ap_pclosesocket(p, dsock);
|
ap_close_socket(dsock);
|
||||||
ap_bclose(f);
|
ap_bclose(f);
|
||||||
if (c != NULL)
|
if (c != NULL) ap_proxy_cache_error(&c);
|
||||||
c = ap_proxy_cache_error(c);
|
|
||||||
return HTTP_BAD_GATEWAY;
|
return HTTP_BAD_GATEWAY;
|
||||||
}
|
}
|
||||||
ap_note_cleanups_for_socket(p, csd);
|
}
|
||||||
data = ap_bcreate(p, B_RDWR | B_SOCKET);
|
data = ap_bcreate(p, B_RDWR);
|
||||||
ap_bpushfd(data, csd);
|
ap_bpush_iol(f, unix_attach_socket(csd));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
data = ap_bcreate(p, B_RDWR | B_SOCKET);
|
data = ap_bcreate(p, B_RDWR);
|
||||||
ap_bpushfd(data, dsock);
|
ap_bpush_iol(data, unix_attach_socket(dsock));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* send response */
|
/* send response */
|
||||||
/* 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 (c != NULL && c->fp != NULL
|
if (cachefp && ap_bvputs(cachefp, "HTTP/1.0 ", r->status_line, CRLF, NULL) == -1) {
|
||||||
&& ap_bvputs(c->fp, "HTTP/1.0 ", r->status_line, CRLF, NULL) == -1) {
|
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
|
"proxy: error writing CRLF to cache");
|
||||||
"proxy: error writing CRLF to %s", c->tempfile);
|
ap_proxy_cache_error(&c);
|
||||||
c = ap_proxy_cache_error(c);
|
cachefp = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* send headers */
|
/* send headers */
|
||||||
tdo.req = r;
|
ap_cache_el_header_walk(c, ap_proxy_send_hdr_line, r, NULL);
|
||||||
tdo.cache = c;
|
|
||||||
ap_table_do(ap_proxy_send_hdr_line, &tdo, resp_hdrs, NULL);
|
|
||||||
|
|
||||||
if (!r->assbackwards)
|
if (!r->assbackwards)
|
||||||
ap_rputs(CRLF, r);
|
ap_rputs(CRLF, r);
|
||||||
if (c != NULL && c->fp != NULL && ap_bputs(CRLF, c->fp) == -1) {
|
if (cachefp && ap_bputs(CRLF, cachefp) == -1) {
|
||||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
|
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||||
"proxy: error writing CRLF to %s", c->tempfile);
|
"proxy: error writing CRLF to cache");
|
||||||
c = ap_proxy_cache_error(c);
|
ap_proxy_cache_error(&c);
|
||||||
|
cachefp = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ap_bsetopt(r->connection->client, BO_BYTECT, &zero);
|
ap_bsetopt(r->connection->client, BO_BYTECT, &zero);
|
||||||
@@ -1189,10 +1252,8 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url)
|
|||||||
/* send body */
|
/* send body */
|
||||||
if (!r->header_only) {
|
if (!r->header_only) {
|
||||||
if (parms[0] != 'd') {
|
if (parms[0] != 'd') {
|
||||||
/* we need to set this for ap_proxy_send_fb()... */
|
/* we don't need no steekin' cache completion*/
|
||||||
if (c != NULL)
|
ap_proxy_send_fb(NULL, data, r, c);
|
||||||
c->cache_completion = 0;
|
|
||||||
ap_proxy_send_fb(data, r, c);
|
|
||||||
} else
|
} else
|
||||||
send_dir(data, r, c, cwd);
|
send_dir(data, r, c, cwd);
|
||||||
|
|
||||||
@@ -1202,7 +1263,7 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url)
|
|||||||
/* XXX: we checked for 125||150||226||250 above. This is redundant. */
|
/* XXX: we checked for 125||150||226||250 above. This is redundant. */
|
||||||
if (rc != 226 && rc != 250)
|
if (rc != 226 && rc != 250)
|
||||||
/* XXX: we no longer log an "error writing to c->tempfile" - should we? */
|
/* XXX: we no longer log an "error writing to c->tempfile" - should we? */
|
||||||
c = ap_proxy_cache_error(c);
|
ap_proxy_cache_error(&c);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* abort the transfer */
|
/* abort the transfer */
|
||||||
@@ -1210,7 +1271,8 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url)
|
|||||||
ap_bflush(f);
|
ap_bflush(f);
|
||||||
if (!pasvmode)
|
if (!pasvmode)
|
||||||
ap_bclose(data);
|
ap_bclose(data);
|
||||||
Explain0("FTP: ABOR");
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"FTP: ABOR");
|
||||||
/* responses: 225, 226, 421, 500, 501, 502 */
|
/* responses: 225, 226, 421, 500, 501, 502 */
|
||||||
/* 225 Data connection open; no transfer in progress. */
|
/* 225 Data connection open; no transfer in progress. */
|
||||||
/* 226 Closing data connection. */
|
/* 226 Closing data connection. */
|
||||||
@@ -1219,28 +1281,27 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url)
|
|||||||
/* 501 Syntax error in parameters or arguments. */
|
/* 501 Syntax error in parameters or arguments. */
|
||||||
/* 502 Command not implemented. */
|
/* 502 Command not implemented. */
|
||||||
i = ftp_getrc(f);
|
i = ftp_getrc(f);
|
||||||
Explain1("FTP: returned status %d", i);
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"FTP: returned status %d", i);
|
||||||
}
|
}
|
||||||
|
|
||||||
ap_proxy_cache_tidy(c);
|
|
||||||
|
|
||||||
/* finish */
|
/* finish */
|
||||||
ap_bputs("QUIT" CRLF, f);
|
ap_bputs("QUIT" CRLF, f);
|
||||||
ap_bflush(f);
|
ap_bflush(f);
|
||||||
Explain0("FTP: QUIT");
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"FTP: QUIT");
|
||||||
/* responses: 221, 500 */
|
/* responses: 221, 500 */
|
||||||
/* 221 Service closing control connection. */
|
/* 221 Service closing control connection. */
|
||||||
/* 500 Syntax error, command unrecognized. */
|
/* 500 Syntax error, command unrecognized. */
|
||||||
i = ftp_getrc(f);
|
i = ftp_getrc(f);
|
||||||
Explain1("FTP: QUIT: status %d", i);
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"FTP: QUIT: status %d", i);
|
||||||
if (pasvmode)
|
if (pasvmode)
|
||||||
ap_bclose(data);
|
ap_bclose(data);
|
||||||
ap_bclose(f);
|
ap_bclose(f);
|
||||||
|
|
||||||
ap_rflush(r); /* flush before garbage collection */
|
ap_rflush(r); /* flush before garbage collection */
|
||||||
|
|
||||||
ap_proxy_garbage_coll(r);
|
if(c) ap_proxy_cache_update(c);
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
@@ -63,6 +63,7 @@
|
|||||||
#include "http_main.h"
|
#include "http_main.h"
|
||||||
#include "http_core.h"
|
#include "http_core.h"
|
||||||
#include "util_date.h"
|
#include "util_date.h"
|
||||||
|
#include "iol_socket.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Canonicalise http-like URLs.
|
* Canonicalise http-like URLs.
|
||||||
@@ -166,29 +167,30 @@ static void clear_connection(ap_pool_t *p, ap_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, cache_req *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;
|
||||||
const char *err, *desthost;
|
const char *err, *desthost;
|
||||||
int i, j, sock, len, backasswards;
|
ap_socket_t *sock;
|
||||||
|
int i, j, len, backasswards, content_length=-1;
|
||||||
ap_array_header_t *reqhdrs_arr;
|
ap_array_header_t *reqhdrs_arr;
|
||||||
ap_table_t *resp_hdrs;
|
ap_table_t *resp_hdrs;
|
||||||
table_entry *reqhdrs;
|
ap_table_entry_t *reqhdrs;
|
||||||
struct sockaddr_in server;
|
struct sockaddr_in server;
|
||||||
struct in_addr destaddr;
|
struct in_addr destaddr;
|
||||||
struct hostent server_hp;
|
struct hostent server_hp;
|
||||||
BUFF *f;
|
BUFF *f, *cachefp=NULL;
|
||||||
char buffer[HUGE_STRING_LEN];
|
char buffer[HUGE_STRING_LEN];
|
||||||
char portstr[32];
|
char portstr[32];
|
||||||
ap_pool_t *p = r->pool;
|
ap_pool_t *p = r->pool;
|
||||||
const long int zero = 0L;
|
const long int zero = 0L;
|
||||||
int destport = 0;
|
int destport = 0;
|
||||||
|
ap_ssize_t cntr;
|
||||||
char *destportstr = NULL;
|
char *destportstr = NULL;
|
||||||
const char *urlptr = NULL;
|
const char *urlptr = NULL;
|
||||||
const char *datestr;
|
char *datestr, *clen;
|
||||||
struct tbl_do_args tdo;
|
|
||||||
|
|
||||||
void *sconf = r->server->module_config;
|
void *sconf = r->server->module_config;
|
||||||
proxy_server_conf *conf =
|
proxy_server_conf *conf =
|
||||||
@@ -238,71 +240,37 @@ int ap_proxy_http_handler(request_rec *r, cache_req *c, char *url,
|
|||||||
"Connect to remote machine blocked");
|
"Connect to remote machine blocked");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (proxyhost != NULL) {
|
if ((ap_create_tcp_socket(&sock, r->pool)) != APR_SUCCESS) {
|
||||||
server.sin_port = htons(proxyport);
|
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||||
err = ap_proxy_host2addr(proxyhost, &server_hp);
|
|
||||||
if (err != NULL)
|
|
||||||
return DECLINED; /* try another */
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
server.sin_port = htons(destport);
|
|
||||||
err = ap_proxy_host2addr(desthost, &server_hp);
|
|
||||||
if (err != NULL)
|
|
||||||
return ap_proxyerror(r, HTTP_INTERNAL_SERVER_ERROR, err);
|
|
||||||
}
|
|
||||||
|
|
||||||
sock = ap_psocket(p, PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
||||||
if (sock == -1) {
|
|
||||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
|
|
||||||
"proxy: error creating socket");
|
"proxy: error creating socket");
|
||||||
return HTTP_INTERNAL_SERVER_ERROR;
|
return HTTP_INTERNAL_SERVER_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conf->recv_buffer_size) {
|
if (conf->recv_buffer_size > 0 && ap_setsocketopt(sock, APR_SO_RCVBUF,conf->recv_buffer_size)) {
|
||||||
if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
|
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||||
(const char *) &conf->recv_buffer_size, sizeof(int))
|
|
||||||
== -1) {
|
|
||||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
|
|
||||||
"setsockopt(SO_RCVBUF): Failed to set ProxyReceiveBufferSize, using default");
|
"setsockopt(SO_RCVBUF): Failed to set ProxyReceiveBufferSize, using default");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (proxyhost != NULL) {
|
||||||
|
i = ap_proxy_doconnect(sock, (char *)proxyhost, proxyport, r);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
i = ap_proxy_doconnect(sock, (char *)desthost, destport, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SINIX_D_RESOLVER_BUG
|
|
||||||
{
|
|
||||||
struct in_addr *ip_addr = (struct in_addr *) *server_hp.h_addr_list;
|
|
||||||
|
|
||||||
for (; ip_addr->s_addr != 0; ++ip_addr) {
|
|
||||||
memcpy(&server.sin_addr, ip_addr, sizeof(struct in_addr));
|
|
||||||
i = ap_proxy_doconnect(sock, &server, r);
|
|
||||||
if (i == 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
j = 0;
|
|
||||||
while (server_hp.h_addr_list[j] != NULL) {
|
|
||||||
memcpy(&server.sin_addr, server_hp.h_addr_list[j],
|
|
||||||
sizeof(struct in_addr));
|
|
||||||
i = ap_proxy_doconnect(sock, &server, r);
|
|
||||||
if (i == 0)
|
|
||||||
break;
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
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
|
||||||
char buf[120];
|
return ap_proxyerror(r, HTTP_BAD_GATEWAY,
|
||||||
return ap_proxyerror(r, HTTP_BAD_GATEWAY, ap_pstrcat(r->pool,
|
ap_pstrcat(r->pool, "Could not connect to remote machine: ",
|
||||||
"Could not connect to remote machine: ",
|
strerror(errno), NULL));
|
||||||
ap_strerror(errno, buf, sizeof(buf)), 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 | B_SOCKET);
|
f = ap_bcreate(p, B_RDWR);
|
||||||
ap_bpushfd(f, sock);
|
ap_bpush_iol(f, unix_attach_socket(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);
|
||||||
@@ -329,7 +297,7 @@ int ap_proxy_http_handler(request_rec *r, cache_req *c, char *url,
|
|||||||
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,
|
||||||
SERVER_BASEVERSION)
|
AP_SERVER_BASEVERSION)
|
||||||
: ap_psprintf(p, "%d.%d %s%s",
|
: ap_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),
|
||||||
@@ -338,7 +306,7 @@ int ap_proxy_http_handler(request_rec *r, cache_req *c, char *url,
|
|||||||
}
|
}
|
||||||
|
|
||||||
reqhdrs_arr = ap_table_elts(r->headers_in);
|
reqhdrs_arr = ap_table_elts(r->headers_in);
|
||||||
reqhdrs = (table_entry *) reqhdrs_arr->elts;
|
reqhdrs = (ap_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 */
|
||||||
@@ -357,14 +325,14 @@ int ap_proxy_http_handler(request_rec *r, cache_req *c, char *url,
|
|||||||
|
|
||||||
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);
|
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, 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,
|
||||||
@@ -399,15 +367,18 @@ int ap_proxy_http_handler(request_rec *r, cache_req *c, char *url,
|
|||||||
/* 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);
|
resp_hdrs = ap_proxy_read_headers(r, buffer, HUGE_STRING_LEN, f);
|
||||||
if (resp_hdrs == NULL) {
|
if (resp_hdrs == NULL) {
|
||||||
ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, r->server,
|
ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r->server,
|
||||||
"proxy: Bad HTTP/%d.%d header returned by %s (%s)",
|
"proxy: Bad HTTP/%d.%d header returned by %s (%s)",
|
||||||
major, minor, r->uri, r->method);
|
major, minor, r->uri, r->method);
|
||||||
resp_hdrs = ap_make_table(p, 20);
|
|
||||||
nocache = 1; /* do not cache this broken file */
|
nocache = 1; /* do not cache this broken file */
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
clear_connection(p, resp_hdrs); /* Strip Connection 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 */
|
||||||
@@ -417,94 +388,76 @@ int ap_proxy_http_handler(request_rec *r, cache_req *c, char *url,
|
|||||||
} else {
|
} else {
|
||||||
ap_snprintf(portstr, sizeof portstr, ":%d", i);
|
ap_snprintf(portstr, sizeof portstr, ":%d", i);
|
||||||
}
|
}
|
||||||
ap_table_mergen((table *)resp_hdrs, "Via",
|
ap_cache_el_header_add(c, "Via", (conf->viaopt == via_full)
|
||||||
(conf->viaopt == via_full)
|
? ap_psprintf(p, "%d.%d %s%s (%s)", major, minor,
|
||||||
? ap_psprintf(p, "%d.%d %s%s (%s)",
|
ap_get_server_name(r), portstr, AP_SERVER_BASEVERSION)
|
||||||
major, minor,
|
: ap_psprintf(p, "%d.%d %s%s", major, minor, ap_get_server_name(r), portstr)
|
||||||
ap_get_server_name(r), portstr,
|
|
||||||
SERVER_BASEVERSION)
|
|
||||||
: ap_psprintf(p, "%d.%d %s%s",
|
|
||||||
major, minor,
|
|
||||||
ap_get_server_name(r), portstr)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
clear_connection(p, resp_hdrs); /* Strip Connection hdrs */
|
|
||||||
}
|
}
|
||||||
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";
|
||||||
|
|
||||||
/* no headers */
|
|
||||||
resp_hdrs = ap_make_table(p, 20);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
c->hdrs = resp_hdrs;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* HTTP/1.0 requires us to accept 3 types of dates, but only generate
|
* HTTP/1.0 requires us to accept 3 types of dates, but only generate
|
||||||
* one type
|
* one type
|
||||||
*/
|
*/
|
||||||
if ((datestr = ap_table_get(resp_hdrs, "Date")) != NULL)
|
if (ap_cache_el_header(c, "Date", &datestr) == APR_SUCCESS)
|
||||||
ap_table_set(resp_hdrs, "Date", ap_proxy_date_canon(p, datestr));
|
ap_cache_el_header_set(c, "Date", ap_proxy_date_canon(p, datestr));
|
||||||
if ((datestr = ap_table_get(resp_hdrs, "Last-Modified")) != NULL)
|
if (ap_cache_el_header(c, "Last-Modified", &datestr) == APR_SUCCESS)
|
||||||
ap_table_set(resp_hdrs, "Last-Modified", ap_proxy_date_canon(p, datestr));
|
ap_cache_el_header_set(c, "Last-Modified", ap_proxy_date_canon(p, datestr));
|
||||||
if ((datestr = ap_table_get(resp_hdrs, "Expires")) != NULL)
|
if (ap_cache_el_header(c, "Expires", &datestr) == APR_SUCCESS)
|
||||||
ap_table_set(resp_hdrs, "Expires", ap_proxy_date_canon(p, datestr));
|
ap_cache_el_header_set(c, "Expires", ap_proxy_date_canon(p, datestr));
|
||||||
|
|
||||||
if ((datestr = ap_table_get(resp_hdrs, "Location")) != NULL)
|
if (ap_cache_el_header(c, "Location", &datestr) == APR_SUCCESS)
|
||||||
ap_table_set(resp_hdrs, "Location", proxy_location_reverse_map(r, datestr));
|
ap_cache_el_header_set(c, "Location", proxy_location_reverse_map(r, datestr));
|
||||||
if ((datestr = ap_table_get(resp_hdrs, "URI")) != NULL)
|
if (ap_cache_el_header(c, "URI", &datestr) == APR_SUCCESS)
|
||||||
ap_table_set(resp_hdrs, "URI", proxy_location_reverse_map(r, datestr));
|
ap_cache_el_header_set(c, "URI", proxy_location_reverse_map(r, datestr));
|
||||||
|
|
||||||
/* check if NoCache directive on this host */
|
/* check if NoCache directive on this host */
|
||||||
|
if (ap_cache_el_header(c, "Content-Length", &clen) == APR_SUCCESS)
|
||||||
|
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 && strstr(desthost, ncent[i].name) != NULL)
|
if ((ncent[i].name != NULL && strstr(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;
|
||||||
}
|
}
|
||||||
|
|
||||||
i = ap_proxy_cache_update(c, resp_hdrs, !backasswards, nocache);
|
if(nocache || !ap_proxy_cache_should_cache(r, resp_hdrs, !backasswards))
|
||||||
if (i != DECLINED) {
|
ap_proxy_cache_error(&c);
|
||||||
ap_bclose(f);
|
else
|
||||||
return i;
|
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 (c != NULL && c->fp != NULL &&
|
if (cachefp && ap_bvputs(cachefp, "HTTP/1.0 ", r->status_line, CRLF, NULL) == -1) {
|
||||||
ap_bvputs(c->fp, "HTTP/1.0 ", r->status_line, CRLF, NULL) == -1) {
|
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
|
"proxy: error writing status line to cache");
|
||||||
"proxy: error writing status line to %s", c->tempfile);
|
ap_proxy_cache_error(&c);
|
||||||
c = ap_proxy_cache_error(c);
|
cachefp = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* send headers */
|
/* send headers */
|
||||||
tdo.req = r;
|
ap_cache_el_header_walk(c, ap_proxy_send_hdr_line, r, NULL);
|
||||||
tdo.cache = c;
|
|
||||||
ap_table_do(ap_proxy_send_hdr_line, &tdo, resp_hdrs, NULL);
|
|
||||||
|
|
||||||
if (!r->assbackwards)
|
if (!r->assbackwards)
|
||||||
ap_rputs(CRLF, r);
|
ap_rputs(CRLF, r);
|
||||||
if (c != NULL && c->fp != NULL && ap_bputs(CRLF, c->fp) == -1) {
|
|
||||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
|
|
||||||
"proxy: error writing CRLF to %s", c->tempfile);
|
|
||||||
c = ap_proxy_cache_error(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 respose? If so, send the extra data */
|
||||||
if (backasswards) {
|
if (backasswards) {
|
||||||
ap_bwrite(r->connection->client, buffer, len);
|
ap_bwrite(r->connection->client, buffer, len, &cntr);
|
||||||
if (c != NULL && c->fp != NULL && ap_bwrite(c->fp, buffer, len) != len) {
|
if (cachefp && ap_bwrite(cachefp, buffer, len, &cntr) != len) {
|
||||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
|
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||||
"proxy: error writing extra data to %s", c->tempfile);
|
"proxy: error writing extra data to cache", cachefp);
|
||||||
c = ap_proxy_cache_error(c);
|
ap_proxy_cache_error(&c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -516,19 +469,17 @@ int ap_proxy_http_handler(request_rec *r, cache_req *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) {
|
||||||
/* we need to set this for ap_proxy_send_fb()... */
|
proxy_completion pc;
|
||||||
c->cache_completion = conf->cache.cache_completion;
|
pc.content_length = content_length;
|
||||||
ap_proxy_send_fb(f, r, c);
|
pc.cache_completion = conf->cache_completion;
|
||||||
|
ap_proxy_send_fb(&pc, f, r, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
ap_proxy_cache_tidy(c);
|
|
||||||
|
|
||||||
ap_bclose(f);
|
ap_bclose(f);
|
||||||
|
if(c) ap_proxy_cache_update(c);
|
||||||
ap_proxy_garbage_coll(r);
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
@@ -416,7 +416,7 @@ static int proxy_getline(char *s, int n, BUFF *in, int fold)
|
|||||||
* the next line begins with a continuation character.
|
* the next line begins with a continuation character.
|
||||||
*/
|
*/
|
||||||
} while (fold && (retval != 1) && (n > 1)
|
} while (fold && (retval != 1) && (n > 1)
|
||||||
&& (ap_blookc(&next, in) == 1)
|
&& (next = ap_blookc(in))
|
||||||
&& ((next == ' ') || (next == '\t')));
|
&& ((next == ' ') || (next == '\t')));
|
||||||
|
|
||||||
return total;
|
return total;
|
||||||
@@ -430,7 +430,7 @@ static int proxy_getline(char *s, int n, BUFF *in, int fold)
|
|||||||
* @@@: XXX: FIXME: currently the headers are passed thru un-merged.
|
* @@@: XXX: FIXME: currently the headers are passed thru un-merged.
|
||||||
* Is that okay, or should they be collapsed where possible?
|
* Is that okay, or should they be collapsed where possible?
|
||||||
*/
|
*/
|
||||||
table *ap_proxy_read_headers(request_rec *r, char *buffer, int size, BUFF *f)
|
ap_table_t *ap_proxy_read_headers(request_rec *r, char *buffer, int size, BUFF *f)
|
||||||
{
|
{
|
||||||
ap_table_t *resp_hdrs;
|
ap_table_t *resp_hdrs;
|
||||||
int len;
|
int len;
|
||||||
@@ -458,7 +458,7 @@ table *ap_proxy_read_headers(request_rec *r, char *buffer, int size, BUFF *f)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, r->server,
|
ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r->server,
|
||||||
"proxy: Ignoring duplicate HTTP header "
|
"proxy: Ignoring duplicate HTTP header "
|
||||||
"returned by %s (%s)", r->uri, r->method);
|
"returned by %s (%s)", r->uri, r->method);
|
||||||
continue;
|
continue;
|
||||||
@@ -491,18 +491,21 @@ table *ap_proxy_read_headers(request_rec *r, char *buffer, int size, BUFF *f)
|
|||||||
return resp_hdrs;
|
return resp_hdrs;
|
||||||
}
|
}
|
||||||
|
|
||||||
long int ap_proxy_send_fb(BUFF *f, request_rec *r, cache_req *c)
|
long int ap_proxy_send_fb(proxy_completion *completion, BUFF *f, request_rec *r, ap_cache_el *c)
|
||||||
{
|
{
|
||||||
int ok;
|
int ok;
|
||||||
char buf[IOBUFSIZE];
|
char buf[IOBUFSIZE];
|
||||||
long total_bytes_rcvd;
|
long total_bytes_rcvd, in_buffer;
|
||||||
|
proxy_server_conf *conf = (proxy_server_conf *) ap_get_module_config(r->server->module_config, &proxy_module);
|
||||||
|
ap_ssize_t cntr;
|
||||||
register int n, o, w;
|
register int n, o, w;
|
||||||
conn_rec *con = r->connection;
|
conn_rec *con = r->connection;
|
||||||
int alternate_timeouts = 1; /* 1 if we alternate between soft & hard timeouts */
|
int alternate_timeouts = 1; /* 1 if we alternate between soft & hard timeouts */
|
||||||
|
BUFF *cachefp = NULL;
|
||||||
|
int written = 0, wrote_to_cache;
|
||||||
|
|
||||||
total_bytes_rcvd = 0;
|
total_bytes_rcvd = 0;
|
||||||
if (c != NULL)
|
if (c) ap_cache_el_data(c, &cachefp);
|
||||||
c->written = 0;
|
|
||||||
|
|
||||||
#ifdef CHARSET_EBCDIC
|
#ifdef CHARSET_EBCDIC
|
||||||
/* The cache copy is ASCII, not EBCDIC, even for text/html) */
|
/* The cache copy is ASCII, not EBCDIC, even for text/html) */
|
||||||
@@ -527,7 +530,7 @@ long int ap_proxy_send_fb(BUFF *f, request_rec *r, cache_req *c)
|
|||||||
* BUT, if we *can't* continue anyway, just use hard_timeout.
|
* BUT, if we *can't* continue anyway, just use hard_timeout.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (c == NULL || c->len <= 0 || c->cache_completion == 1.0) {
|
if (!completion || completion->content_length > 0 || completion->cache_completion == 1.0) {
|
||||||
alternate_timeouts = 0;
|
alternate_timeouts = 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -536,61 +539,55 @@ long int ap_proxy_send_fb(BUFF *f, request_rec *r, cache_req *c)
|
|||||||
* or (after the client aborted) while we can successfully
|
* or (after the client aborted) while we can successfully
|
||||||
* read and finish the configured cache_completion.
|
* read and finish the configured cache_completion.
|
||||||
*/
|
*/
|
||||||
for (ok = 1; ok; ) {
|
for (ok = 1; ok; cntr=0) {
|
||||||
/* Read block from server */
|
/* Read block from server */
|
||||||
n = ap_bread(f, buf, IOBUFSIZE);
|
if(ap_bread(f, buf, IOBUFSIZE, &cntr) != APR_SUCCESS && !cntr)
|
||||||
|
{
|
||||||
if (n == -1) { /* input error */
|
|
||||||
if (c != NULL) {
|
if (c != NULL) {
|
||||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
|
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||||
"proxy: error reading from %s", c->url);
|
"proxy: error reading from %s", c->name);
|
||||||
c = ap_proxy_cache_error(c);
|
ap_proxy_cache_error(&c);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (n == 0)
|
else if(cntr == 0) break;
|
||||||
break; /* EOF */
|
|
||||||
o = 0;
|
|
||||||
total_bytes_rcvd += n;
|
|
||||||
|
|
||||||
/* Write to cache first. */
|
/* Write to cache first. */
|
||||||
/*@@@ XXX FIXME: Assuming that writing the cache file won't time out?!!? */
|
/*@@@ XXX FIXME: Assuming that writing the cache file won't time out?!!? */
|
||||||
if (c != NULL && c->fp != NULL) {
|
if (cachefp && ap_bwrite(cachefp, &buf[0], cntr, &wrote_to_cache) != APR_SUCCESS) {
|
||||||
if (ap_bwrite(c->fp, &buf[0], n) != n) {
|
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
|
"proxy: error writing to cache");
|
||||||
"proxy: error writing to %s", c->tempfile);
|
ap_proxy_cache_error(&c);
|
||||||
c = ap_proxy_cache_error(c);
|
cachefp = NULL;
|
||||||
} else {
|
} else {
|
||||||
c->written += n;
|
written += n;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
o = 0;
|
||||||
|
total_bytes_rcvd += cntr;
|
||||||
|
in_buffer = cntr;
|
||||||
|
|
||||||
/* Write the block to the client, detect aborted transfers */
|
/* Write the block to the client, detect aborted transfers */
|
||||||
while (!con->aborted && n > 0) {
|
while (!con->aborted && in_buffer > 0) {
|
||||||
w = ap_bwrite(con->client, &buf[o], n);
|
if (ap_bwrite(con->client, &buf[o], in_buffer, &cntr) != APR_SUCCESS) {
|
||||||
|
if (completion) {
|
||||||
if (w <= 0) {
|
|
||||||
if (c != NULL && c->fp != NULL) {
|
|
||||||
/* when a send failure occurs, we need to decide
|
/* when a send failure occurs, we need to decide
|
||||||
* whether to continue loading and caching the
|
* whether to continue loading and caching the
|
||||||
* document, or to abort the whole thing
|
* document, or to abort the whole thing
|
||||||
*/
|
*/
|
||||||
ok = (c->len > 0) &&
|
ok = (completion->content_length > 0) &&
|
||||||
(c->cache_completion > 0) &&
|
(completion->cache_completion > 0) &&
|
||||||
(c->len * c->cache_completion < total_bytes_rcvd);
|
(completion->content_length * completion->cache_completion < total_bytes_rcvd);
|
||||||
|
|
||||||
if (! ok) {
|
if (!ok)
|
||||||
ap_pclosef(c->req->pool, c->fp->fd);
|
ap_proxy_cache_error(&c);
|
||||||
c->fp = NULL;
|
|
||||||
unlink(c->tempfile);
|
|
||||||
c = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
con->aborted = 1;
|
con->aborted = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
n -= w;
|
in_buffer -= cntr;
|
||||||
o += w;
|
o += cntr;
|
||||||
} /* while client alive and more data to send */
|
} /* while client alive and more data to send */
|
||||||
} /* loop and ap_bread while "ok" */
|
} /* loop and ap_bread while "ok" */
|
||||||
|
|
||||||
@@ -611,7 +608,7 @@ void ap_proxy_send_headers(request_rec *r, const char *respline, ap_table_t *t)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
BUFF *fp = r->connection->client;
|
BUFF *fp = r->connection->client;
|
||||||
table_entry *elts = (table_entry *) ap_table_elts(t)->elts;
|
ap_table_entry_t *elts = (ap_table_entry_t *) ap_table_elts(t)->elts;
|
||||||
|
|
||||||
ap_bvputs(fp, respline, CRLF, NULL);
|
ap_bvputs(fp, respline, CRLF, NULL);
|
||||||
|
|
||||||
@@ -659,108 +656,6 @@ int ap_proxy_liststr(const char *list, const char *val)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CASE_BLIND_FILESYSTEM
|
|
||||||
|
|
||||||
/*
|
|
||||||
* On some platforms, the file system is NOT case sensitive. So, a == A
|
|
||||||
* need to map to smaller set of characters
|
|
||||||
*/
|
|
||||||
void ap_proxy_hash(const char *it, char *val, int ndepth, int nlength)
|
|
||||||
{
|
|
||||||
ap_md5_ctx_t context;
|
|
||||||
unsigned char digest[MD5_DIGESTSIZE];
|
|
||||||
char tmp[26];
|
|
||||||
int i, k, d;
|
|
||||||
unsigned int x;
|
|
||||||
static const char enc_table[32] = "abcdefghijklmnopqrstuvwxyz012345";
|
|
||||||
|
|
||||||
ap_MD5Init(&context);
|
|
||||||
ap_MD5Update(&context, (const unsigned char *) it, strlen(it));
|
|
||||||
ap_MD5Final(digest, &context);
|
|
||||||
|
|
||||||
/* encode 128 bits as 26 characters, using a modified uuencoding */
|
|
||||||
/* the encoding is 5 bytes -> 8 characters
|
|
||||||
* i.e. 128 bits is 3 x 5 bytes + 1 byte -> 3 * 8 characters + 2 characters
|
|
||||||
*/
|
|
||||||
for (i = 0, k = 0; i < 15; i += 5) {
|
|
||||||
x = (digest[i] << 24) | (digest[i + 1] << 16) | (digest[i + 2] << 8) | digest[i + 3];
|
|
||||||
tmp[k++] = enc_table[x >> 27];
|
|
||||||
tmp[k++] = enc_table[(x >> 22) & 0x1f];
|
|
||||||
tmp[k++] = enc_table[(x >> 17) & 0x1f];
|
|
||||||
tmp[k++] = enc_table[(x >> 12) & 0x1f];
|
|
||||||
tmp[k++] = enc_table[(x >> 7) & 0x1f];
|
|
||||||
tmp[k++] = enc_table[(x >> 2) & 0x1f];
|
|
||||||
x = ((x & 0x3) << 8) | digest[i + 4];
|
|
||||||
tmp[k++] = enc_table[x >> 5];
|
|
||||||
tmp[k++] = enc_table[x & 0x1f];
|
|
||||||
}
|
|
||||||
/* one byte left */
|
|
||||||
x = digest[15];
|
|
||||||
tmp[k++] = enc_table[x >> 3]; /* use up 5 bits */
|
|
||||||
tmp[k++] = enc_table[x & 0x7];
|
|
||||||
/* now split into directory levels */
|
|
||||||
|
|
||||||
for (i = k = d = 0; d < ndepth; ++d) {
|
|
||||||
memcpy(&val[i], &tmp[k], nlength);
|
|
||||||
k += nlength;
|
|
||||||
val[i + nlength] = '/';
|
|
||||||
i += nlength + 1;
|
|
||||||
}
|
|
||||||
memcpy(&val[i], &tmp[k], 26 - k);
|
|
||||||
val[i + 26 - k] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
void ap_proxy_hash(const char *it, char *val, int ndepth, int nlength)
|
|
||||||
{
|
|
||||||
ap_md5_ctx_t context;
|
|
||||||
unsigned char digest[MD5_DIGESTSIZE];
|
|
||||||
char tmp[22];
|
|
||||||
int i, k, d;
|
|
||||||
unsigned int x;
|
|
||||||
#if defined(AIX) && defined(__ps2__)
|
|
||||||
/* Believe it or not, AIX 1.x does not allow you to name a file '@',
|
|
||||||
* so hack around it in the encoding. */
|
|
||||||
static const char enc_table[64] =
|
|
||||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_%";
|
|
||||||
#else
|
|
||||||
static const char enc_table[64] =
|
|
||||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_@";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ap_MD5Init(&context);
|
|
||||||
ap_MD5Update(&context, (const unsigned char *) it, strlen(it));
|
|
||||||
ap_MD5Final(digest, &context);
|
|
||||||
|
|
||||||
/* encode 128 bits as 22 characters, using a modified uuencoding */
|
|
||||||
/* the encoding is 3 bytes -> 4 characters
|
|
||||||
* i.e. 128 bits is 5 x 3 bytes + 1 byte -> 5 * 4 characters + 2 characters
|
|
||||||
*/
|
|
||||||
for (i = 0, k = 0; i < 15; i += 3) {
|
|
||||||
x = (digest[i] << 16) | (digest[i + 1] << 8) | digest[i + 2];
|
|
||||||
tmp[k++] = enc_table[x >> 18];
|
|
||||||
tmp[k++] = enc_table[(x >> 12) & 0x3f];
|
|
||||||
tmp[k++] = enc_table[(x >> 6) & 0x3f];
|
|
||||||
tmp[k++] = enc_table[x & 0x3f];
|
|
||||||
}
|
|
||||||
/* one byte left */
|
|
||||||
x = digest[15];
|
|
||||||
tmp[k++] = enc_table[x >> 2]; /* use up 6 bits */
|
|
||||||
tmp[k++] = enc_table[(x << 4) & 0x3f];
|
|
||||||
/* now split into directory levels */
|
|
||||||
|
|
||||||
for (i = k = d = 0; d < ndepth; ++d) {
|
|
||||||
memcpy(&val[i], &tmp[k], nlength);
|
|
||||||
k += nlength;
|
|
||||||
val[i + nlength] = '/';
|
|
||||||
i += nlength + 1;
|
|
||||||
}
|
|
||||||
memcpy(&val[i], &tmp[k], 22 - k);
|
|
||||||
val[i + 22 - k] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* CASE_BLIND_FILESYSTEM */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Converts 8 hex digits to a time integer
|
* Converts 8 hex digits to a time integer
|
||||||
@@ -806,16 +701,14 @@ void ap_proxy_sec2hex(int t, char *y)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
cache_req *ap_proxy_cache_error(cache_req *c)
|
void ap_proxy_cache_error(ap_cache_el **c)
|
||||||
{
|
{
|
||||||
if (c != NULL) {
|
if (c && *c) {
|
||||||
if (c->fp != NULL) {
|
const char *name = (*c)->name;
|
||||||
ap_pclosef(c->req->pool, c->fp->fd);
|
ap_cache_el_finalize((*c));
|
||||||
c->fp = NULL;
|
ap_cache_remove((*c)->cache, name);
|
||||||
|
*c = NULL;
|
||||||
}
|
}
|
||||||
if (c->tempfile) unlink(c->tempfile);
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int ap_proxyerror(request_rec *r, int statuscode, const char *message)
|
int ap_proxyerror(request_rec *r, int statuscode, const char *message)
|
||||||
@@ -841,8 +734,7 @@ int ap_proxyerror(request_rec *r, int statuscode, const char *message)
|
|||||||
/*
|
/*
|
||||||
* This routine returns its own error message
|
* This routine returns its own error message
|
||||||
*/
|
*/
|
||||||
const char *
|
const char *ap_proxy_host2addr(const char *host, struct hostent *reqhp)
|
||||||
ap_proxy_host2addr(const char *host, struct hostent *reqhp)
|
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct hostent *hp;
|
struct hostent *hp;
|
||||||
@@ -898,7 +790,7 @@ static const char *
|
|||||||
err = ap_proxy_canon_netloc(r->pool, &url, &user, &password, &host, &port);
|
err = ap_proxy_canon_netloc(r->pool, &url, &user, &password, &host, &port);
|
||||||
|
|
||||||
if (err != NULL)
|
if (err != NULL)
|
||||||
ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, r,
|
ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, r,
|
||||||
"%s", err);
|
"%s", err);
|
||||||
|
|
||||||
r->hostname = host;
|
r->hostname = host;
|
||||||
@@ -1237,24 +1129,32 @@ static int proxy_match_word(struct dirconn_entry *This, request_rec *r)
|
|||||||
return host != NULL && strstr(host, This->name) != NULL;
|
return host != NULL && strstr(host, This->name) != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ap_proxy_doconnect(int sock, struct sockaddr_in *addr, request_rec *r)
|
int ap_proxy_doconnect(ap_socket_t *sock, char *host, ap_uint32_t port, request_rec *r)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
for (i = 0; host[i] != '\0'; i++)
|
||||||
|
if (!ap_isdigit(host[i]) && host[i] != '.')
|
||||||
|
break;
|
||||||
|
|
||||||
do {
|
ap_set_remote_port(sock, port);
|
||||||
i = connect(sock, (struct sockaddr *) addr, sizeof(struct sockaddr_in));
|
if (host[i] == '\0') {
|
||||||
#ifdef WIN32
|
ap_set_remote_ipaddr(sock, host);
|
||||||
if (i == SOCKET_ERROR)
|
host = NULL;
|
||||||
errno = WSAGetLastError();
|
|
||||||
#endif /* WIN32 */
|
|
||||||
} while (i == -1 && errno == EINTR);
|
|
||||||
if (i == -1) {
|
|
||||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
|
|
||||||
"proxy connect to %s port %d failed",
|
|
||||||
inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
|
|
||||||
}
|
}
|
||||||
|
for(;;)
|
||||||
return i;
|
{
|
||||||
|
switch(ap_connect(sock, host))
|
||||||
|
{
|
||||||
|
case APR_EINTR:
|
||||||
|
continue;
|
||||||
|
case APR_SUCCESS:
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "proxy connect to %s port %d failed", host, port);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function is called by ap_table_do() for all header lines */
|
/* This function is called by ap_table_do() for all header lines */
|
||||||
@@ -1262,27 +1162,86 @@ int ap_proxy_doconnect(int sock, struct sockaddr_in *addr, request_rec *r)
|
|||||||
/* It is passed a table_do_args struct pointer and a MIME field and value pair */
|
/* It is passed a table_do_args struct pointer and a MIME field and value pair */
|
||||||
int ap_proxy_send_hdr_line(void *p, const char *key, const char *value)
|
int ap_proxy_send_hdr_line(void *p, const char *key, const char *value)
|
||||||
{
|
{
|
||||||
struct tbl_do_args *parm = (struct tbl_do_args *)p;
|
struct request_rec *r = (struct request_rec *)p;
|
||||||
|
|
||||||
if (key == NULL || value == NULL || value[0] == '\0')
|
if (key == NULL || value == NULL || value[0] == '\0')
|
||||||
return 1;
|
return 1;
|
||||||
if (!parm->req->assbackwards)
|
if (!r->assbackwards)
|
||||||
ap_rvputs(parm->req, key, ": ", value, CRLF, NULL);
|
ap_rvputs(r, key, ": ", value, CRLF, NULL);
|
||||||
if (parm->cache != NULL && parm->cache->fp != NULL &&
|
|
||||||
ap_bvputs(parm->cache->fp, key, ": ", value, CRLF, NULL) == -1) {
|
|
||||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, parm->cache->req,
|
|
||||||
"proxy: error writing header to %s", parm->cache->tempfile);
|
|
||||||
parm->cache = ap_proxy_cache_error(parm->cache);
|
|
||||||
}
|
|
||||||
return 1; /* tell ap_table_do() to continue calling us for more headers */
|
return 1; /* tell ap_table_do() to continue calling us for more headers */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* send a text line to one or two BUFF's; return line length */
|
/* send a text line to one or two BUFF's; return line length */
|
||||||
unsigned ap_proxy_bputs2(const char *data, BUFF *client, cache_req *cache)
|
unsigned ap_proxy_bputs2(const char *data, BUFF *client, ap_cache_el *cache)
|
||||||
{
|
{
|
||||||
unsigned len = ap_bputs(data, client);
|
unsigned len = ap_bputs(data, client);
|
||||||
if (cache != NULL && cache->fp != NULL)
|
BUFF *cachefp = NULL;
|
||||||
ap_bputs(data, cache->fp);
|
|
||||||
|
if (ap_cache_el_data(cache, &cachefp) == APR_SUCCESS)
|
||||||
|
ap_bputs(data, cachefp);
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ap_proxy_cache_send(request_rec *r, ap_cache_el *c)
|
||||||
|
{
|
||||||
|
BUFF *cachefp = NULL, *fp = r->connection->client;
|
||||||
|
char buffer[500];
|
||||||
|
|
||||||
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"Sending cache file for %s", c->name);
|
||||||
|
if(ap_cache_el_data(c, &cachefp) != APR_SUCCESS)
|
||||||
|
return HTTP_INTERNAL_SERVER_ERROR;
|
||||||
|
/* send the response */
|
||||||
|
if(ap_bgets(buffer, sizeof(buffer), cachefp))
|
||||||
|
ap_bvputs(fp, buffer, NULL);
|
||||||
|
/* send headers */
|
||||||
|
ap_cache_el_header_walk(c, ap_proxy_send_hdr_line, r, NULL);
|
||||||
|
ap_bputs(CRLF, fp);
|
||||||
|
/* send data */
|
||||||
|
if(!r->header_only && !ap_proxy_send_fb(0, cachefp, r, NULL))
|
||||||
|
return HTTP_INTERNAL_SERVER_ERROR;
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ap_proxy_cache_should_cache(request_rec *r, ap_table_t *resp_hdrs, const int is_HTTP1)
|
||||||
|
{
|
||||||
|
const char *expire = ap_table_get(resp_hdrs, "Expires");
|
||||||
|
time_t expc;
|
||||||
|
if (expire != NULL)
|
||||||
|
expc = ap_parseHTTPdate(expire);
|
||||||
|
else
|
||||||
|
expc = BAD_DATE;
|
||||||
|
if((r->status != HTTP_OK && r->status != HTTP_MOVED_PERMANENTLY && r->status != HTTP_NOT_MODIFIED) ||
|
||||||
|
(r->status == HTTP_NOT_MODIFIED) ||
|
||||||
|
r->header_only ||
|
||||||
|
ap_table_get(r->headers_in, "Authorization") != NULL ||
|
||||||
|
(expire != NULL && expc == BAD_DATE) ||
|
||||||
|
(r->status == HTTP_OK && !ap_table_get(resp_hdrs, "Last-Modified") && is_HTTP1))
|
||||||
|
{
|
||||||
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"proxy: Response is not cacheable: %s", r->unparsed_uri);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* what responses should we not cache?
|
||||||
|
* Unknown status responses and those known to be uncacheable
|
||||||
|
* 304 HTTP_NOT_MODIFIED response when we have no valid cache file, or
|
||||||
|
* 200 HTTP_OK response from HTTP/1.0 and up without a Last-Modified header, or
|
||||||
|
* HEAD requests, or
|
||||||
|
* requests with an Authorization header, or
|
||||||
|
* protocol requests nocache (e.g. ftp with user/password)
|
||||||
|
*/
|
||||||
|
/* @@@ XXX FIXME: is the test "r->status != HTTP_MOVED_PERMANENTLY" correct?
|
||||||
|
* or shouldn't it be "ap_is_HTTP_REDIRECT(r->status)" ? -MnKr */
|
||||||
|
int ap_proxy_cache_update(ap_cache_el *c)
|
||||||
|
{
|
||||||
|
ap_cache_handle_t *h = c ? c->cache : NULL;
|
||||||
|
if(!h) return DECLINED;
|
||||||
|
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
|
||||||
|
"proxy: Cache finalized: %s", c->name);
|
||||||
|
ap_cache_el_finalize(c);
|
||||||
|
ap_cache_garbage_collect(h);
|
||||||
|
return DECLINED;
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user