--- /dev/null
+
+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
--- /dev/null
+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)
#include "http_log.h"
#include "http_vhost.h"
#include "http_request.h"
+#include "util_date.h"
/* Some WWW schemes and their default ports; this is basically /etc/services */
/* This will become global when the protocol abstraction comes */
{"wais", DEFAULT_WAIS_PORT},
{"snews", DEFAULT_SNEWS_PORT},
{"prospero", DEFAULT_PROSPERO_PORT},
- {NULL, -1} /* unknown port */
+ {NULL, -1} /* unknown port */
};
/*
const char *aliasp = alias_fakename, *urip = uri;
while (aliasp < end_fakename) {
- if (*aliasp == '/') {
- /* any number of '/' in the alias matches any number in
- * the supplied URI, but there must be at least one...
- */
- if (*urip != '/')
- return 0;
-
- while (*aliasp == '/')
- ++aliasp;
- while (*urip == '/')
- ++urip;
- }
- else {
- /* Other characters are compared literally */
- if (*urip++ != *aliasp++)
- return 0;
- }
+ if (*aliasp == '/') {
+ /* any number of '/' in the alias matches any number in
+ * the supplied URI, but there must be at least one...
+ */
+ if (*urip != '/')
+ return 0;
+
+ while (*aliasp == '/')
+ ++aliasp;
+ while (*urip == '/')
+ ++urip;
+ }
+ else {
+ /* Other characters are compared literally */
+ if (*urip++ != *aliasp++)
+ return 0;
+ }
}
/* Check last alias path component matched all the way */
if (aliasp[-1] != '/' && *urip != '\0' && *urip != '/')
- return 0;
+ return 0;
/* Return number of characters from URI which matched (may be
* greater than length of alias, since we may have matched
conf = (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
if (conf->req && r->parsed_uri.scheme) {
- /* but it might be something vhosted */
+ /* but it might be something vhosted */
if (!(r->parsed_uri.hostname
- && !strcasecmp(r->parsed_uri.scheme, ap_http_method(r))
- && ap_matches_request_vhost(r, r->parsed_uri.hostname,
- r->parsed_uri.port_str ? r->parsed_uri.port : ap_default_port(r)))) {
- r->proxyreq = 1;
- r->uri = r->unparsed_uri;
- r->filename = ap_pstrcat(r->pool, "proxy:", r->uri, NULL);
- r->handler = "proxy-server";
+ && !strcasecmp(r->parsed_uri.scheme, ap_http_method(r))
+ && ap_matches_request_vhost(r, r->parsed_uri.hostname,
+ r->parsed_uri.port_str ? r->parsed_uri.port : ap_default_port(r)))) {
+ r->proxyreq = 1;
+ r->uri = r->unparsed_uri;
+ r->filename = ap_pstrcat(r->pool, "proxy:", r->uri, NULL);
+ r->handler = "proxy-server";
}
}
/* We need special treatment for CONNECT proxying: it has no scheme part */
else if (conf->req && r->method_number == M_CONNECT
- && r->parsed_uri.hostname
- && r->parsed_uri.port_str) {
- r->proxyreq = 1;
- r->uri = r->unparsed_uri;
- r->filename = ap_pstrcat(r->pool, "proxy:", r->uri, NULL);
- r->handler = "proxy-server";
+ && r->parsed_uri.hostname
+ && r->parsed_uri.port_str) {
+ r->proxyreq = 1;
+ r->uri = r->unparsed_uri;
+ r->filename = ap_pstrcat(r->pool, "proxy:", r->uri, NULL);
+ r->handler = "proxy-server";
}
return DECLINED;
}
struct proxy_alias *ent = (struct proxy_alias *) conf->aliases->elts;
if (r->proxyreq) {
- /* someone has already set up the proxy, it was possibly ourselves
- * in proxy_detect
- */
- return OK;
+ /* someone has already set up the proxy, it was possibly ourselves
+ * in proxy_detect
+ */
+ return OK;
}
/* XXX: since r->uri has been manipulated already we're not really
for (i = 0; i < conf->aliases->nelts; i++) {
len = alias_match(r->uri, ent[i].fake);
-
- if (len > 0) {
+
+ if (len > 0) {
r->filename = ap_pstrcat(r->pool, "proxy:", ent[i].real,
r->uri + len, NULL);
r->handler = "proxy-server";
r->proxyreq = 1;
return OK;
- }
+ }
}
return DECLINED;
}
char *url, *p;
if (!r->proxyreq || strncmp(r->filename, "proxy:", 6) != 0)
- return DECLINED;
+ return DECLINED;
url = &r->filename[6];
/* canonicalise each specific scheme */
if (strncasecmp(url, "http:", 5) == 0)
- return ap_proxy_http_canon(r, url + 5, "http", DEFAULT_HTTP_PORT);
+ return ap_proxy_http_canon(r, url + 5, "http", DEFAULT_HTTP_PORT);
else if (strncasecmp(url, "ftp:", 4) == 0)
- return ap_proxy_ftp_canon(r, url + 4);
+ return ap_proxy_ftp_canon(r, url + 4);
p = strchr(url, ':');
if (p == NULL || p == url)
- return HTTP_BAD_REQUEST;
+ return HTTP_BAD_REQUEST;
- 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)
-{
- ap_proxy_garbage_init(r, 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 */
-/* 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)
{
char *nuri;
/* We only want to worry about GETs */
if (!r->proxyreq || r->method_number != M_GET || !r->parsed_uri.hostname)
- return DECLINED;
+ return DECLINED;
/* If host does contain a dot already, or it is "localhost", decline */
if (strchr(r->parsed_uri.hostname, '.') != NULL
|| strcasecmp(r->parsed_uri.hostname, "localhost") == 0)
- return DECLINED; /* host name has a dot already */
+ return DECLINED; /* host name has a dot already */
ref = ap_table_get(r->headers_in, "Referer");
/* Reassemble the request, but insert the domain after the host name */
/* Note that the domain name always starts with a dot */
r->parsed_uri.hostname = ap_pstrcat(r->pool, r->parsed_uri.hostname,
- domain, NULL);
+ domain, NULL);
nuri = ap_unparse_uri_components(r->pool,
- &r->parsed_uri,
- UNP_REVEALPASSWORD);
+ &r->parsed_uri,
+ UNP_REVEALPASSWORD);
ap_table_set(r->headers_out, "Location", nuri);
- ap_log_rerror(APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, r,
- "Domain missing: %s sent to %s%s%s", r->uri,
- ap_unparse_uri_components(r->pool, &r->parsed_uri,
- UNP_OMITUSERINFO),
- ref ? " from " : "", ref ? ref : "");
+ ap_log_rerror(APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, 0, r,
+ "Domain missing: %s sent to %s%s%s", r->uri,
+ ap_unparse_uri_components(r->pool, &r->parsed_uri,
+ UNP_OMITUSERINFO),
+ ref ? " from " : "", ref ? ref : "");
return HTTP_MOVED_PERMANENTLY;
}
{
char *url, *scheme, *p;
void *sconf = r->server->module_config;
- proxy_server_conf *conf =
- (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
+ proxy_server_conf *conf = (proxy_server_conf *)
+ ap_get_module_config(sconf, &proxy_module);
ap_array_header_t *proxies = conf->proxies;
struct proxy_remote *ents = (struct proxy_remote *) proxies->elts;
int i, rc;
- cache_req *cr;
+ ap_cache_el *cr=NULL;
int direct_connect = 0;
const char *maxfwd_str;
-
+ const char *pragma, *auth, *imstr;
+
if (!r->proxyreq || strncmp(r->filename, "proxy:", 6) != 0)
- return DECLINED;
-
- if (r->method_number == M_TRACE &&
- (maxfwd_str = ap_table_get(r->headers_in, "Max-Forwards")) != NULL) {
- int maxfwd = strtol(maxfwd_str, NULL, 10);
- if (maxfwd < 1) {
- int access_status;
- r->proxyreq = 0;
- if ((access_status = ap_send_http_trace(r)))
- ap_die(access_status, r);
- else
- ap_finalize_request_protocol(r);
- return OK;
- }
- ap_table_setn(r->headers_in, "Max-Forwards",
- ap_psprintf(r->pool, "%d", (maxfwd > 0) ? maxfwd-1 : 0));
+ return DECLINED;
+
+ if (r->method_number == M_TRACE && (maxfwd_str =
+ ap_table_get(r->headers_in, "Max-Forwards")) != NULL) {
+ int maxfwd = strtol(maxfwd_str, NULL, 10);
+ if (maxfwd < 1) {
+ int access_status;
+ r->proxyreq = 0;
+ if ((access_status = ap_send_http_trace(r)))
+ ap_die(access_status, r);
+ else
+ ap_finalize_request_protocol(r);
+ return OK;
+ }
+ ap_table_setn(r->headers_in, "Max-Forwards",
+ ap_psprintf(r->pool, "%d", (maxfwd > 0) ? maxfwd-1 : 0));
}
if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR)))
- return rc;
+ return rc;
url = r->filename + 6;
p = strchr(url, ':');
if (p == NULL)
- return HTTP_BAD_REQUEST;
-
- rc = ap_proxy_cache_check(r, url, &conf->cache, &cr);
- if (rc != DECLINED)
- return rc;
-
+ return HTTP_BAD_REQUEST;
+
+ pragma = ap_table_get(r->headers_in, "Pragma");
+ auth = ap_table_get(r->headers_in, "Authorization");
+ 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 (conf->domain != NULL) {
- rc = proxy_needsdomain(r, url, conf->domain);
- if (ap_is_HTTP_REDIRECT(rc))
- return HTTP_MOVED_PERMANENTLY;
+ rc = proxy_needsdomain(r, url, conf->domain);
+ if (ap_is_HTTP_REDIRECT(rc))
+ return HTTP_MOVED_PERMANENTLY;
}
*p = '\0';
/* we only know how to handle communication to a proxy via http */
/*if (strcasecmp(scheme, "http") == 0) */
{
- int ii;
- struct dirconn_entry *list = (struct dirconn_entry *) conf->dirconn->elts;
+ int ii;
+ struct dirconn_entry *list = (struct dirconn_entry *) conf->dirconn->elts;
- for (direct_connect = ii = 0; ii < conf->dirconn->nelts && !direct_connect; ii++) {
- direct_connect = list[ii].matcher(&list[ii], r);
- }
+ for (direct_connect = ii = 0; ii < conf->dirconn->nelts && !direct_connect; ii++) {
+ direct_connect = list[ii].matcher(&list[ii], r);
+ }
#if DEBUGGING
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, r,
- (direct_connect) ? "NoProxy for %s" : "UseProxy for %s",
- r->uri);
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
+ (direct_connect) ? "NoProxy for %s" : "UseProxy for %s",
+ r->uri);
#endif
}
/* firstly, try a proxy, unless a NoProxy directive is active */
if (!direct_connect)
- for (i = 0; i < proxies->nelts; i++) {
- p = strchr(ents[i].scheme, ':'); /* is it a partial URL? */
- if (strcmp(ents[i].scheme, "*") == 0 ||
- (p == NULL && strcasecmp(scheme, ents[i].scheme) == 0) ||
- (p != NULL &&
- strncasecmp(url, ents[i].scheme, strlen(ents[i].scheme)) == 0)) {
- /* CONNECT is a special method that bypasses the normal
- * proxy code.
- */
- if (r->method_number == M_CONNECT)
- rc = ap_proxy_connect_handler(r, cr, url, ents[i].hostname,
- ents[i].port);
+ for (i = 0; i < proxies->nelts; i++) {
+ p = strchr(ents[i].scheme, ':'); /* is it a partial URL? */
+ if (strcmp(ents[i].scheme, "*") == 0 ||
+ (p == NULL && strcasecmp(scheme, ents[i].scheme) == 0) ||
+ (p != NULL &&
+ strncasecmp(url, ents[i].scheme, strlen(ents[i].scheme)) == 0)) {
+ /* CONNECT is a special method that bypasses the normal
+ * proxy code.
+ */
+ if (r->method_number == M_CONNECT)
+ rc = ap_proxy_connect_handler(r, cr, url, ents[i].hostname,
+ ents[i].port);
/* we only know how to handle communication to a proxy via http */
- else if (strcasecmp(ents[i].protocol, "http") == 0)
- rc = ap_proxy_http_handler(r, cr, url, ents[i].hostname,
- ents[i].port);
- else
- rc = DECLINED;
-
- /* an error or success */
- if (rc != DECLINED && rc != HTTP_BAD_GATEWAY)
- return rc;
- /* we failed to talk to the upstream proxy */
- }
- }
+ else if (strcasecmp(ents[i].protocol, "http") == 0)
+ rc = ap_proxy_http_handler(r, cr, url, ents[i].hostname,
+ ents[i].port);
+ else
+ rc = DECLINED;
+
+ /* an error or success */
+ if (rc != DECLINED && rc != HTTP_BAD_GATEWAY)
+ return rc;
+ /* we failed to talk to the upstream proxy */
+ }
+ }
/* otherwise, try it direct */
/* N.B. what if we're behind a firewall, where we must use a proxy or
*/
/* handle the scheme */
if (r->method_number == M_CONNECT)
- return ap_proxy_connect_handler(r, cr, url, NULL, 0);
+ return ap_proxy_connect_handler(r, cr, url, NULL, 0);
if (strcasecmp(scheme, "http") == 0)
- return ap_proxy_http_handler(r, cr, url, NULL, 0);
+ return ap_proxy_http_handler(r, cr, url, NULL, 0);
if (strcasecmp(scheme, "ftp") == 0)
- return ap_proxy_ftp_handler(r, cr, url);
+ return ap_proxy_ftp_handler(r, cr, url);
else
- return HTTP_FORBIDDEN;
+ return HTTP_FORBIDDEN;
}
/* -------------------------------------------------------------- */
/* Setup configurable data */
-static void *
- create_proxy_config(ap_pool_t *p, server_rec *s)
+static void *create_proxy_config(ap_pool_t *p, server_rec *s)
{
proxy_server_conf *ps = ap_pcalloc(p, sizeof(proxy_server_conf));
ps->dirconn = ap_make_array(p, 10, sizeof(struct dirconn_entry));
ps->nocaches = ap_make_array(p, 10, sizeof(struct nocache_entry));
ps->allowed_connect_ports = ap_make_array(p, 10, sizeof(int));
+ ps->cache_completion = DEFAULT_CACHE_COMPLETION;
ps->domain = NULL;
ps->viaopt = via_off; /* initially backward compatible with 1.3.1 */
ps->req = 0;
- ps->cache.root = NULL;
- 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;
-
+ ap_cache_init(&ps->cache, "mod_proxy cache", s);
return ps;
}
p = strchr(r, ':');
if (p == NULL || p[1] != '/' || p[2] != '/' || p[3] == '\0')
- return "ProxyRemote: Bad syntax for a remote proxy server";
+ return "ProxyRemote: Bad syntax for a remote proxy server";
q = strchr(p + 3, ':');
if (q != NULL) {
- if (sscanf(q + 1, "%u", &port) != 1 || port > 65535)
- return "ProxyRemote: Bad syntax for a remote proxy server (bad port number)";
- *q = '\0';
+ if (sscanf(q + 1, "%u", &port) != 1 || port > 65535)
+ return "ProxyRemote: Bad syntax for a remote proxy server (bad port number)";
+ *q = '\0';
}
else
- port = -1;
+ port = -1;
*p = '\0';
if (strchr(f, ':') == NULL)
- ap_str_tolower(f); /* lowercase scheme */
- ap_str_tolower(p + 3); /* lowercase hostname */
+ ap_str_tolower(f); /* lowercase scheme */
+ ap_str_tolower(p + 3); /* lowercase hostname */
if (port == -1) {
- int i;
- for (i = 0; defports[i].scheme != NULL; i++)
- if (strcasecmp(defports[i].scheme, r) == 0)
- break;
- port = defports[i].port;
+ int i;
+ for (i = 0; defports[i].scheme != NULL; i++)
+ if (strcasecmp(defports[i].scheme, r) == 0)
+ break;
+ port = defports[i].port;
}
new = ap_push_array(conf->proxies);
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 *
add_pass(cmd_parms *cmd, void *dummy, char *f, char *r)
{
return NULL;
}
-static const char *
- set_proxy_exclude(cmd_parms *parms, void *dummy, char *arg)
+static const char *set_proxy_exclude(cmd_parms *parms, void *dummy, char *arg)
{
server_rec *s = parms->server;
proxy_server_conf *conf =
/* Don't duplicate entries */
for (i = 0; i < conf->noproxies->nelts; i++) {
- if (strcasecmp(arg, list[i].name) == 0) /* ignore case for host names */
- found = 1;
+ if (strcasecmp(arg, list[i].name) == 0) /* ignore case for host names */
+ found = 1;
}
if (!found) {
- new = ap_push_array(conf->noproxies);
- 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;
+ new = ap_push_array(conf->noproxies);
+ 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;
}
int *New;
if (!ap_isdigit(arg[0]))
- return "AllowCONNECT: port number must be numeric";
+ return "AllowCONNECT: port number must be numeric";
New = ap_push_array(conf->allowed_connect_ports);
*New = atoi(arg);
/* Don't duplicate entries */
for (i = 0; i < conf->dirconn->nelts; i++) {
- if (strcasecmp(arg, list[i].name) == 0)
- found = 1;
+ if (strcasecmp(arg, list[i].name) == 0)
+ found = 1;
}
if (!found) {
- New = ap_push_array(conf->dirconn);
- New->name = arg;
- New->hostentry = NULL;
+ New = ap_push_array(conf->dirconn);
+ New->name = arg;
+ New->hostentry = NULL;
- if (ap_proxy_is_ipaddr(New, parms->pool)) {
+ if (ap_proxy_is_ipaddr(New, parms->pool)) {
#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));
- 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));
#endif
- }
- else if (ap_proxy_is_domainname(New, parms->pool)) {
- ap_str_tolower(New->name);
+ }
+ else if (ap_proxy_is_domainname(New, parms->pool)) {
+ ap_str_tolower(New->name);
#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);
#endif
- }
- else if (ap_proxy_is_hostname(New, parms->pool)) {
- ap_str_tolower(New->name);
+ }
+ else if (ap_proxy_is_hostname(New, parms->pool)) {
+ ap_str_tolower(New->name);
#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);
#endif
- }
- else {
- ap_proxy_is_word(New, parms->pool);
+ }
+ else {
+ ap_proxy_is_word(New, parms->pool);
#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);
#endif
- }
+ }
}
return NULL;
}
ap_get_module_config(parms->server->module_config, &proxy_module);
if (arg[0] != '.')
- return "ProxyDomain: domain name must start with a dot.";
+ return "ProxyDomain: domain name must start with a dot.";
psf->domain = arg;
return NULL;
}
-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 *
set_recv_buffer_size(cmd_parms *parms, void *dummy, char *arg)
{
ap_get_module_config(parms->server->module_config, &proxy_module);
int s = atoi(arg);
if (s < 512 && s != 0) {
- return "ProxyReceiveBufferSize must be >= 512 bytes, or 0 for system default.";
+ return "ProxyReceiveBufferSize must be >= 512 bytes, or 0 for system default.";
}
psf->recv_buffer_size = s;
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*
set_via_opt(cmd_parms *parms, void *dummy, char *arg)
{
- proxy_server_conf *psf =
- ap_get_module_config(parms->server->module_config, &proxy_module);
+ proxy_server_conf *psf = ap_get_module_config(parms->server->module_config, &proxy_module);
if (strcasecmp(arg, "Off") == 0)
psf->viaopt = via_off;
else if (strcasecmp(arg, "Full") == 0)
psf->viaopt = via_full;
else {
- return "ProxyVia must be one of: "
+ return "ProxyVia must be one of: "
"off | on | full | block";
}
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[] =
{
{"proxy-server", proxy_handler},
"The default intranet domain name (in absence of a domain in the URL)"},
{"AllowCONNECT", set_allowed_ports, NULL, RSRC_CONF, ITERATE,
"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,
"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}
};
+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 =
{
- STANDARD_MODULE_STUFF,
- proxy_init, /* initializer */
- NULL, /* create per-directory config structure */
- NULL, /* merge per-directory config structures */
- create_proxy_config, /* create per-server config structure */
- NULL, /* merge per-server config structures */
- proxy_cmds, /* command ap_table_t */
- proxy_handlers, /* handlers */
- proxy_trans, /* translate_handler */
- 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 */
+ STANDARD20_MODULE_STUFF,
+ NULL, /* create per-directory config structure */
+ NULL, /* merge per-directory config structures */
+ create_proxy_config, /* create per-server config structure */
+ NULL, /* merge per-server config structures */
+ proxy_cmds, /* command ap_table_t */
+ proxy_handlers, /* handlers */
+ register_hooks
};
Things to do:
- 1. Make it garbage collect in the background, not while someone is waiting for
- a response!
+ 1. Make it garbage collect in the background, not while someone is
+ waiting for a response!
2. Check the logic thoroughly.
- 3. Empty directories are only removed the next time round (but this does avoid
- two passes). Consider doing them the first time round.
+ 3. Empty directories are only removed the next time round (but this does
+ avoid two passes). Consider doing them the first time round.
Ben Laurie <ben@algroup.co.uk> 30 Mar 96
*/
-#define TESTING 0
+#define TESTING 0
#undef EXPLAIN
#include "httpd.h"
#include "http_config.h"
#include "http_protocol.h"
+#include "ap_cache.h"
#include "explain.h"
enc_path, enc_search, enc_user, enc_fpath, enc_parm
};
-#define HDR_APP (0) /* append header, for proxy_add_header() */
-#define HDR_REP (1) /* replace 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() */
-/* number of characters in the hash */
-#define HASH_LEN (22*2)
+#ifdef CHARSET_EBCDIC
+#define CRLF "\r\n"
+#else /*CHARSET_EBCDIC*/
+#define CRLF "\015\012"
+#endif /*CHARSET_EBCDIC*/
-/* maximum 'CacheDirLevels*CacheDirLength' value */
-#define CACHEFILE_LEN 20 /* must be less than HASH_LEN/2 */
-
-#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_PORT 21
-#define DEFAULT_GOPHER_PORT 70
-#define DEFAULT_NNTP_PORT 119
-#define DEFAULT_WAIS_PORT 210
-#define DEFAULT_HTTPS_PORT 443
-#define DEFAULT_SNEWS_PORT 563
-#define DEFAULT_PROSPERO_PORT 1525 /* WARNING: conflict w/Oracle */
+#define DEFAULT_FTP_DATA_PORT 20
+#define DEFAULT_FTP_PORT 21
+#define DEFAULT_GOPHER_PORT 70
+#define DEFAULT_NNTP_PORT 119
+#define DEFAULT_WAIS_PORT 210
+#define DEFAULT_HTTPS_PORT 443
+#define DEFAULT_SNEWS_PORT 563
+#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 */
struct proxy_services {
const char *scheme;
/* static information about a remote proxy */
struct proxy_remote {
- const char *scheme; /* the schemes handled by this proxy, or '*' */
- const char *protocol; /* the scheme used to talk to this proxy */
- const char *hostname; /* the hostname of this proxy */
- int port; /* the port for this proxy */
+ const char *scheme; /* the schemes handled by this proxy, or '*' */
+ const char *protocol; /* the scheme used to talk to this proxy */
+ const char *hostname; /* the hostname of this proxy */
+ int port; /* the port for this proxy */
};
struct proxy_alias {
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 {
- struct cache_conf cache; /* cache configuration */
ap_array_header_t *proxies;
ap_array_header_t *aliases;
ap_array_header_t *raliases;
ap_array_header_t *dirconn;
ap_array_header_t *nocaches;
ap_array_header_t *allowed_connect_ports;
- char *domain; /* domain name to use in absence of a domain name in the request */
- int req; /* true if proxy requests are enabled */
+ char *domain; /* domain name to use in absence of
+ a domain name in the request */
+ int req; /* true if proxy requests are enabled */
+ float cache_completion; /* Force cache completion after this point */
enum {
via_off,
via_on,
via_full
} viaopt; /* how to deal with proxy Via: headers */
size_t recv_buffer_size;
+ ap_cache_handle_t *cache;
} proxy_server_conf;
-struct hdr_entry {
- const char *field;
- const char *value;
-};
-
-/* caching information about a request */
typedef struct {
- request_rec *req; /* the request */
- char *url; /* the URL requested */
- char *filename; /* name of the cache file, or NULL if no cache */
- 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;
-};
+ float cache_completion; /* completion percentage */
+ int content_length; /* length of the content */
+} proxy_completion;
/* 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 */
-int ap_proxy_connect_handler(request_rec *r, cache_req *c, char *url,
- const char *proxyhost, int proxyport);
+int ap_proxy_connect_handler(request_rec *r, ap_cache_el *c, char *url,
+ const char *proxyhost, int proxyport);
/* proxy_ftp.c */
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 */
int ap_proxy_http_canon(request_rec *r, char *url, const char *scheme,
- int def_port);
-int ap_proxy_http_handler(request_rec *r, cache_req *c, char *url,
- const char *proxyhost, int proxyport);
+ int def_port);
+int ap_proxy_http_handler(request_rec *r, ap_cache_el *c, char *url,
+ const char *proxyhost, int proxyport);
/* proxy_util.c */
int ap_proxy_hex2c(const char *x);
void ap_proxy_c2hex(int ch, char *x);
char *ap_proxy_canonenc(ap_pool_t *p, const char *x, int len, enum enctype t,
- int isenc);
+ int isenc);
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);
-table *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);
+ap_table_t *ap_proxy_read_headers(request_rec *r, char *buffer, int size, BUFF *f);
+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);
int ap_proxy_liststr(const char *list, const char *val);
void ap_proxy_hash(const char *it, char *val, int ndepth, int nlength);
int ap_proxy_hex2sec(const char *x);
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);
+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_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_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 *);
/* 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);
-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*/
#include "mod_proxy.h"
#include "http_log.h"
#include "http_main.h"
+#include "iol_socket.h"
#ifdef HAVE_BSTRING_H
-#include <bstring.h> /* for IRIX, FD_SET calls bzero() */
+#include <bstring.h> /* for IRIX, FD_SET calls bzero() */
#endif
-DEF_Explain
-
/*
* This handles Netscape CONNECT method secure proxy requests.
* A connection is opened to the specified host and data is
int *list = (int *) conf->allowed_connect_ports->elts;
for(i = 0; i < conf->allowed_connect_ports->nelts; i++) {
- if(port == list[i])
- return 1;
+ if(port == list[i])
+ return 1;
}
return 0;
}
-int ap_proxy_connect_handler(request_rec *r, cache_req *c, char *url,
- const char *proxyhost, int proxyport)
+int ap_proxy_connect_handler(request_rec *r, ap_cache_el *c, char *url,
+ const char *proxyhost, int proxyport)
{
- struct sockaddr_in server;
struct in_addr destaddr;
- struct hostent server_hp;
const char *host, *err;
char *p;
- int port, sock;
+ int port;
+ ap_socket_t *sock;
char buffer[HUGE_STRING_LEN];
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;
proxy_server_conf *conf =
(proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
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 */
-
host = url;
p = strchr(url, ':');
if (p == NULL)
- port = DEFAULT_HTTPS_PORT;
+ port = DEFAULT_HTTPS_PORT;
else {
- port = atoi(p + 1);
- *p = '\0';
+ port = atoi(p + 1);
+ *p = '\0';
}
/* check if ProxyBlock directive on this host */
destaddr.s_addr = ap_inet_addr(host);
for (i = 0; i < conf->noproxies->nelts; i++) {
- if ((npent[i].name != NULL && strstr(host, npent[i].name) != NULL)
- || destaddr.s_addr == npent[i].addr.s_addr || npent[i].name[0] == '*')
- return ap_proxyerror(r, HTTP_FORBIDDEN,
- "Connect to remote machine blocked");
+ if ((npent[i].name != NULL && strstr(host, npent[i].name) != NULL)
+ || destaddr.s_addr == npent[i].addr.s_addr || npent[i].name[0] == '*')
+ return ap_proxyerror(r, HTTP_FORBIDDEN,
+ "Connect to remote machine blocked");
}
/* Check if it is an allowed port */
if (conf->allowed_connect_ports->nelts == 0) {
- /* Default setting if not overridden by AllowCONNECT */
- switch (port) {
- case DEFAULT_HTTPS_PORT:
- case DEFAULT_SNEWS_PORT:
- break;
- default:
- return HTTP_FORBIDDEN;
- }
+ /* Default setting if not overridden by AllowCONNECT */
+ switch (port) {
+ case DEFAULT_HTTPS_PORT:
+ case DEFAULT_SNEWS_PORT:
+ break;
+ default:
+ return HTTP_FORBIDDEN;
+ }
} else if(!allowed_port(conf, port))
- return HTTP_FORBIDDEN;
+ return HTTP_FORBIDDEN;
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 {
- Explain2("CONNECT to %s on port %d", host, port);
- }
-
- server.sin_port = (proxyport ? htons(proxyport) : htons(port));
- err = ap_proxy_host2addr(proxyhost ? proxyhost : host, &server_hp);
-
- 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");
- return HTTP_INTERNAL_SERVER_ERROR;
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
+ "CONNECT to %s on port %d", host, port);
}
-#ifdef CHECK_FD_SETSIZE
- if (sock >= FD_SETSIZE) {
- ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, NULL,
- "proxy_connect_handler: filedescriptor (%u) "
- "larger than FD_SETSIZE (%u) "
- "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;
+ if ((ap_create_tcp_socket(&sock, r->pool)) != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "proxy: error creating socket");
+ 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 (ap_proxy_doconnect(sock, (char *)(proxyhost ? proxyhost : host), proxyport ? proxyport : port, r) == -1) {
+ ap_close_socket(sock);
+ return ap_proxyerror(r, HTTP_INTERNAL_SERVER_ERROR,
+ ap_pstrcat(r->pool, "Could not connect to remote machine:<br>",
+ strerror(errno), NULL));
}
/* If we are connecting through a remote proxy, we need to pass
* the CONNECT request on to it.
*/
if (proxyport) {
- /* FIXME: We should not be calling write() directly, but we currently
- * have no alternative. Error checking ignored. Also, we force
- * a HTTP/1.0 request to keep things simple.
- */
- Explain0("Sending the CONNECT request to the remote proxy");
- ap_snprintf(buffer, sizeof(buffer), "CONNECT %s HTTP/1.0" CRLF,
- r->uri);
- write(sock, buffer, strlen(buffer));
- ap_snprintf(buffer, sizeof(buffer),
- "Proxy-agent: %s" CRLF CRLF, ap_get_server_version());
- write(sock, buffer, strlen(buffer));
+ /* FIXME: We should not be calling write() directly, but we currently
+ * have no alternative. Error checking ignored. Also, we force
+ * a HTTP/1.0 request to keep things simple.
+ */
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
+ "Sending the CONNECT request to the remote proxy");
+ nbytes = ap_snprintf(buffer, sizeof(buffer), "CONNECT %s HTTP/1.0" CRLF, r->uri);
+ ap_send(sock, buffer, &nbytes);
+ nbytes = ap_snprintf(buffer, sizeof(buffer),"Proxy-agent: %s" CRLF CRLF, ap_get_server_version());
+ ap_send(sock, buffer, &nbytes);
}
else {
- Explain0("Returning 200 OK Status");
- ap_rvputs(r, "HTTP/1.0 200 Connection established" CRLF, NULL);
- ap_rvputs(r, "Proxy-agent: ", ap_get_server_version(), CRLF CRLF, NULL);
- ap_bflush(r->connection->client);
+ 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, "Proxy-agent: ", ap_get_server_version(), CRLF CRLF, NULL);
+ ap_bflush(r->connection->client);
}
- while (1) { /* Infinite loop until error (one side closes the connection) */
- FD_ZERO(&fds);
- FD_SET(sock, &fds);
- FD_SET(r->connection->client->fd, &fds);
+ sock_buff = ap_bcreate(r->pool, B_RDWR);
+ ap_bpush_iol(sock_buff, unix_attach_socket(sock));
- Explain0("Going to sleep (select)");
- i = ap_select((r->connection->client->fd > sock ?
- r->connection->client->fd + 1 :
- sock + 1), &fds, NULL, NULL, NULL);
- Explain1("Woke from select(), i=%d", i);
+ 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;
+ }
- if (i) {
- if (FD_ISSET(sock, &fds)) {
- Explain0("sock was set");
- if ((nbytes = read(sock, buffer, HUGE_STRING_LEN)) != 0) {
- if (nbytes == -1)
- break;
- if (write(r->connection->client->fd, buffer, nbytes) == EOF)
- break;
- Explain1("Wrote %d bytes to client", nbytes);
- }
- else
- break;
- }
- 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
- break;
+ /* 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) */
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL, "Going to sleep (poll)");
+ if(ap_poll(pollfd, &pollcnt, -1) != APR_SUCCESS)
+ {
+ 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);
+
+ if (pollcnt) {
+ ap_get_revents(&pollevent, sock, pollfd);
+ if (pollevent & APR_POLLIN) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
+ "sock was set");
+ if(ap_bread(sock_buff, buffer, HUGE_STRING_LEN, &nbytes) == APR_SUCCESS) {
+ int o = 0;
+ while(nbytes)
+ {
+ ap_bwrite(r->connection->client, buffer + o, nbytes, &i);
+ o += i;
+ nbytes -= i;
+ }
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
+ "Wrote %d bytes to client", nbytes);
+ }
+ else
+ 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;
}
#include "http_main.h"
#include "http_log.h"
#include "http_core.h"
+#include "iol_socket.h"
#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
int i, j, ch;
if (x[0] == '\0')
- return 0; /* special case for no characters */
+ return 0; /* special case for no characters */
for (i = 0, j = 0; x[i] != '\0'; i++, j++) {
/* decode it if not already done */
- ch = x[i];
- if (ch == '%' && ap_isxdigit(x[i + 1]) && ap_isxdigit(x[i + 2])) {
- ch = ap_proxy_hex2c(&x[i + 1]);
- i += 2;
- }
- x[j] = ch;
+ ch = x[i];
+ if (ch == '%' && ap_isxdigit(x[i + 1]) && ap_isxdigit(x[i + 2])) {
+ ch = ap_proxy_hex2c(&x[i + 1]);
+ i += 2;
+ }
+ x[j] = ch;
}
x[j] = '\0';
return j;
int i, ch;
for (i = 0; x[i] != '\0'; i++) {
- ch = x[i];
- if (ch == '%' && ap_isxdigit(x[i + 1]) && ap_isxdigit(x[i + 2])) {
- ch = ap_proxy_hex2c(&x[i + 1]);
- i += 2;
- }
+ ch = x[i];
+ if (ch == '%' && ap_isxdigit(x[i + 1]) && ap_isxdigit(x[i + 2])) {
+ ch = ap_proxy_hex2c(&x[i + 1]);
+ i += 2;
+ }
#ifndef CHARSET_EBCDIC
- if (ch == '\015' || ch == '\012' || (ch & 0x80))
+ if (ch == '\015' || ch == '\012' || (ch & 0x80))
#else /*CHARSET_EBCDIC*/
- if (ch == '\r' || ch == '\n' || (os_toascii[ch] & 0x80))
+ if (ch == '\r' || ch == '\n' || (os_toascii[ch] & 0x80))
#endif /*CHARSET_EBCDIC*/
- return 0;
+ return 0;
}
return 1;
}
port = DEFAULT_FTP_PORT;
err = ap_proxy_canon_netloc(p, &url, &user, &password, &host, &port);
if (err)
- return HTTP_BAD_REQUEST;
+ return HTTP_BAD_REQUEST;
if (user != NULL && !ftp_check_string(user))
- return HTTP_BAD_REQUEST;
+ return HTTP_BAD_REQUEST;
if (password != NULL && !ftp_check_string(password))
- return HTTP_BAD_REQUEST;
+ return HTTP_BAD_REQUEST;
/* now parse path/parameters args, according to rfc1738 */
/* N.B. if this isn't a true proxy request, then the URL path
*/
strp = strchr(url, ';');
if (strp != NULL) {
- *(strp++) = '\0';
- parms = ap_proxy_canonenc(p, strp, strlen(strp), enc_parm, r->proxyreq);
- if (parms == NULL)
- return HTTP_BAD_REQUEST;
+ *(strp++) = '\0';
+ parms = ap_proxy_canonenc(p, strp, strlen(strp), enc_parm, r->proxyreq);
+ if (parms == NULL)
+ return HTTP_BAD_REQUEST;
}
else
- parms = "";
+ parms = "";
path = ap_proxy_canonenc(p, url, strlen(url), enc_path, r->proxyreq);
if (path == NULL)
- return HTTP_BAD_REQUEST;
+ return HTTP_BAD_REQUEST;
if (!ftp_check_string(path))
- return HTTP_BAD_REQUEST;
+ return HTTP_BAD_REQUEST;
if (!r->proxyreq && r->args != NULL) {
- if (strp != NULL) {
- strp = ap_proxy_canonenc(p, r->args, strlen(r->args), enc_parm, 1);
- if (strp == NULL)
- return HTTP_BAD_REQUEST;
- parms = ap_pstrcat(p, parms, "?", strp, NULL);
- }
- else {
- strp = ap_proxy_canonenc(p, r->args, strlen(r->args), enc_fpath, 1);
- if (strp == NULL)
- return HTTP_BAD_REQUEST;
- path = ap_pstrcat(p, path, "?", strp, NULL);
- }
- r->args = NULL;
+ if (strp != NULL) {
+ strp = ap_proxy_canonenc(p, r->args, strlen(r->args), enc_parm, 1);
+ if (strp == NULL)
+ return HTTP_BAD_REQUEST;
+ parms = ap_pstrcat(p, parms, "?", strp, NULL);
+ }
+ else {
+ strp = ap_proxy_canonenc(p, r->args, strlen(r->args), enc_fpath, 1);
+ if (strp == NULL)
+ return HTTP_BAD_REQUEST;
+ path = ap_pstrcat(p, path, "?", strp, NULL);
+ }
+ r->args = NULL;
}
/* now, rebuild URL */
if (port != DEFAULT_FTP_PORT)
- ap_snprintf(sport, sizeof(sport), ":%d", port);
+ ap_snprintf(sport, sizeof(sport), ":%d", port);
else
- sport[0] = '\0';
+ sport[0] = '\0';
r->filename = ap_pstrcat(p, "proxy:ftp://", (user != NULL) ? user : "",
- (password != NULL) ? ":" : "",
- (password != NULL) ? password : "",
- (user != NULL) ? "@" : "", host, sport, "/", path,
- (parms[0] != '\0') ? ";" : "", parms, NULL);
+ (password != NULL) ? ":" : "",
+ (password != NULL) ? password : "",
+ (user != NULL) ? "@" : "", host, sport, "/", path,
+ (parms[0] != '\0') ? ";" : "", parms, NULL);
return OK;
}
len = ap_bgets(linebuff, sizeof linebuff, f);
if (len == -1)
- return -1;
+ return -1;
/* check format */
if (len < 5 || !ap_isdigit(linebuff[0]) || !ap_isdigit(linebuff[1]) ||
- !ap_isdigit(linebuff[2]) || (linebuff[3] != ' ' && linebuff[3] != '-'))
- status = 0;
+ !ap_isdigit(linebuff[2]) || (linebuff[3] != ' ' && linebuff[3] != '-'))
+ status = 0;
else
- 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') {
- (void)ap_bskiplf(f);
+ skiplf(f);
}
/* skip continuation lines */
if (linebuff[3] == '-') {
- memcpy(buff, linebuff, 3);
- buff[3] = ' ';
- do {
- len = ap_bgets(linebuff, sizeof linebuff, f);
- if (len == -1)
- return -1;
- if (linebuff[len - 1] != '\n') {
- (void)ap_bskiplf(f);
- }
- } while (memcmp(linebuff, buff, 4) != 0);
+ memcpy(buff, linebuff, 3);
+ buff[3] = ' ';
+ do {
+ len = ap_bgets(linebuff, sizeof linebuff, f);
+ if (len == -1)
+ return -1;
+ if (linebuff[len - 1] != '\n') {
+ skiplf(f);
+ }
+ } while (memcmp(linebuff, buff, 4) != 0);
}
return status;
int len, status;
char linebuff[100], buff[5];
char *mb = msgbuf,
- *me = &msgbuf[msglen];
+ *me = &msgbuf[msglen];
len = ap_bgets(linebuff, sizeof linebuff, f);
if (len == -1)
- return -1;
+ return -1;
if (len < 5 || !ap_isdigit(linebuff[0]) || !ap_isdigit(linebuff[1]) ||
- !ap_isdigit(linebuff[2]) || (linebuff[3] != ' ' && linebuff[3] != '-'))
- status = 0;
+ !ap_isdigit(linebuff[2]) || (linebuff[3] != ' ' && linebuff[3] != '-'))
+ status = 0;
else
- status = 100 * linebuff[0] + 10 * linebuff[1] + linebuff[2] - 111 * '0';
+ status = 100 * linebuff[0] + 10 * linebuff[1] + linebuff[2] - 111 * '0';
mb = ap_cpystrn(mb, linebuff+4, me - mb);
if (linebuff[len - 1] != '\n')
- (void)ap_bskiplf(f);
+ skiplf(f);
if (linebuff[3] == '-') {
- memcpy(buff, linebuff, 3);
- buff[3] = ' ';
- do {
- len = ap_bgets(linebuff, sizeof linebuff, f);
- if (len == -1)
- return -1;
- if (linebuff[len - 1] != '\n') {
- (void)ap_bskiplf(f);
- }
- mb = ap_cpystrn(mb, linebuff+4, me - mb);
- } while (memcmp(linebuff, buff, 4) != 0);
+ memcpy(buff, linebuff, 3);
+ buff[3] = ' ';
+ do {
+ len = ap_bgets(linebuff, sizeof linebuff, f);
+ if (len == -1)
+ return -1;
+ if (linebuff[len - 1] != '\n') {
+ skiplf(f);
+ }
+ mb = ap_cpystrn(mb, linebuff+4, me - mb);
+ } while (memcmp(linebuff, buff, 4) != 0);
}
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 buf2[IOBUFSIZE];
int searchidx = 0;
char *searchptr = NULL;
int firstfile = 1;
+ ap_ssize_t cntr;
unsigned long total_bytes_sent = 0;
register int n, o, w;
conn_rec *con = r->connection;
char *dir, *path, *reldir, *site;
+ BUFF *cachefp = NULL;
+ if(c) ap_cache_el_data(c, &cachefp);
+
/* Save "scheme://site" prefix without password */
site = ap_unparse_uri_components(r->pool, &r->parsed_uri, UNP_OMITPASSWORD|UNP_OMITPATHINFO);
/* ... and path without query args */
/* Copy path, strip (all except the last) trailing slashes */
path = dir = ap_pstrcat(r->pool, path, "/", NULL);
while ((n = strlen(path)) > 1 && path[n-1] == '/' && path[n-2] == '/')
- path[n-1] = '\0';
+ path[n-1] = '\0';
/* print "ftp://host/" */
n = ap_snprintf(buf, sizeof(buf), DOCTYPE_HTML_3_2
- "<HTML><HEAD><TITLE>%s%s</TITLE>\n"
- "<BASE HREF=\"%s%s\"></HEAD>\n"
- "<BODY><H2>Directory of "
- "<A HREF=\"/\">%s</A>/",
- site, path, site, path, site);
+ "<HTML><HEAD><TITLE>%s%s</TITLE>\n"
+ "<BASE HREF=\"%s%s\"></HEAD>\n"
+ "<BODY><H2>Directory of "
+ "<A HREF=\"/\">%s</A>/",
+ site, path, site, path, site);
total_bytes_sent += ap_proxy_bputs2(buf, con->client, c);
while ((dir = strchr(dir+1, '/')) != NULL)
{
- *dir = '\0';
- if ((reldir = strrchr(path+1, '/'))==NULL)
- reldir = path+1;
- else
- ++reldir;
- /* print "path/" component */
- ap_snprintf(buf, sizeof(buf), "<A HREF=\"/%s/\">%s</A>/", path+1, reldir);
- total_bytes_sent += ap_proxy_bputs2(buf, con->client, c);
- *dir = '/';
+ *dir = '\0';
+ if ((reldir = strrchr(path+1, '/'))==NULL)
+ reldir = path+1;
+ else
+ ++reldir;
+ /* print "path/" component */
+ ap_snprintf(buf, sizeof(buf), "<A HREF=\"/%s/\">%s</A>/", path+1, reldir);
+ total_bytes_sent += ap_proxy_bputs2(buf, con->client, c);
+ *dir = '/';
}
/* If the caller has determined the current directory, and it differs */
/* from what the client requested, then show the real name */
if (cwd == NULL || strncmp (cwd, path, strlen(cwd)) == 0) {
- ap_snprintf(buf, sizeof(buf), "</H2>\n<HR><PRE>");
+ ap_snprintf(buf, sizeof(buf), "</H2>\n<HR><PRE>");
} else {
- ap_snprintf(buf, sizeof(buf), "</H2>\n(%s)\n<HR><PRE>", cwd);
+ ap_snprintf(buf, sizeof(buf), "</H2>\n(%s)\n<HR><PRE>", cwd);
}
total_bytes_sent += ap_proxy_bputs2(buf, con->client, c);
while (!con->aborted) {
- n = ap_bgets(buf, sizeof buf, f);
- if (n == -1) { /* input error */
- if (c != NULL) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
- "proxy: error reading from %s", c->url);
- c = ap_proxy_cache_error(c);
- }
- break;
- }
- if (n == 0)
- break; /* EOF */
- if (buf[0] == 'l' && (filename=strstr(buf, " -> ")) != NULL) {
- char *link_ptr = filename;
-
- do {
- filename--;
- } while (filename[0] != ' ');
- *(filename++) = '\0';
- *(link_ptr++) = '\0';
- if ((n = strlen(link_ptr)) > 1 && link_ptr[n - 1] == '\n')
- link_ptr[n - 1] = '\0';
- ap_snprintf(buf2, sizeof(buf2), "%s <A HREF=\"%s\">%s %s</A>\n", buf, filename, filename, link_ptr);
- ap_cpystrn(buf, buf2, sizeof(buf));
- n = strlen(buf);
- }
- else if (buf[0] == 'd' || buf[0] == '-' || buf[0] == 'l' || ap_isdigit(buf[0])) {
- if (ap_isdigit(buf[0])) { /* handle DOS dir */
- searchptr = strchr(buf, '<');
- if (searchptr != NULL)
- *searchptr = '[';
- searchptr = strchr(buf, '>');
- if (searchptr != NULL)
- *searchptr = ']';
- }
-
- filename = strrchr(buf, ' ');
- *(filename++) = 0;
- filename[strlen(filename) - 1] = 0;
-
- /* handle filenames with spaces in 'em */
- if (!strcmp(filename, ".") || !strcmp(filename, "..") || firstfile) {
- firstfile = 0;
- searchidx = filename - buf;
- }
- else if (searchidx != 0 && buf[searchidx] != 0) {
- *(--filename) = ' ';
- buf[searchidx - 1] = 0;
- filename = &buf[searchidx];
- }
-
- /* Special handling for '.' and '..' */
- if (!strcmp(filename, ".") || !strcmp(filename, "..") || buf[0] == 'd') {
- ap_snprintf(buf2, sizeof(buf2), "%s <A HREF=\"%s/\">%s</A>\n",
- buf, filename, filename);
- }
- else {
- ap_snprintf(buf2, sizeof(buf2), "%s <A HREF=\"%s\">%s</A>\n", buf, filename, filename);
- }
- ap_cpystrn(buf, buf2, sizeof(buf));
- n = strlen(buf);
- }
+ n = ap_bgets(buf, sizeof buf, f);
+ if (n == -1) { /* input error */
+ if (c != NULL) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "proxy: error reading from cache");
+ ap_proxy_cache_error(&c);
+ }
+ break;
+ }
+ if (n == 0)
+ break; /* EOF */
+ if (buf[0] == 'l' && (filename=strstr(buf, " -> ")) != NULL) {
+ char *link_ptr = filename;
+
+ do {
+ filename--;
+ } while (filename[0] != ' ');
+ *(filename++) = '\0';
+ *(link_ptr++) = '\0';
+ if ((n = strlen(link_ptr)) > 1 && link_ptr[n - 1] == '\n')
+ link_ptr[n - 1] = '\0';
+ ap_snprintf(buf2, sizeof(buf2), "%s <A HREF=\"%s\">%s %s</A>\n", buf, filename, filename, link_ptr);
+ ap_cpystrn(buf, buf2, sizeof(buf));
+ n = strlen(buf);
+ }
+ else if (buf[0] == 'd' || buf[0] == '-' || buf[0] == 'l' || ap_isdigit(buf[0])) {
+ if (ap_isdigit(buf[0])) { /* handle DOS dir */
+ searchptr = strchr(buf, '<');
+ if (searchptr != NULL)
+ *searchptr = '[';
+ searchptr = strchr(buf, '>');
+ if (searchptr != NULL)
+ *searchptr = ']';
+ }
+
+ filename = strrchr(buf, ' ');
+ *(filename++) = 0;
+ filename[strlen(filename) - 1] = 0;
+
+ /* handle filenames with spaces in 'em */
+ if (!strcmp(filename, ".") || !strcmp(filename, "..") || firstfile) {
+ firstfile = 0;
+ searchidx = filename - buf;
+ }
+ else if (searchidx != 0 && buf[searchidx] != 0) {
+ *(--filename) = ' ';
+ buf[searchidx - 1] = 0;
+ filename = &buf[searchidx];
+ }
+
+ /* Special handling for '.' and '..' */
+ if (!strcmp(filename, ".") || !strcmp(filename, "..") || buf[0] == 'd') {
+ ap_snprintf(buf2, sizeof(buf2), "%s <A HREF=\"%s/\">%s</A>\n",
+ buf, filename, filename);
+ }
+ else {
+ ap_snprintf(buf2, sizeof(buf2), "%s <A HREF=\"%s\">%s</A>\n", buf, filename, filename);
+ }
+ ap_cpystrn(buf, buf2, sizeof(buf));
+ n = strlen(buf);
+ }
- o = 0;
- total_bytes_sent += n;
+ o = 0;
+ total_bytes_sent += n;
- if (c != NULL && c->fp && ap_bwrite(c->fp, buf, n) != n) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
- "proxy: error writing to %s", c->tempfile);
- c = ap_proxy_cache_error(c);
- }
+ if (cachefp && ap_bwrite(cachefp, buf, n, &cntr) != n) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "proxy: error writing to cache");
+ ap_proxy_cache_error(&c);
+ cachefp = NULL;
+ }
- while (n && !r->connection->aborted) {
- w = ap_bwrite(con->client, &buf[o], n);
- if (w <= 0)
- break;
- n -= w;
- o += w;
- }
+ while (n && !r->connection->aborted) {
+ w = ap_bwrite(con->client, &buf[o], n, &cntr);
+ if (w <= 0)
+ break;
+ n -= w;
+ o += w;
+ }
}
total_bytes_sent += ap_proxy_bputs2("</PRE><HR>\n", con->client, c);
* (log username/password guessing attempts)
*/
if (log_it)
- ap_log_rerror(APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, r,
- "proxy: missing or failed auth to %s",
- ap_unparse_uri_components(r->pool,
- &r->parsed_uri, UNP_OMITPATHINFO));
+ ap_log_rerror(APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, 0, r,
+ "proxy: missing or failed auth to %s",
+ ap_unparse_uri_components(r->pool,
+ &r->parsed_uri, UNP_OMITPATHINFO));
ap_table_setn(r->err_headers_out, "WWW-Authenticate",
ap_pstrcat(r->pool, "Basic realm=\"",
- ap_unparse_uri_components(r->pool, &r->parsed_uri,
- UNP_OMITPASSWORD|UNP_OMITPATHINFO),
- "\"", NULL));
+ ap_unparse_uri_components(r->pool, &r->parsed_uri,
+ UNP_OMITPASSWORD|UNP_OMITPATHINFO),
+ "\"", NULL));
return HTTP_UNAUTHORIZED;
}
* Troy Morrison <spiffnet@zoom.com>
* 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 *user = NULL;
/* char *account = NULL; how to supply an account in a URL? */
const char *password = NULL;
const char *err;
- int port, i, j, len, sock, dsock, rc, nocache = 0;
- int csd = 0;
- struct sockaddr_in server;
- struct hostent server_hp;
+ ap_socket_t *sock, *dsock, *inc;
+ int port, i, j, len, rc, nocache = 0;
+ ap_socket_t *csd;
struct in_addr destaddr;
- ap_table_t *resp_hdrs;
- BUFF *f;
+ BUFF *f, *cachefp = NULL;
BUFF *data = NULL;
ap_pool_t *p = r->pool;
int one = 1;
const long int zero = 0L;
- NET_SIZE_T clen;
- struct tbl_do_args tdo;
-
+ ap_table_t *resp_hdrs;
+
void *sconf = r->server->module_config;
proxy_server_conf *conf =
(proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
struct sockaddr_in data_addr;
int pasvmode = 0;
char pasv[64];
- char *pstr;
+ char *pstr, dates[AP_RFC822_DATE_LEN];
+ char *npaddr;
+ ap_uint32_t npport;
+
/* stuff for responses */
char resp[MAX_STRING_LEN];
char *size = NULL;
/* we only support GET and HEAD */
if (r->method_number != M_GET)
- return HTTP_NOT_IMPLEMENTED;
+ return HTTP_NOT_IMPLEMENTED;
/* We break the URL into host, port, path-search */
host = r->parsed_uri.hostname;
port = (r->parsed_uri.port != 0)
- ? r->parsed_uri.port
- : ap_default_port_for_request(r);
+ ? r->parsed_uri.port
+ : ap_default_port_for_request(r);
path = ap_pstrdup(p, r->parsed_uri.path);
path = (path != NULL && path[0] != '\0') ? &path[1] : "";
* But chances are still smaller that the URL is logged regularly.
*/
if ((password = ap_table_get(r->headers_in, "Authorization")) != NULL
- && strcasecmp(ap_getword(r->pool, &password, ' '), "Basic") == 0
- && (password = ap_pbase64decode(r->pool, password))[0] != ':') {
- /* Note that this allocation has to be made from r->connection->pool
- * because it has the lifetime of the connection. The other allocations
- * are temporary and can be tossed away any time.
- */
- user = ap_getword_nulls (r->pool, &password, ':');
- r->ap_auth_type = "Basic";
- r->user = r->parsed_uri.user = user;
- nocache = 1; /* This resource only accessible with username/password */
+ && strcasecmp(ap_getword(r->pool, &password, ' '), "Basic") == 0
+ && (password = ap_pbase64decode(r->pool, password))[0] != ':') {
+ /* Note that this allocation has to be made from r->connection->pool
+ * because it has the lifetime of the connection. The other allocations
+ * are temporary and can be tossed away any time.
+ */
+ user = ap_getword_nulls (r->pool, &password, ':');
+ r->ap_auth_type = "Basic";
+ r->user = r->parsed_uri.user = user;
+ nocache = 1; /* This resource only accessible with username/password */
}
else if ((user = r->parsed_uri.user) != NULL) {
- user = ap_pstrdup(p, user);
- decodeenc(user);
- if ((password = r->parsed_uri.password) != NULL) {
- char *tmp = ap_pstrdup(p, password);
- decodeenc(tmp);
- password = tmp;
- }
- nocache = 1; /* This resource only accessible with username/password */
+ user = ap_pstrdup(p, user);
+ decodeenc(user);
+ if ((password = r->parsed_uri.password) != NULL) {
+ char *tmp = ap_pstrdup(p, password);
+ decodeenc(tmp);
+ password = tmp;
+ }
+ nocache = 1; /* This resource only accessible with username/password */
}
else {
- user = "anonymous";
- password = "apache_proxy@";
+ user = "anonymous";
+ password = "apache_proxy@";
}
/* check if ProxyBlock directive on this host */
destaddr.s_addr = ap_inet_addr(host);
for (i = 0; i < conf->noproxies->nelts; i++) {
- if ((npent[i].name != NULL && strstr(host, npent[i].name) != NULL)
- || destaddr.s_addr == npent[i].addr.s_addr || npent[i].name[0] == '*')
- return ap_proxyerror(r, HTTP_FORBIDDEN,
- "Connect to remote machine blocked");
+ if ((npent[i].name != NULL && strstr(host, npent[i].name) != NULL)
+ || destaddr.s_addr == npent[i].addr.s_addr || npent[i].name[0] == '*')
+ return ap_proxyerror(r, HTTP_FORBIDDEN,
+ "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, ';');
if (parms != NULL)
- *(parms++) = '\0';
-
- memset(&server, 0, sizeof(struct sockaddr_in));
- server.sin_family = AF_INET;
- 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");
- return HTTP_INTERNAL_SERVER_ERROR;
- }
-
- if (conf->recv_buffer_size > 0
- && setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
- (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");
+ *(parms++) = '\0';
+
+ if ((ap_create_tcp_socket(&sock, r->pool)) != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "proxy: error creating socket");
+ return HTTP_INTERNAL_SERVER_ERROR;
}
- if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &one,
- sizeof(one)) == -1) {
+ if (conf->recv_buffer_size > 0 && ap_setsocketopt(sock, APR_SO_RCVBUF,conf->recv_buffer_size)) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "setsockopt(SO_RCVBUF): Failed to set ProxyReceiveBufferSize, using default");
+ }
+
+ if (ap_setsocketopt(sock, APR_SO_REUSEADDR, one)) {
#ifndef _OSD_POSIX /* BS2000 has this option "always on" */
- ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
- "proxy: error setting reuseaddr option: setsockopt(SO_REUSEADDR)");
- ap_pclosesocket(p, sock);
- return HTTP_INTERNAL_SERVER_ERROR;
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "proxy: error setting reuseaddr option: setsockopt(SO_REUSEADDR)");
+ ap_close_socket(sock);
+ return HTTP_INTERNAL_SERVER_ERROR;
#endif /*_OSD_POSIX*/
}
-#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) {
- 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));
+ if (ap_proxy_doconnect(sock, host, port, r) == -1) {
+ ap_close_socket(sock);
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+ ap_pstrcat(r->pool, "Could not connect to remote machine: ",
+ strerror(errno), NULL));
}
- f = ap_bcreate(p, B_RDWR | B_SOCKET);
- ap_bpushfd(f, sock);
+ f = ap_bcreate(p, B_RDWR);
+ ap_bpush_iol(f, unix_attach_socket(sock));
/* shouldn't we implement telnet control options here? */
#ifdef CHARSET_EBCDIC
/* 220 Service ready for new user. */
/* 421 Service not available, closing control connection. */
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) {
- return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY,
"Error reading from remote server");
}
#if 0
if (i == 120) {
- /* RFC2068 states:
- * 14.38 Retry-After
- *
- * The Retry-After response-header field can be used with a 503 (Service
- * Unavailable) response to indicate how long the service is expected to
- * be unavailable to the requesting client. The value of this field can
- * be either an HTTP-date or an integer number of seconds (in decimal)
- * after the time of the response.
- * Retry-After = "Retry-After" ":" ( HTTP-date | delta-seconds )
- */
- ap_set_header("Retry-After", ap_psprintf(p, "%u", 60*wait_mins);
- return ap_proxyerror(r, HTTP_SERVICE_UNAVAILABLE, resp);
+ /* RFC2068 states:
+ * 14.38 Retry-After
+ *
+ * The Retry-After response-header field can be used with a 503 (Service
+ * Unavailable) response to indicate how long the service is expected to
+ * be unavailable to the requesting client. The value of this field can
+ * be either an HTTP-date or an integer number of seconds (in decimal)
+ * after the time of the response.
+ * Retry-After = "Retry-After" ":" ( HTTP-date | delta-seconds )
+ */
+ ap_set_header("Retry-After", ap_psprintf(p, "%u", 60*wait_mins);
+ return ap_proxyerror(r, HTTP_SERVICE_UNAVAILABLE, resp);
}
#endif
if (i != 220) {
- 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_bflush(f); /* capture any errors */
- Explain1("FTP: USER %s", user);
+ ap_bflush(f); /* capture any errors */
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
+ "FTP: USER %s", user);
/* possible results; 230, 331, 332, 421, 500, 501, 530 */
/* states: 1 - error, 2 - success; 3 - send password, 4,5 fail */
/* 501 Syntax error in parameters or arguments. */
/* 530 Not logged in. */
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) {
- return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY,
"Error reading from remote server");
}
if (i == 530) {
- return ftp_unauthorized (r, 1); /* log it: user name guessing attempt? */
+ return ftp_unauthorized (r, 1); /* log it: user name guessing attempt? */
}
if (i != 230 && i != 331) {
- return HTTP_BAD_GATEWAY;
+ return HTTP_BAD_GATEWAY;
}
- if (i == 331) { /* send password */
- if (password == NULL) {
- return ftp_unauthorized (r, 0);
- }
- ap_bvputs(f, "PASS ", password, CRLF, NULL);
- ap_bflush(f);
- Explain1("FTP: PASS %s", password);
+ if (i == 331) { /* send password */
+ if (password == NULL) {
+ return ftp_unauthorized (r, 0);
+ }
+ ap_bvputs(f, "PASS ", password, CRLF, NULL);
+ ap_bflush(f);
+ 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 */
- /* 230 User logged in, proceed. */
- /* 332 Need account for login. */
- /* 421 Service not available, closing control connection. */
- /* 500 Syntax error, command unrecognized. */
- /* 501 Syntax error in parameters or arguments. */
- /* 503 Bad sequence of commands. */
- /* 530 Not logged in. */
- i = ftp_getrc(f);
- Explain1("FTP: returned status %d", i);
- if (i == -1) {
- return ap_proxyerror(r, HTTP_BAD_GATEWAY, "Error reading from remote server");
- }
- if (i == 332) {
- return ap_proxyerror(r, HTTP_UNAUTHORIZED, "Need account for login");
- }
- /* @@@ questionable -- we might as well return a 403 Forbidden here */
- if (i == 530) {
- return ftp_unauthorized (r, 1); /* log it: passwd guessing attempt? */
- }
- if (i != 230 && i != 202) {
- return HTTP_BAD_GATEWAY;
- }
+ /* 230 User logged in, proceed. */
+ /* 332 Need account for login. */
+ /* 421 Service not available, closing control connection. */
+ /* 500 Syntax error, command unrecognized. */
+ /* 501 Syntax error in parameters or arguments. */
+ /* 503 Bad sequence of commands. */
+ /* 530 Not logged in. */
+ i = ftp_getrc(f);
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
+ "FTP: returned status %d", i);
+ if (i == -1) {
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY, "Error reading from remote server");
+ }
+ if (i == 332) {
+ return ap_proxyerror(r, HTTP_UNAUTHORIZED, "Need account for login");
+ }
+ /* @@@ questionable -- we might as well return a 403 Forbidden here */
+ if (i == 530) {
+ return ftp_unauthorized (r, 1); /* log it: passwd guessing attempt? */
+ }
+ if (i != 230 && i != 202) {
+ return HTTP_BAD_GATEWAY;
+ }
}
/* set the directory (walk directory component by component):
* machine
*/
for (;;) {
- strp = strchr(path, '/');
- if (strp == NULL)
- break;
- *strp = '\0';
-
- len = decodeenc(path);
- ap_bvputs(f, "CWD ", path, CRLF, NULL);
- ap_bflush(f);
- Explain1("FTP: CWD %s", path);
- *strp = '/';
+ strp = strchr(path, '/');
+ if (strp == NULL)
+ break;
+ *strp = '\0';
+
+ len = decodeenc(path);
+ ap_bvputs(f, "CWD ", path, CRLF, NULL);
+ ap_bflush(f);
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
+ "FTP: CWD %s", path);
+ *strp = '/';
/* responses: 250, 421, 500, 501, 502, 530, 550 */
- /* 250 Requested file action okay, completed. */
- /* 421 Service not available, closing control connection. */
- /* 500 Syntax error, command unrecognized. */
- /* 501 Syntax error in parameters or arguments. */
- /* 502 Command not implemented. */
- /* 530 Not logged in. */
- /* 550 Requested action not taken. */
- i = ftp_getrc(f);
- Explain1("FTP: returned status %d", i);
- if (i == -1) {
- return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+ /* 250 Requested file action okay, completed. */
+ /* 421 Service not available, closing control connection. */
+ /* 500 Syntax error, command unrecognized. */
+ /* 501 Syntax error in parameters or arguments. */
+ /* 502 Command not implemented. */
+ /* 530 Not logged in. */
+ /* 550 Requested action not taken. */
+ i = ftp_getrc(f);
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
+ "FTP: returned status %d", i);
+ if (i == -1) {
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY,
"Error reading from remote server");
- }
- if (i == 550) {
- return HTTP_NOT_FOUND;
- }
- if (i != 250) {
- return HTTP_BAD_GATEWAY;
- }
-
- path = strp + 1;
+ }
+ if (i == 550) {
+ return HTTP_NOT_FOUND;
+ }
+ if (i != 250) {
+ return HTTP_BAD_GATEWAY;
+ }
+
+ path = strp + 1;
}
if (parms != NULL && strncmp(parms, "type=", 5) == 0) {
- parms += 5;
- if ((parms[0] != 'd' && parms[0] != 'a' && parms[0] != 'i') ||
- parms[1] != '\0')
- parms = "";
+ parms += 5;
+ if ((parms[0] != 'd' && parms[0] != 'a' && parms[0] != 'i') ||
+ parms[1] != '\0')
+ parms = "";
}
else
- parms = "";
+ parms = "";
/* changed to make binary transfers the default */
if (parms[0] != 'a') {
- /* set type to image */
- /* TM - Added \015\012 to the end of TYPE I, otherwise it hangs the
- connection */
- ap_bputs("TYPE I" CRLF, f);
- ap_bflush(f);
- Explain0("FTP: TYPE I");
+ /* set type to image */
+ /* TM - Added \015\012 to the end of TYPE I, otherwise it hangs the
+ connection */
+ ap_bputs("TYPE I" CRLF, f);
+ ap_bflush(f);
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
+ "FTP: TYPE I");
/* responses: 200, 421, 500, 501, 504, 530 */
/* 200 Command okay. */
/* 421 Service not available, closing control connection. */
/* 501 Syntax error in parameters or arguments. */
/* 504 Command not implemented for that parameter. */
/* 530 Not logged in. */
- i = ftp_getrc(f);
- Explain1("FTP: returned status %d", i);
- if (i == -1) {
- return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+ i = ftp_getrc(f);
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
+ "FTP: returned status %d", i);
+ if (i == -1) {
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY,
"Error reading from remote server");
- }
- if (i != 200 && i != 504) {
- return HTTP_BAD_GATEWAY;
- }
+ }
+ if (i != 200 && i != 504) {
+ return HTTP_BAD_GATEWAY;
+ }
/* Allow not implemented */
- if (i == 504)
- parms[0] = '\0';
+ if (i == 504)
+ parms[0] = '\0';
}
/* try to set up PASV data connection first */
- dsock = ap_psocket(p, PF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (dsock == -1) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
- "proxy: error creating PASV socket");
- ap_bclose(f);
- return HTTP_INTERNAL_SERVER_ERROR;
+ if ((ap_create_tcp_socket(&dsock, r->pool)) != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "proxy: error creating PASV socket");
+ ap_bclose(f);
+ return HTTP_INTERNAL_SERVER_ERROR;
}
- if (conf->recv_buffer_size) {
- if (setsockopt(dsock, SOL_SOCKET, SO_RCVBUF,
- (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");
- }
+ if (conf->recv_buffer_size > 0 && ap_setsocketopt(dsock, APR_SO_RCVBUF,conf->recv_buffer_size)) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "setsockopt(SO_RCVBUF): Failed to set ProxyReceiveBufferSize, using default");
}
ap_bputs("PASV" CRLF, 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 */
/* 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2). */
/* 421 Service not available, closing control connection. */
/* 530 Not logged in. */
i = ap_bgets(pasv, sizeof(pasv), f);
if (i == -1) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, r,
- "PASV: control connection is toast");
- ap_pclosesocket(p, dsock);
- ap_bclose(f);
- return HTTP_INTERNAL_SERVER_ERROR;
+ ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, r,
+ "PASV: control connection is toast");
+ ap_close_socket(dsock);
+ ap_bclose(f);
+ return HTTP_INTERNAL_SERVER_ERROR;
}
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';
pstr = strtok(pasv, " "); /* separate result code */
if (pstr != NULL) {
if (i == -1) {
char buf[120];
return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+>>>>>>> 1.8
ap_pstrcat(r->pool,
"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,
sizeof(buf)), NULL));
}
if (setsockopt(dsock, SOL_SOCKET, SO_REUSEADDR, (void *) &one,
sizeof(one)) == -1) {
+>>>>>>> 1.8
#ifndef _OSD_POSIX /* BS2000 has this option "always on" */
- ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
- "proxy: error setting reuseaddr option");
- ap_pclosesocket(p, dsock);
- ap_bclose(f);
- return HTTP_INTERNAL_SERVER_ERROR;
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "proxy: error setting reuseaddr option");
+ ap_close_socket(dsock);
+ ap_bclose(f);
+ return HTTP_INTERNAL_SERVER_ERROR;
#endif /*_OSD_POSIX*/
- }
-
- if (bind(dsock, (struct sockaddr *) &server,
- sizeof(struct sockaddr_in)) == -1) {
- char buff[22];
-
- ap_snprintf(buff, sizeof(buff), "%s:%d", inet_ntoa(server.sin_addr), server.sin_port);
- ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
- "proxy: error binding to ftp data socket %s", buff);
- ap_bclose(f);
- ap_pclosesocket(p, dsock);
- return HTTP_INTERNAL_SERVER_ERROR;
- }
- listen(dsock, 2); /* only need a short queue */
+ }
+
+ if (ap_bind(dsock) != APR_SUCCESS) {
+ char buff[22];
+
+ ap_snprintf(buff, sizeof(buff), "%s:%d", npaddr, npport);
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "proxy: error binding to ftp data socket %s", buff);
+ ap_bclose(f);
+ ap_close_socket(dsock);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+ ap_listen(dsock, 2); /* only need a short queue */
}
/* set request; "path" holds last path component */
/* TM - if len == 0 then it must be a directory (you can't RETR nothing) */
if (len == 0) {
- parms = "d";
+ parms = "d";
}
else {
- ap_bvputs(f, "SIZE ", path, CRLF, NULL);
- ap_bflush(f);
- Explain1("FTP: SIZE %s", path);
- i = ftp_getrc_msg(f, resp, sizeof resp);
- Explain2("FTP: returned status %d with response %s", i, resp);
- if (i != 500) { /* Size command not recognized */
- if (i == 550) { /* Not a regular file */
- Explain0("FTP: SIZE shows this is a directory");
- parms = "d";
- ap_bvputs(f, "CWD ", path, CRLF, NULL);
- ap_bflush(f);
- Explain1("FTP: CWD %s", path);
- i = ftp_getrc(f);
- /* possible results: 250, 421, 500, 501, 502, 530, 550 */
- /* 250 Requested file action okay, completed. */
- /* 421 Service not available, closing control connection. */
- /* 500 Syntax error, command unrecognized. */
- /* 501 Syntax error in parameters or arguments. */
- /* 502 Command not implemented. */
- /* 530 Not logged in. */
- /* 550 Requested action not taken. */
- Explain1("FTP: returned status %d", i);
- if (i == -1) {
- return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+ ap_bvputs(f, "SIZE ", path, CRLF, NULL);
+ ap_bflush(f);
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
+ "FTP: SIZE %s", path);
+ i = ftp_getrc_msg(f, resp, sizeof 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 == 550) { /* Not a regular file */
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
+ "FTP: SIZE shows this is a directory");
+ parms = "d";
+ ap_bvputs(f, "CWD ", path, CRLF, NULL);
+ ap_bflush(f);
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
+ "FTP: CWD %s", path);
+ i = ftp_getrc(f);
+ /* possible results: 250, 421, 500, 501, 502, 530, 550 */
+ /* 250 Requested file action okay, completed. */
+ /* 421 Service not available, closing control connection. */
+ /* 500 Syntax error, command unrecognized. */
+ /* 501 Syntax error in parameters or arguments. */
+ /* 502 Command not implemented. */
+ /* 530 Not logged in. */
+ /* 550 Requested action not taken. */
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
+ "FTP: returned status %d", i);
+ if (i == -1) {
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY,
"Error reading from remote server");
- }
- if (i == 550) {
- return HTTP_NOT_FOUND;
- }
- if (i != 250) {
- return HTTP_BAD_GATEWAY;
- }
- path = "";
- len = 0;
- }
- else if (i == 213) { /* Size command ok */
- for (j = 0; j < sizeof resp && ap_isdigit(resp[j]); j++)
- ;
- resp[j] = '\0';
- if (resp[0] != '\0')
- size = ap_pstrdup(p, resp);
- }
- }
+ }
+ if (i == 550) {
+ return HTTP_NOT_FOUND;
+ }
+ if (i != 250) {
+ return HTTP_BAD_GATEWAY;
+ }
+ path = "";
+ len = 0;
+ }
+ else if (i == 213) { /* Size command ok */
+ for (j = 0; j < sizeof resp && ap_isdigit(resp[j]); j++)
+ ;
+ resp[j] = '\0';
+ if (resp[0] != '\0')
+ size = ap_pstrdup(p, resp);
+ }
+ }
}
#ifdef AUTODETECT_PWD
ap_bvputs(f, "PWD", CRLF, NULL);
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 */
/* 257 "<directory-name>" <commentary> */
/* 421 Service not available, closing control connection. */
/* 502 Command not implemented. */
/* 550 Requested action not taken. */
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) {
- return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY,
"Error reading from remote server");
}
if (i == 550) {
- return HTTP_NOT_FOUND;
+ return HTTP_NOT_FOUND;
}
if (i == 257) {
- const char *dirp = resp;
- cwd = ap_getword_conf(r->pool, &dirp);
+ const char *dirp = resp;
+ cwd = ap_getword_conf(r->pool, &dirp);
}
#endif /*AUTODETECT_PWD*/
if (parms[0] == 'd') {
- if (len != 0)
- ap_bvputs(f, "LIST ", path, CRLF, NULL);
- else
- ap_bputs("LIST -lag" CRLF, f);
- Explain1("FTP: LIST %s", (len == 0 ? "" : path));
+ if (len != 0)
+ ap_bvputs(f, "LIST ", path, CRLF, NULL);
+ else
+ ap_bputs("LIST -lag" CRLF, f);
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
+ "FTP: LIST %s", (len == 0 ? "" : path));
}
else {
- ap_bvputs(f, "RETR ", path, CRLF, NULL);
- Explain1("FTP: RETR %s", path);
+ ap_bvputs(f, "RETR ", path, CRLF, NULL);
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
+ "FTP: RETR %s", path);
}
ap_bflush(f);
/* RETR: 110, 125, 150, 226, 250, 421, 425, 426, 450, 451, 500, 501, 530, 550
/* 530 Not logged in. */
/* 550 Requested action not taken. */
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) {
- return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY,
"Error reading from remote server");
}
if (rc == 550) {
- Explain0("FTP: RETR failed, trying LIST instead");
- parms = "d";
- ap_bvputs(f, "CWD ", path, CRLF, NULL);
- ap_bflush(f);
- Explain1("FTP: CWD %s", path);
- /* possible results: 250, 421, 500, 501, 502, 530, 550 */
- /* 250 Requested file action okay, completed. */
- /* 421 Service not available, closing control connection. */
- /* 500 Syntax error, command unrecognized. */
- /* 501 Syntax error in parameters or arguments. */
- /* 502 Command not implemented. */
- /* 530 Not logged in. */
- /* 550 Requested action not taken. */
- rc = ftp_getrc(f);
- Explain1("FTP: returned status %d", rc);
- if (rc == -1) {
- return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
+ "FTP: RETR failed, trying LIST instead");
+ parms = "d";
+ ap_bvputs(f, "CWD ", path, CRLF, NULL);
+ ap_bflush(f);
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
+ "FTP: CWD %s", path);
+ /* possible results: 250, 421, 500, 501, 502, 530, 550 */
+ /* 250 Requested file action okay, completed. */
+ /* 421 Service not available, closing control connection. */
+ /* 500 Syntax error, command unrecognized. */
+ /* 501 Syntax error in parameters or arguments. */
+ /* 502 Command not implemented. */
+ /* 530 Not logged in. */
+ /* 550 Requested action not taken. */
+ rc = ftp_getrc(f);
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
+ "FTP: returned status %d", rc);
+ if (rc == -1) {
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY,
"Error reading from remote server");
- }
- if (rc == 550) {
- return HTTP_NOT_FOUND;
- }
- if (rc != 250) {
- return HTTP_BAD_GATEWAY;
- }
+ }
+ if (rc == 550) {
+ return HTTP_NOT_FOUND;
+ }
+ if (rc != 250) {
+ return HTTP_BAD_GATEWAY;
+ }
#ifdef AUTODETECT_PWD
- ap_bvputs(f, "PWD", CRLF, NULL);
- ap_bflush(f);
- Explain0("FTP: PWD");
+ ap_bvputs(f, "PWD", CRLF, NULL);
+ ap_bflush(f);
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
+ "FTP: PWD");
/* responses: 257, 500, 501, 502, 421, 550 */
- /* 257 "<directory-name>" <commentary> */
- /* 421 Service not available, closing control connection. */
- /* 500 Syntax error, command unrecognized. */
- /* 501 Syntax error in parameters or arguments. */
- /* 502 Command not implemented. */
- /* 550 Requested action not taken. */
- i = ftp_getrc_msg(f, resp, sizeof resp);
- Explain1("FTP: PWD returned status %d", i);
- if (i == -1 || i == 421) {
- return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+ /* 257 "<directory-name>" <commentary> */
+ /* 421 Service not available, closing control connection. */
+ /* 500 Syntax error, command unrecognized. */
+ /* 501 Syntax error in parameters or arguments. */
+ /* 502 Command not implemented. */
+ /* 550 Requested action not taken. */
+ i = ftp_getrc_msg(f, resp, sizeof resp);
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
+ "FTP: PWD returned status %d", i);
+ if (i == -1 || i == 421) {
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY,
"Error reading from remote server");
- }
- if (i == 550) {
- return HTTP_NOT_FOUND;
- }
- if (i == 257) {
- const char *dirp = resp;
- cwd = ap_getword_conf(r->pool, &dirp);
- }
+ }
+ if (i == 550) {
+ return HTTP_NOT_FOUND;
+ }
+ if (i == 257) {
+ const char *dirp = resp;
+ cwd = ap_getword_conf(r->pool, &dirp);
+ }
#endif /*AUTODETECT_PWD*/
- ap_bputs("LIST -lag" CRLF, f);
- ap_bflush(f);
- Explain0("FTP: LIST -lag");
- rc = ftp_getrc(f);
- Explain1("FTP: returned status %d", rc);
- if (rc == -1)
- return ap_proxyerror(r, HTTP_BAD_GATEWAY,
- "Error reading from remote server");
+ ap_bputs("LIST -lag" CRLF, f);
+ ap_bflush(f);
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
+ "FTP: LIST -lag");
+ rc = ftp_getrc(f);
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
+ "FTP: returned status %d", rc);
+ if (rc == -1)
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+ "Error reading from remote server");
}
if (rc != 125 && rc != 150 && rc != 226 && rc != 250)
- return HTTP_BAD_GATEWAY;
+ return HTTP_BAD_GATEWAY;
r->status = HTTP_OK;
r->status_line = "200 OK";
-
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());
if (parms[0] == 'd')
- ap_table_setn(resp_hdrs, "Content-Type", "text/html");
+ ap_table_setn(resp_hdrs, "Content-Type", "text/html");
else {
- if (r->content_type != NULL) {
- ap_table_setn(resp_hdrs, "Content-Type", r->content_type);
- Explain1("FTP: Content-Type set to %s", r->content_type);
- }
- else {
- ap_table_setn(resp_hdrs, "Content-Type", ap_default_type(r));
- }
- if (parms[0] != 'a' && size != NULL) {
- /* We "trust" the ftp server to really serve (size) bytes... */
- ap_table_set(resp_hdrs, "Content-Length", size);
- Explain1("FTP: Content-Length set to %s", size);
- }
+ if (r->content_type != NULL) {
+ ap_table_setn(resp_hdrs, "Content-Type", r->content_type);
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
+ "FTP: Content-Type set to %s", r->content_type);
+ }
+ else {
+ ap_table_setn(resp_hdrs, "Content-Type", ap_default_type(r));
+ }
+ if (parms[0] != 'a' && size != NULL) {
+ /* We "trust" the ftp server to really serve (size) bytes... */
+ ap_table_setn(resp_hdrs, "Content-Length", 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') {
- Explain1("FTP: Content-Encoding set to %s", r->content_encoding);
- ap_table_setn(resp_hdrs, "Content-Encoding", 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_cache_el_header_merge(c, resp_hdrs);
+
/* check if NoCache directive on this host */
for (i = 0; i < conf->nocaches->nelts; i++) {
- if ((ncent[i].name != NULL && strstr(host, ncent[i].name) != NULL)
- || destaddr.s_addr == ncent[i].addr.s_addr || ncent[i].name[0] == '*')
- nocache = 1;
- }
-
- i = ap_proxy_cache_update(c, resp_hdrs, 0, nocache);
-
- if (i != DECLINED) {
- ap_pclosesocket(p, dsock);
- ap_bclose(f);
- return i;
+ if ((ncent[i].name != NULL && strstr(host, ncent[i].name) != NULL)
+ || destaddr.s_addr == ncent[i].addr.s_addr || ncent[i].name[0] == '*')
+ nocache = 1;
}
- if (!pasvmode) { /* wait for connection */
- clen = sizeof(struct sockaddr_in);
- do
- csd = accept(dsock, (struct sockaddr *) &server, &clen);
- while (csd == -1 && errno == EINTR);
- if (csd == -1) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
- "proxy: failed to accept data connection");
- ap_pclosesocket(p, dsock);
- ap_bclose(f);
- if (c != NULL)
- c = ap_proxy_cache_error(c);
- return HTTP_BAD_GATEWAY;
- }
- ap_note_cleanups_for_socket(p, csd);
- data = ap_bcreate(p, B_RDWR | B_SOCKET);
- ap_bpushfd(data, csd);
+ if(nocache || !ap_proxy_cache_should_cache(r, resp_hdrs, 0))
+ ap_proxy_cache_error(&c);
+ else
+ ap_cache_el_data(c, &cachefp);
+
+ if (!pasvmode) { /* wait for connection */
+ for(;;)
+ {
+ switch(ap_accept(&inc, dsock, r->pool))
+ {
+ case APR_EINTR:
+ continue;
+ case APR_SUCCESS:
+ break;
+ default:
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "proxy: failed to accept data connection");
+ ap_close_socket(dsock);
+ ap_bclose(f);
+ if (c != NULL) ap_proxy_cache_error(&c);
+ return HTTP_BAD_GATEWAY;
+ }
+ }
+ data = ap_bcreate(p, B_RDWR);
+ ap_bpush_iol(f, unix_attach_socket(csd));
}
else {
- data = ap_bcreate(p, B_RDWR | B_SOCKET);
- ap_bpushfd(data, dsock);
+ data = ap_bcreate(p, B_RDWR);
+ ap_bpush_iol(data, unix_attach_socket(dsock));
}
/* send response */
/* write status line */
if (!r->assbackwards)
- ap_rvputs(r, "HTTP/1.0 ", r->status_line, CRLF, NULL);
- if (c != NULL && c->fp != NULL
- && ap_bvputs(c->fp, "HTTP/1.0 ", r->status_line, CRLF, NULL) == -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_rvputs(r, "HTTP/1.0 ", r->status_line, CRLF, NULL);
+ if (cachefp && ap_bvputs(cachefp, "HTTP/1.0 ", r->status_line, CRLF, NULL) == -1) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "proxy: error writing CRLF to cache");
+ ap_proxy_cache_error(&c);
+ cachefp = NULL;
}
/* send headers */
- tdo.req = r;
- tdo.cache = c;
- ap_table_do(ap_proxy_send_hdr_line, &tdo, resp_hdrs, NULL);
-
+ ap_cache_el_header_walk(c, ap_proxy_send_hdr_line, r, NULL);
if (!r->assbackwards)
- 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_rputs(CRLF, r);
+ if (cachefp && ap_bputs(CRLF, cachefp) == -1) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "proxy: error writing CRLF to cache");
+ ap_proxy_cache_error(&c);
+ cachefp = NULL;
}
ap_bsetopt(r->connection->client, BO_BYTECT, &zero);
r->sent_bodyct = 1;
/* send body */
if (!r->header_only) {
- if (parms[0] != 'd') {
-/* we need to set this for ap_proxy_send_fb()... */
- if (c != NULL)
- c->cache_completion = 0;
- ap_proxy_send_fb(data, r, c);
- } else
- send_dir(data, r, c, cwd);
-
- if (rc == 125 || rc == 150)
- rc = ftp_getrc(f);
-
- /* XXX: we checked for 125||150||226||250 above. This is redundant. */
- if (rc != 226 && rc != 250)
+ if (parms[0] != 'd') {
+ /* we don't need no steekin' cache completion*/
+ ap_proxy_send_fb(NULL, data, r, c);
+ } else
+ send_dir(data, r, c, cwd);
+
+ if (rc == 125 || rc == 150)
+ rc = ftp_getrc(f);
+
+ /* XXX: we checked for 125||150||226||250 above. This is redundant. */
+ if (rc != 226 && rc != 250)
/* 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 {
/* abort the transfer */
- ap_bputs("ABOR" CRLF, f);
- ap_bflush(f);
- if (!pasvmode)
- ap_bclose(data);
- Explain0("FTP: ABOR");
+ ap_bputs("ABOR" CRLF, f);
+ ap_bflush(f);
+ if (!pasvmode)
+ ap_bclose(data);
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
+ "FTP: ABOR");
/* responses: 225, 226, 421, 500, 501, 502 */
/* 225 Data connection open; no transfer in progress. */
/* 226 Closing data connection. */
/* 500 Syntax error, command unrecognized. */
/* 501 Syntax error in parameters or arguments. */
/* 502 Command not implemented. */
- i = ftp_getrc(f);
- Explain1("FTP: returned status %d", i);
+ i = ftp_getrc(f);
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
+ "FTP: returned status %d", i);
}
- ap_proxy_cache_tidy(c);
-
/* finish */
ap_bputs("QUIT" CRLF, f);
ap_bflush(f);
- Explain0("FTP: QUIT");
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
+ "FTP: QUIT");
/* responses: 221, 500 */
/* 221 Service closing control connection. */
/* 500 Syntax error, command unrecognized. */
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)
- ap_bclose(data);
+ ap_bclose(data);
ap_bclose(f);
- ap_rflush(r); /* flush before garbage collection */
-
- ap_proxy_garbage_coll(r);
+ ap_rflush(r); /* flush before garbage collection */
+ if(c) ap_proxy_cache_update(c);
return OK;
}
#include "http_main.h"
#include "http_core.h"
#include "util_date.h"
+#include "iol_socket.h"
/*
* Canonicalise http-like URLs.
port = def_port;
err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port);
if (err)
- return HTTP_BAD_REQUEST;
+ return HTTP_BAD_REQUEST;
/* now parse path/search args, according to rfc1738 */
/* N.B. if this isn't a true proxy request, then the URL _path_
* == r->unparsed_uri, and no others have that property.
*/
if (r->uri == r->unparsed_uri) {
- search = strchr(url, '?');
- if (search != NULL)
- *(search++) = '\0';
+ search = strchr(url, '?');
+ if (search != NULL)
+ *(search++) = '\0';
}
else
- search = r->args;
+ search = r->args;
/* process path */
path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, r->proxyreq);
if (path == NULL)
- return HTTP_BAD_REQUEST;
+ return HTTP_BAD_REQUEST;
if (port != def_port)
- ap_snprintf(sport, sizeof(sport), ":%d", port);
+ ap_snprintf(sport, sizeof(sport), ":%d", port);
else
- sport[0] = '\0';
+ sport[0] = '\0';
r->filename = ap_pstrcat(r->pool, "proxy:", scheme, "://", host, sport, "/",
- path, (search) ? "?" : "", (search) ? search : "", NULL);
+ path, (search) ? "?" : "", (search) ? search : "", NULL);
return OK;
}
ap_table_unset(headers, "Proxy-Connection");
if (!next)
- return;
+ return;
while (*next) {
- name = next;
- while (*next && !ap_isspace(*next) && (*next != ','))
- ++next;
- while (*next && (ap_isspace(*next) || (*next == ','))) {
- *next = '\0';
- ++next;
- }
- ap_table_unset(headers, name);
+ name = next;
+ while (*next && !ap_isspace(*next) && (*next != ','))
+ ++next;
+ while (*next && (ap_isspace(*next) || (*next == ','))) {
+ *next = '\0';
+ ++next;
+ }
+ ap_table_unset(headers, name);
}
ap_table_unset(headers, "Connection");
}
* we return DECLINED so that we can try another proxy. (Or the direct
* route.)
*/
-int ap_proxy_http_handler(request_rec *r, cache_req *c, char *url,
- const char *proxyhost, int proxyport)
+int ap_proxy_http_handler(request_rec *r, ap_cache_el *c, char *url,
+ const char *proxyhost, int proxyport)
{
const char *strp;
char *strp2;
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_table_t *resp_hdrs;
- table_entry *reqhdrs;
+ ap_table_entry_t *reqhdrs;
struct sockaddr_in server;
struct in_addr destaddr;
struct hostent server_hp;
- BUFF *f;
+ BUFF *f, *cachefp=NULL;
char buffer[HUGE_STRING_LEN];
char portstr[32];
ap_pool_t *p = r->pool;
const long int zero = 0L;
int destport = 0;
+ ap_ssize_t cntr;
char *destportstr = NULL;
const char *urlptr = NULL;
- const char *datestr;
- struct tbl_do_args tdo;
+ char *datestr, *clen;
void *sconf = r->server->module_config;
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 nocache_entry *ncent = (struct nocache_entry *) conf->nocaches->elts;
int nocache = 0;
urlptr = strstr(url, "://");
if (urlptr == NULL)
- return HTTP_BAD_REQUEST;
+ return HTTP_BAD_REQUEST;
urlptr += 3;
destport = DEFAULT_HTTP_PORT;
strp = strchr(urlptr, '/');
if (strp == NULL) {
- desthost = ap_pstrdup(p, urlptr);
- urlptr = "/";
+ desthost = ap_pstrdup(p, urlptr);
+ urlptr = "/";
}
else {
- char *q = ap_palloc(p, strp - urlptr + 1);
- memcpy(q, urlptr, strp - urlptr);
- q[strp - urlptr] = '\0';
- urlptr = strp;
- desthost = q;
+ char *q = ap_palloc(p, strp - urlptr + 1);
+ memcpy(q, urlptr, strp - urlptr);
+ q[strp - urlptr] = '\0';
+ urlptr = strp;
+ desthost = q;
}
strp2 = strchr(desthost, ':');
if (strp2 != NULL) {
- *(strp2++) = '\0';
- if (ap_isdigit(*strp2)) {
- destport = atoi(strp2);
- destportstr = strp2;
- }
+ *(strp2++) = '\0';
+ if (ap_isdigit(*strp2)) {
+ destport = atoi(strp2);
+ destportstr = strp2;
+ }
}
/* check if ProxyBlock directive on this host */
destaddr.s_addr = ap_inet_addr(desthost);
for (i = 0; i < conf->noproxies->nelts; i++) {
- if ((npent[i].name != NULL && strstr(desthost, npent[i].name) != NULL)
- || destaddr.s_addr == npent[i].addr.s_addr || npent[i].name[0] == '*')
- return ap_proxyerror(r, HTTP_FORBIDDEN,
- "Connect to remote machine blocked");
- }
-
- if (proxyhost != NULL) {
- server.sin_port = htons(proxyport);
- 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);
+ if ((npent[i].name != NULL && strstr(desthost, npent[i].name) != NULL)
+ || destaddr.s_addr == npent[i].addr.s_addr || npent[i].name[0] == '*')
+ return ap_proxyerror(r, HTTP_FORBIDDEN,
+ "Connect to remote machine blocked");
}
- 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");
- return HTTP_INTERNAL_SERVER_ERROR;
+ if ((ap_create_tcp_socket(&sock, r->pool)) != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "proxy: error creating socket");
+ return HTTP_INTERNAL_SERVER_ERROR;
}
- if (conf->recv_buffer_size) {
- if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
- (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");
- }
+ if (conf->recv_buffer_size > 0 && ap_setsocketopt(sock, APR_SO_RCVBUF,conf->recv_buffer_size)) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "setsockopt(SO_RCVBUF): Failed to set ProxyReceiveBufferSize, using default");
}
-
-#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;
- }
+
+ if (proxyhost != NULL) {
+ i = ap_proxy_doconnect(sock, (char *)proxyhost, proxyport, r);
}
-#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++;
+ else {
+ i = ap_proxy_doconnect(sock, (char *)desthost, destport, r);
}
-#endif
+
if (i == -1) {
- if (proxyhost != NULL)
- return DECLINED; /* try again another way */
- else
- char buf[120];
- return ap_proxyerror(r, HTTP_BAD_GATEWAY, ap_pstrcat(r->pool,
- "Could not connect to remote machine: ",
- ap_strerror(errno, buf, sizeof(buf)), NULL));
+ if (proxyhost != NULL)
+ return DECLINED; /* try again another way */
+ else
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+ ap_pstrcat(r->pool, "Could not connect to remote machine: ",
+ strerror(errno), NULL));
}
- clear_connection(r->pool, r->headers_in); /* Strip connection-based headers */
+ clear_connection(r->pool, r->headers_in); /* Strip connection-based headers */
- f = ap_bcreate(p, B_RDWR | B_SOCKET);
- ap_bpushfd(f, sock);
+ f = ap_bcreate(p, B_RDWR);
+ ap_bpush_iol(f, unix_attach_socket(sock));
ap_bvputs(f, r->method, " ", proxyhost ? url : urlptr, " HTTP/1.0" CRLF,
- NULL);
+ NULL);
if (destportstr != NULL && destport != DEFAULT_HTTP_PORT)
- ap_bvputs(f, "Host: ", desthost, ":", destportstr, CRLF, NULL);
+ ap_bvputs(f, "Host: ", desthost, ":", destportstr, CRLF, NULL);
else
- ap_bvputs(f, "Host: ", desthost, CRLF, NULL);
+ ap_bvputs(f, "Host: ", desthost, CRLF, NULL);
if (conf->viaopt == via_block) {
- /* Block all outgoing Via: headers */
- ap_table_unset(r->headers_in, "Via");
+ /* Block all outgoing Via: headers */
+ ap_table_unset(r->headers_in, "Via");
} else if (conf->viaopt != via_off) {
- /* Create a "Via:" request header entry and merge it */
- i = ap_get_server_port(r);
- if (ap_is_default_port(i,r)) {
- strcpy(portstr,"");
- } else {
- ap_snprintf(portstr, sizeof portstr, ":%d", i);
- }
- /* Generate outgoing Via: header with/without server comment: */
- ap_table_mergen(r->headers_in, "Via",
- (conf->viaopt == via_full)
- ? ap_psprintf(p, "%d.%d %s%s (%s)",
- HTTP_VERSION_MAJOR(r->proto_num),
- HTTP_VERSION_MINOR(r->proto_num),
- ap_get_server_name(r), portstr,
- SERVER_BASEVERSION)
- : ap_psprintf(p, "%d.%d %s%s",
- HTTP_VERSION_MAJOR(r->proto_num),
- HTTP_VERSION_MINOR(r->proto_num),
- ap_get_server_name(r), portstr)
- );
+ /* Create a "Via:" request header entry and merge it */
+ i = ap_get_server_port(r);
+ if (ap_is_default_port(i,r)) {
+ strcpy(portstr,"");
+ } else {
+ ap_snprintf(portstr, sizeof portstr, ":%d", i);
+ }
+ /* Generate outgoing Via: header with/without server comment: */
+ ap_table_mergen(r->headers_in, "Via",
+ (conf->viaopt == via_full)
+ ? ap_psprintf(p, "%d.%d %s%s (%s)",
+ HTTP_VERSION_MAJOR(r->proto_num),
+ HTTP_VERSION_MINOR(r->proto_num),
+ ap_get_server_name(r), portstr,
+ AP_SERVER_BASEVERSION)
+ : ap_psprintf(p, "%d.%d %s%s",
+ HTTP_VERSION_MAJOR(r->proto_num),
+ HTTP_VERSION_MINOR(r->proto_num),
+ ap_get_server_name(r), portstr)
+ );
}
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++) {
- if (reqhdrs[i].key == NULL || reqhdrs[i].val == NULL
- /* Clear out headers not to send */
- || !strcasecmp(reqhdrs[i].key, "Host") /* Already sent */
- /* XXX: @@@ FIXME: "Proxy-Authorization" should *only* be
- * suppressed if THIS server requested the authentication,
- * not when a frontend proxy requested it!
- */
- || !strcasecmp(reqhdrs[i].key, "Proxy-Authorization"))
- continue;
- ap_bvputs(f, reqhdrs[i].key, ": ", reqhdrs[i].val, CRLF, NULL);
+ if (reqhdrs[i].key == NULL || reqhdrs[i].val == NULL
+ /* Clear out headers not to send */
+ || !strcasecmp(reqhdrs[i].key, "Host") /* Already sent */
+ /* XXX: @@@ FIXME: "Proxy-Authorization" should *only* be
+ * suppressed if THIS server requested the authentication,
+ * not when a frontend proxy requested it!
+ */
+ || !strcasecmp(reqhdrs[i].key, "Proxy-Authorization"))
+ continue;
+ ap_bvputs(f, reqhdrs[i].key, ": ", reqhdrs[i].val, CRLF, NULL);
}
ap_bputs(CRLF, f);
/* send the request data, if any. */
if (ap_should_client_block(r)) {
- while ((i = ap_get_client_block(r, buffer, sizeof buffer)) > 0)
- ap_bwrite(f, buffer, i);
+ while ((i = ap_get_client_block(r, buffer, sizeof buffer)) > 0)
+ ap_bwrite(f, buffer, i, &cntr);
}
ap_bflush(f);
len = ap_bgets(buffer, sizeof buffer - 1, f);
if (len == -1) {
- ap_bclose(f);
- ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
- "ap_bgets() - proxy receive - Error reading from remote server %s (length %d)",
- proxyhost ? proxyhost : desthost, len);
- return ap_proxyerror(r, HTTP_BAD_GATEWAY,
- "Error reading from remote server");
+ ap_bclose(f);
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "ap_bgets() - proxy receive - Error reading from remote server %s (length %d)",
+ proxyhost ? proxyhost : desthost, len);
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+ "Error reading from remote server");
} else if (len == 0) {
- ap_bclose(f);
- return ap_proxyerror(r, HTTP_BAD_GATEWAY,
- "Document contains no data");
+ ap_bclose(f);
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+ "Document contains no data");
}
/* Is it an HTTP/1 response? This is buggy if we ever see an HTTP/1.10 */
if (ap_checkmask(buffer, "HTTP/#.# ###*")) {
- int major, minor;
- if (2 != sscanf(buffer, "HTTP/%u.%u", &major, &minor)) {
- major = 1;
- minor = 0;
- }
+ int major, minor;
+ if (2 != sscanf(buffer, "HTTP/%u.%u", &major, &minor)) {
+ major = 1;
+ minor = 0;
+ }
/* If not an HTTP/1 message or if the status line was > 8192 bytes */
- if (buffer[5] != '1' || buffer[len - 1] != '\n') {
- ap_bclose(f);
- return HTTP_BAD_GATEWAY;
- }
- backasswards = 0;
- buffer[--len] = '\0';
-
- buffer[12] = '\0';
- r->status = atoi(&buffer[9]);
- buffer[12] = ' ';
- r->status_line = ap_pstrdup(p, &buffer[9]);
+ if (buffer[5] != '1' || buffer[len - 1] != '\n') {
+ ap_bclose(f);
+ return HTTP_BAD_GATEWAY;
+ }
+ backasswards = 0;
+ buffer[--len] = '\0';
+
+ buffer[12] = '\0';
+ r->status = atoi(&buffer[9]);
+ buffer[12] = ' ';
+ r->status_line = ap_pstrdup(p, &buffer[9]);
/* read the headers. */
/* N.B. for HTTP/1.0 clients, we have to fold line-wrapped headers */
/* Also, take care with headers with multiple occurences. */
-
- resp_hdrs = ap_proxy_read_headers(r, buffer, HUGE_STRING_LEN, f);
- if (resp_hdrs == NULL) {
- ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, r->server,
- "proxy: Bad HTTP/%d.%d header returned by %s (%s)",
- major, minor, r->uri, r->method);
- resp_hdrs = ap_make_table(p, 20);
- nocache = 1; /* do not cache this broken file */
- }
-
- if (conf->viaopt != via_off && conf->viaopt != via_block) {
- /* Create a "Via:" response header entry and merge it */
- i = ap_get_server_port(r);
- if (ap_is_default_port(i,r)) {
- strcpy(portstr,"");
- } else {
- ap_snprintf(portstr, sizeof portstr, ":%d", i);
- }
- ap_table_mergen((table *)resp_hdrs, "Via",
- (conf->viaopt == via_full)
- ? ap_psprintf(p, "%d.%d %s%s (%s)",
- major, minor,
- 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 */
+ resp_hdrs = ap_proxy_read_headers(r, buffer, HUGE_STRING_LEN, f);
+ if (resp_hdrs == NULL) {
+ ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r->server,
+ "proxy: Bad HTTP/%d.%d header returned by %s (%s)",
+ major, minor, r->uri, r->method);
+ 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) {
+ /* Create a "Via:" response header entry and merge it */
+ i = ap_get_server_port(r);
+ if (ap_is_default_port(i,r)) {
+ strcpy(portstr,"");
+ } else {
+ ap_snprintf(portstr, sizeof portstr, ":%d", i);
+ }
+ ap_cache_el_header_add(c, "Via", (conf->viaopt == via_full)
+ ? ap_psprintf(p, "%d.%d %s%s (%s)", major, minor,
+ ap_get_server_name(r), portstr, AP_SERVER_BASEVERSION)
+ : ap_psprintf(p, "%d.%d %s%s", major, minor, ap_get_server_name(r), portstr)
+ );
+ }
}
else {
/* an http/0.9 response */
- backasswards = 1;
- r->status = 200;
- r->status_line = "200 OK";
-
-/* no headers */
- resp_hdrs = ap_make_table(p, 20);
+ backasswards = 1;
+ r->status = 200;
+ r->status_line = "200 OK";
}
- c->hdrs = resp_hdrs;
-
-
/*
* HTTP/1.0 requires us to accept 3 types of dates, but only generate
* one type
*/
- if ((datestr = ap_table_get(resp_hdrs, "Date")) != NULL)
- ap_table_set(resp_hdrs, "Date", ap_proxy_date_canon(p, datestr));
- if ((datestr = ap_table_get(resp_hdrs, "Last-Modified")) != NULL)
- ap_table_set(resp_hdrs, "Last-Modified", ap_proxy_date_canon(p, datestr));
- if ((datestr = ap_table_get(resp_hdrs, "Expires")) != NULL)
- ap_table_set(resp_hdrs, "Expires", ap_proxy_date_canon(p, datestr));
-
- if ((datestr = ap_table_get(resp_hdrs, "Location")) != NULL)
- ap_table_set(resp_hdrs, "Location", proxy_location_reverse_map(r, datestr));
- if ((datestr = ap_table_get(resp_hdrs, "URI")) != NULL)
- ap_table_set(resp_hdrs, "URI", proxy_location_reverse_map(r, datestr));
+ if (ap_cache_el_header(c, "Date", &datestr) == APR_SUCCESS)
+ ap_cache_el_header_set(c, "Date", ap_proxy_date_canon(p, datestr));
+ if (ap_cache_el_header(c, "Last-Modified", &datestr) == APR_SUCCESS)
+ ap_cache_el_header_set(c, "Last-Modified", ap_proxy_date_canon(p, datestr));
+ if (ap_cache_el_header(c, "Expires", &datestr) == APR_SUCCESS)
+ ap_cache_el_header_set(c, "Expires", ap_proxy_date_canon(p, datestr));
+
+ if (ap_cache_el_header(c, "Location", &datestr) == APR_SUCCESS)
+ ap_cache_el_header_set(c, "Location", proxy_location_reverse_map(r, datestr));
+ if (ap_cache_el_header(c, "URI", &datestr) == APR_SUCCESS)
+ ap_cache_el_header_set(c, "URI", proxy_location_reverse_map(r, datestr));
/* check if NoCache directive on this host */
- for (i = 0; i < conf->nocaches->nelts; i++) {
- if ((ncent[i].name != NULL && strstr(desthost, ncent[i].name) != NULL)
- || destaddr.s_addr == ncent[i].addr.s_addr || ncent[i].name[0] == '*')
- nocache = 1;
- }
+ if (ap_cache_el_header(c, "Content-Length", &clen) == APR_SUCCESS)
+ content_length = atoi(clen ? clen : "-1");
- i = ap_proxy_cache_update(c, resp_hdrs, !backasswards, nocache);
- if (i != DECLINED) {
- ap_bclose(f);
- return i;
+ for (i = 0; i < conf->nocaches->nelts; i++) {
+ if ((ncent[i].name != NULL && strstr(desthost, ncent[i].name) != NULL)
+ || destaddr.s_addr == ncent[i].addr.s_addr || ncent[i].name[0] == '*')
+ nocache = 1;
}
+ if(nocache || !ap_proxy_cache_should_cache(r, resp_hdrs, !backasswards))
+ ap_proxy_cache_error(&c);
+ else
+ ap_cache_el_data(c, &cachefp);
+
/* write status line */
if (!r->assbackwards)
- ap_rvputs(r, "HTTP/1.0 ", r->status_line, CRLF, NULL);
- if (c != NULL && c->fp != NULL &&
- ap_bvputs(c->fp, "HTTP/1.0 ", r->status_line, CRLF, NULL) == -1) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
- "proxy: error writing status line to %s", c->tempfile);
- c = ap_proxy_cache_error(c);
+ ap_rvputs(r, "HTTP/1.0 ", r->status_line, CRLF, NULL);
+ if (cachefp && ap_bvputs(cachefp, "HTTP/1.0 ", r->status_line, CRLF, NULL) == -1) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "proxy: error writing status line to cache");
+ ap_proxy_cache_error(&c);
+ cachefp = NULL;
}
/* send headers */
- tdo.req = r;
- tdo.cache = c;
- ap_table_do(ap_proxy_send_hdr_line, &tdo, resp_hdrs, NULL);
+ ap_cache_el_header_walk(c, ap_proxy_send_hdr_line, r, NULL);
if (!r->assbackwards)
- 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_rputs(CRLF, r);
ap_bsetopt(r->connection->client, BO_BYTECT, &zero);
r->sent_bodyct = 1;
/* Is it an HTTP/0.9 respose? If so, send the extra data */
if (backasswards) {
- ap_bwrite(r->connection->client, buffer, len);
- if (c != NULL && c->fp != NULL && ap_bwrite(c->fp, buffer, len) != len) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
- "proxy: error writing extra data to %s", c->tempfile);
- c = ap_proxy_cache_error(c);
- }
+ ap_bwrite(r->connection->client, buffer, len, &cntr);
+ if (cachefp && ap_bwrite(cachefp, buffer, len, &cntr) != len) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "proxy: error writing extra data to cache", cachefp);
+ ap_proxy_cache_error(&c);
+ }
}
#ifdef CHARSET_EBCDIC
ap_bsetflag(r->connection->client, B_ASCII2EBCDIC|B_EBCDIC2ASCII, 0);
#endif
-/* send body */
-/* if header only, then cache will be NULL */
-/* HTTP/1.0 tells us to read to EOF, rather than content-length bytes */
+ /* send body */
+ /* if header only, then cache will be NULL */
+ /* HTTP/1.0 tells us to read to EOF, rather than content-length bytes */
if (!r->header_only) {
-/* we need to set this for ap_proxy_send_fb()... */
- c->cache_completion = conf->cache.cache_completion;
- ap_proxy_send_fb(f, r, c);
+ proxy_completion pc;
+ pc.content_length = content_length;
+ pc.cache_completion = conf->cache_completion;
+ ap_proxy_send_fb(&pc, f, r, c);
}
- ap_proxy_cache_tidy(c);
-
ap_bclose(f);
-
- ap_proxy_garbage_coll(r);
+ if(c) ap_proxy_cache_update(c);
return OK;
}
#include "apr_md5.h"
#include "http_log.h"
#include "util_uri.h"
-#include "util_date.h" /* get ap_checkmask() decl. */
+#include "util_date.h" /* get ap_checkmask() decl. */
#include <pthread.h>
#ifndef CHARSET_EBCDIC
ch = x[0];
if (ap_isdigit(ch))
- i = ch - '0';
+ i = ch - '0';
else if (ap_isupper(ch))
- i = ch - ('A' - 10);
+ i = ch - ('A' - 10);
else
- i = ch - ('a' - 10);
+ i = ch - ('a' - 10);
i <<= 4;
ch = x[1];
if (ap_isdigit(ch))
- i += ch - '0';
+ i += ch - '0';
else if (ap_isupper(ch))
- i += ch - ('A' - 10);
+ i += ch - ('A' - 10);
else
- i += ch - ('a' - 10);
+ i += ch - ('a' - 10);
return i;
#else /*CHARSET_EBCDIC*/
return (1 == sscanf(x, "%2x", &i)) ? os_toebcdic[i&0xFF] : 0;
x[0] = '%';
i = (ch & 0xF0) >> 4;
if (i >= 10)
- x[1] = ('A' - 10) + i;
+ x[1] = ('A' - 10) + i;
else
- x[1] = '0' + i;
+ x[1] = '0' + i;
i = ch & 0x0F;
if (i >= 10)
- x[2] = ('A' - 10) + i;
+ x[2] = ('A' - 10) + i;
else
- x[2] = '0' + i;
+ x[2] = '0' + i;
#else /*CHARSET_EBCDIC*/
static const char ntoa[] = { "0123456789ABCDEF" };
ch &= 0xFF;
{
int i, j, ch;
char *y;
- const char *allowed; /* characters which should not be encoded */
- const char *reserved; /* characters which much not be en/de-coded */
+ const char *allowed; /* characters which should not be encoded */
+ const char *reserved; /* characters which much not be en/de-coded */
/* N.B. in addition to :@&=, this allows ';' in an http path
* and '?' in an ftp path -- this may be revised
* it only permits ; / ? : @ = & as reserved chars.)
*/
if (t == enc_path)
- allowed = "$-_.+!*'(),;:@&=";
+ allowed = "$-_.+!*'(),;:@&=";
else if (t == enc_search)
- allowed = "$-_.!*'(),;:@&=";
+ allowed = "$-_.!*'(),;:@&=";
else if (t == enc_user)
- allowed = "$-_.+!*'(),;@&=";
+ allowed = "$-_.+!*'(),;@&=";
else if (t == enc_fpath)
- allowed = "$-_.+!*'(),?:@&=";
- else /* if (t == enc_parm) */
- allowed = "$-_.+!*'(),?/:@&=";
+ allowed = "$-_.+!*'(),?:@&=";
+ else /* if (t == enc_parm) */
+ allowed = "$-_.+!*'(),?/:@&=";
if (t == enc_path)
- reserved = "/";
+ reserved = "/";
else if (t == enc_search)
- reserved = "+";
+ reserved = "+";
else
- reserved = "";
+ reserved = "";
y = ap_palloc(p, 3 * len + 1);
for (i = 0, j = 0; i < len; i++, j++) {
/* always handle '/' first */
- ch = x[i];
- if (strchr(reserved, ch)) {
- y[j] = ch;
- continue;
- }
+ ch = x[i];
+ if (strchr(reserved, ch)) {
+ y[j] = ch;
+ continue;
+ }
/* decode it if not already done */
- if (isenc && ch == '%') {
- if (!ap_isxdigit(x[i + 1]) || !ap_isxdigit(x[i + 2]))
- return NULL;
- ch = ap_proxy_hex2c(&x[i + 1]);
- i += 2;
- if (ch != 0 && strchr(reserved, ch)) { /* keep it encoded */
- ap_proxy_c2hex(ch, &y[j]);
- j += 2;
- continue;
- }
- }
+ if (isenc && ch == '%') {
+ if (!ap_isxdigit(x[i + 1]) || !ap_isxdigit(x[i + 2]))
+ return NULL;
+ ch = ap_proxy_hex2c(&x[i + 1]);
+ i += 2;
+ if (ch != 0 && strchr(reserved, ch)) { /* keep it encoded */
+ ap_proxy_c2hex(ch, &y[j]);
+ j += 2;
+ continue;
+ }
+ }
/* recode it, if necessary */
- if (!ap_isalnum(ch) && !strchr(allowed, ch)) {
- ap_proxy_c2hex(ch, &y[j]);
- j += 2;
- }
- else
- y[j] = ch;
+ if (!ap_isalnum(ch) && !strchr(allowed, ch)) {
+ ap_proxy_c2hex(ch, &y[j]);
+ j += 2;
+ }
+ else
+ y[j] = ch;
}
y[j] = '\0';
return y;
*/
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)
{
int i;
char *strp, *host, *url = *urlp;
char *user = NULL, *password = NULL;
if (url[0] != '/' || url[1] != '/')
- return "Malformed URL";
+ return "Malformed URL";
host = url + 2;
url = strchr(host, '/');
if (url == NULL)
- url = "";
+ url = "";
else
- *(url++) = '\0'; /* skip seperating '/' */
+ *(url++) = '\0'; /* skip seperating '/' */
/* find _last_ '@' since it might occur in user/password part */
strp = strrchr(host, '@');
if (strp != NULL) {
- *strp = '\0';
- user = host;
- host = strp + 1;
+ *strp = '\0';
+ user = host;
+ host = strp + 1;
/* find password */
- strp = strchr(user, ':');
- if (strp != NULL) {
- *strp = '\0';
- password = ap_proxy_canonenc(p, strp + 1, strlen(strp + 1), enc_user, 1);
- if (password == NULL)
- return "Bad %-escape in URL (password)";
- }
-
- user = ap_proxy_canonenc(p, user, strlen(user), enc_user, 1);
- if (user == NULL)
- return "Bad %-escape in URL (username)";
+ strp = strchr(user, ':');
+ if (strp != NULL) {
+ *strp = '\0';
+ password = ap_proxy_canonenc(p, strp + 1, strlen(strp + 1), enc_user, 1);
+ if (password == NULL)
+ return "Bad %-escape in URL (password)";
+ }
+
+ user = ap_proxy_canonenc(p, user, strlen(user), enc_user, 1);
+ if (user == NULL)
+ return "Bad %-escape in URL (username)";
}
if (userp != NULL) {
- *userp = user;
+ *userp = user;
}
if (passwordp != NULL) {
- *passwordp = password;
+ *passwordp = password;
}
strp = strrchr(host, ':');
if (strp != NULL) {
- *(strp++) = '\0';
-
- for (i = 0; strp[i] != '\0'; i++)
- if (!ap_isdigit(strp[i]))
- break;
-
- /* if (i == 0) the no port was given; keep default */
- if (strp[i] != '\0') {
- return "Bad port number in URL";
- } else if (i > 0) {
- *port = atoi(strp);
- if (*port > 65535)
- return "Port number in URL > 65535";
- }
+ *(strp++) = '\0';
+
+ for (i = 0; strp[i] != '\0'; i++)
+ if (!ap_isdigit(strp[i]))
+ break;
+
+ /* if (i == 0) the no port was given; keep default */
+ if (strp[i] != '\0') {
+ return "Bad port number in URL";
+ } else if (i > 0) {
+ *port = atoi(strp);
+ if (*port > 65535)
+ return "Port number in URL > 65535";
+ }
}
- ap_str_tolower(host); /* DNS names are case insensitive */
+ ap_str_tolower(host); /* DNS names are case insensitive */
if (*host == '\0')
- return "Missing host in URL";
+ return "Missing host in URL";
/* check hostname syntax */
for (i = 0; host[i] != '\0'; i++)
- if (!ap_isdigit(host[i]) && host[i] != '.')
- break;
+ if (!ap_isdigit(host[i]) && host[i] != '.')
+ break;
/* must be an IP address */
#ifdef WIN32
if (host[i] == '\0' && (inet_addr(host) == -1))
if (host[i] == '\0' && (ap_inet_addr(host) == -1 || inet_network(host) == -1))
#endif
{
- return "Bad IP address in URL";
+ return "Bad IP address in URL";
}
/* if (strchr(host,'.') == NULL && domain != NULL)
q = strchr(x, ',');
/* check for RFC 850 date */
if (q != NULL && q - x > 3 && q[1] == ' ') {
- *q = '\0';
- for (wk = 0; wk < 7; wk++)
- if (strcmp(x, lwday[wk]) == 0)
- break;
- *q = ',';
- if (wk == 7)
- return x; /* not a valid date */
- if (q[4] != '-' || q[8] != '-' || q[11] != ' ' || q[14] != ':' ||
- q[17] != ':' || strcmp(&q[20], " GMT") != 0)
- return x;
- if (sscanf(q + 2, "%u-%3s-%u %u:%u:%u %3s", &mday, month, &year,
- &hour, &min, &sec, zone) != 7)
- return x;
- if (year < 70)
- year += 2000;
- else
- year += 1900;
+ *q = '\0';
+ for (wk = 0; wk < 7; wk++)
+ if (strcmp(x, lwday[wk]) == 0)
+ break;
+ *q = ',';
+ if (wk == 7)
+ return x; /* not a valid date */
+ if (q[4] != '-' || q[8] != '-' || q[11] != ' ' || q[14] != ':' ||
+ q[17] != ':' || strcmp(&q[20], " GMT") != 0)
+ return x;
+ if (sscanf(q + 2, "%u-%3s-%u %u:%u:%u %3s", &mday, month, &year,
+ &hour, &min, &sec, zone) != 7)
+ return x;
+ if (year < 70)
+ year += 2000;
+ else
+ year += 1900;
}
else {
/* check for acstime() date */
- if (x[3] != ' ' || x[7] != ' ' || x[10] != ' ' || x[13] != ':' ||
- x[16] != ':' || x[19] != ' ' || x[24] != '\0')
- return x;
- if (sscanf(x, "%3s %3s %u %u:%u:%u %u", week, month, &mday, &hour,
- &min, &sec, &year) != 7)
- return x;
- for (wk = 0; wk < 7; wk++)
- if (strcmp(week, ap_day_snames[wk]) == 0)
- break;
- if (wk == 7)
- return x;
+ if (x[3] != ' ' || x[7] != ' ' || x[10] != ' ' || x[13] != ':' ||
+ x[16] != ':' || x[19] != ' ' || x[24] != '\0')
+ return x;
+ if (sscanf(x, "%3s %3s %u %u:%u:%u %u", week, month, &mday, &hour,
+ &min, &sec, &year) != 7)
+ return x;
+ for (wk = 0; wk < 7; wk++)
+ if (strcmp(week, ap_day_snames[wk]) == 0)
+ break;
+ if (wk == 7)
+ return x;
}
/* check date */
for (mon = 0; mon < 12; mon++)
- if (strcmp(month, ap_month_snames[mon]) == 0)
- break;
+ if (strcmp(month, ap_month_snames[mon]) == 0)
+ break;
if (mon == 12)
- return x;
+ return x;
q = ap_palloc(p, 30);
ap_snprintf(q, 30, "%s, %.2d %s %d %.2d:%.2d:%.2d GMT", ap_day_snames[wk], mday,
- ap_month_snames[mon], year, hour, min, sec);
+ ap_month_snames[mon], year, hour, min, sec);
return q;
}
* the next line begins with a continuation character.
*/
} while (fold && (retval != 1) && (n > 1)
- && (ap_blookc(&next, in) == 1)
+ && (next = ap_blookc(in))
&& ((next == ' ') || (next == '\t')));
return total;
* @@@: XXX: FIXME: currently the headers are passed thru un-merged.
* 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;
int len;
* the connection closes (EOF), or we timeout.
*/
while ((len = proxy_getline(buffer, size, f, 1)) > 0) {
-
- if (!(value = strchr(buffer, ':'))) { /* Find the colon separator */
-
- /* Buggy MS IIS servers sometimes return invalid headers
- * (an extra "HTTP/1.0 200, OK" line sprinkled in between
- * the usual MIME headers). Try to deal with it in a sensible
- * way, but log the fact.
- * XXX: The mask check is buggy if we ever see an HTTP/1.10 */
-
- if (!ap_checkmask(buffer, "HTTP/#.# ###*")) {
- /* Nope, it wasn't even an extra HTTP header. Give up. */
- return NULL;
- }
-
- ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, r->server,
- "proxy: Ignoring duplicate HTTP header "
- "returned by %s (%s)", r->uri, r->method);
- continue;
- }
+
+ if (!(value = strchr(buffer, ':'))) { /* Find the colon separator */
+
+ /* Buggy MS IIS servers sometimes return invalid headers
+ * (an extra "HTTP/1.0 200, OK" line sprinkled in between
+ * the usual MIME headers). Try to deal with it in a sensible
+ * way, but log the fact.
+ * XXX: The mask check is buggy if we ever see an HTTP/1.10 */
+
+ if (!ap_checkmask(buffer, "HTTP/#.# ###*")) {
+ /* Nope, it wasn't even an extra HTTP header. Give up. */
+ return NULL;
+ }
+
+ ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r->server,
+ "proxy: Ignoring duplicate HTTP header "
+ "returned by %s (%s)", r->uri, r->method);
+ continue;
+ }
*value = '\0';
++value;
- /* XXX: RFC2068 defines only SP and HT as whitespace, this test is
- * wrong... and so are many others probably.
- */
+ /* XXX: RFC2068 defines only SP and HT as whitespace, this test is
+ * wrong... and so are many others probably.
+ */
while (ap_isspace(*value))
++value; /* Skip to start of value */
- /* should strip trailing whitespace as well */
- for (end = &value[strlen(value)-1]; end > value && ap_isspace(*end); --end)
- *end = '\0';
+ /* should strip trailing whitespace as well */
+ for (end = &value[strlen(value)-1]; end > value && ap_isspace(*end); --end)
+ *end = '\0';
ap_table_add(resp_hdrs, buffer, value);
- /* the header was too long; at the least we should skip extra data */
- if (len >= size - 1) {
- while ((len = proxy_getline(field, MAX_STRING_LEN, f, 1))
- >= MAX_STRING_LEN - 1) {
- /* soak up the extra data */
- }
- if (len == 0) /* time to exit the larger loop as well */
- break;
- }
+ /* the header was too long; at the least we should skip extra data */
+ if (len >= size - 1) {
+ while ((len = proxy_getline(field, MAX_STRING_LEN, f, 1))
+ >= MAX_STRING_LEN - 1) {
+ /* soak up the extra data */
+ }
+ if (len == 0) /* time to exit the larger loop as well */
+ break;
+ }
}
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;
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;
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;
- if (c != NULL)
- c->written = 0;
+ if (c) ap_cache_el_data(c, &cachefp);
#ifdef CHARSET_EBCDIC
/* The cache copy is ASCII, not EBCDIC, even for text/html) */
ap_bsetflag(f, B_ASCII2EBCDIC|B_EBCDIC2ASCII, 0);
if (c != NULL && c->fp != NULL)
- ap_bsetflag(c->fp, B_ASCII2EBCDIC|B_EBCDIC2ASCII, 0);
+ ap_bsetflag(c->fp, B_ASCII2EBCDIC|B_EBCDIC2ASCII, 0);
ap_bsetflag(con->client, B_ASCII2EBCDIC|B_EBCDIC2ASCII, 0);
#endif
* 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;
}
#endif
* or (after the client aborted) while we can successfully
* read and finish the configured cache_completion.
*/
- for (ok = 1; ok; ) {
- /* Read block from server */
- n = ap_bread(f, buf, IOBUFSIZE);
-
- if (n == -1) { /* input error */
- if (c != NULL) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
- "proxy: error reading from %s", c->url);
- c = ap_proxy_cache_error(c);
- }
- break;
- }
- if (n == 0)
- break; /* EOF */
- o = 0;
- total_bytes_rcvd += n;
-
- /* Write to cache first. */
- /*@@@ XXX FIXME: Assuming that writing the cache file won't time out?!!? */
- if (c != NULL && c->fp != NULL) {
- if (ap_bwrite(c->fp, &buf[0], n) != n) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
- "proxy: error writing to %s", c->tempfile);
- c = ap_proxy_cache_error(c);
- } else {
- c->written += n;
+ for (ok = 1; ok; cntr=0) {
+ /* Read block from server */
+ if(ap_bread(f, buf, IOBUFSIZE, &cntr) != APR_SUCCESS && !cntr)
+ {
+ if (c != NULL) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "proxy: error reading from %s", c->name);
+ ap_proxy_cache_error(&c);
}
+ break;
+ }
+ else if(cntr == 0) break;
+
+
+ /* Write to cache first. */
+ /*@@@ XXX FIXME: Assuming that writing the cache file won't time out?!!? */
+ if (cachefp && ap_bwrite(cachefp, &buf[0], cntr, &wrote_to_cache) != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "proxy: error writing to cache");
+ ap_proxy_cache_error(&c);
+ cachefp = NULL;
+ } else {
+ written += n;
}
- /* Write the block to the client, detect aborted transfers */
- while (!con->aborted && n > 0) {
- w = ap_bwrite(con->client, &buf[o], n);
+ o = 0;
+ total_bytes_rcvd += cntr;
+ in_buffer = cntr;
- if (w <= 0) {
- if (c != NULL && c->fp != NULL) {
+ /* Write the block to the client, detect aborted transfers */
+ while (!con->aborted && in_buffer > 0) {
+ if (ap_bwrite(con->client, &buf[o], in_buffer, &cntr) != APR_SUCCESS) {
+ if (completion) {
/* when a send failure occurs, we need to decide
* whether to continue loading and caching the
* document, or to abort the whole thing
*/
- ok = (c->len > 0) &&
- (c->cache_completion > 0) &&
- (c->len * c->cache_completion < total_bytes_rcvd);
-
- if (! ok) {
- ap_pclosef(c->req->pool, c->fp->fd);
- c->fp = NULL;
- unlink(c->tempfile);
- c = NULL;
- }
+ ok = (completion->content_length > 0) &&
+ (completion->cache_completion > 0) &&
+ (completion->content_length * completion->cache_completion < total_bytes_rcvd);
+
+ if (!ok)
+ ap_proxy_cache_error(&c);
}
con->aborted = 1;
break;
}
- n -= w;
- o += w;
+ in_buffer -= cntr;
+ o += cntr;
} /* while client alive and more data to send */
} /* loop and ap_bread while "ok" */
if (!con->aborted)
- ap_bflush(con->client);
+ ap_bflush(con->client);
return total_bytes_rcvd;
}
{
int i;
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);
for (i = 0; i < ap_table_elts(t)->nelts; ++i) {
- if (elts[i].key != NULL) {
- ap_bvputs(fp, elts[i].key, ": ", elts[i].val, CRLF, NULL);
- ap_table_addn(r->headers_out, elts[i].key, elts[i].val);
- }
+ if (elts[i].key != NULL) {
+ ap_bvputs(fp, elts[i].key, ": ", elts[i].val, CRLF, NULL);
+ ap_table_addn(r->headers_out, elts[i].key, elts[i].val);
+ }
}
ap_bputs(CRLF, fp);
len = strlen(val);
while (list != NULL) {
- p = strchr(list, ',');
- if (p != NULL) {
- i = p - list;
- do
- p++;
- while (ap_isspace(*p));
- }
- else
- i = strlen(list);
-
- while (i > 0 && ap_isspace(list[i - 1]))
- i--;
- if (i == len && strncasecmp(list, val, len) == 0)
- return 1;
- list = p;
- }
- 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];
+ p = strchr(list, ',');
+ if (p != NULL) {
+ i = p - list;
+ do
+ p++;
+ while (ap_isspace(*p));
}
-/* 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);
+ else
+ i = strlen(list);
-/* 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;
+ while (i > 0 && ap_isspace(list[i - 1]))
+ i--;
+ if (i == len && strncasecmp(list, val, len) == 0)
+ return 1;
+ list = p;
}
- memcpy(&val[i], &tmp[k], 22 - k);
- val[i + 22 - k] = '\0';
+ return 0;
}
-#endif /* CASE_BLIND_FILESYSTEM */
/*
* Converts 8 hex digits to a time integer
unsigned int j;
for (i = 0, j = 0; i < 8; i++) {
- ch = x[i];
- j <<= 4;
- if (ap_isdigit(ch))
- j |= ch - '0';
- else if (ap_isupper(ch))
- j |= ch - ('A' - 10);
- else
- j |= ch - ('a' - 10);
+ ch = x[i];
+ j <<= 4;
+ if (ap_isdigit(ch))
+ j |= ch - '0';
+ else if (ap_isupper(ch))
+ j |= ch - ('A' - 10);
+ else
+ j |= ch - ('a' - 10);
}
if (j == 0xffffffff)
- return -1; /* so that it works with 8-byte ints */
+ return -1; /* so that it works with 8-byte ints */
else
- return j;
+ return j;
}
/*
unsigned int j = t;
for (i = 7; i >= 0; i--) {
- ch = j & 0xF;
- j >>= 4;
- if (ch >= 10)
- y[i] = ch + ('A' - 10);
- else
- y[i] = ch + '0';
+ ch = j & 0xF;
+ j >>= 4;
+ if (ch >= 10)
+ y[i] = ch + ('A' - 10);
+ else
+ y[i] = ch + '0';
}
y[8] = '\0';
}
-cache_req *ap_proxy_cache_error(cache_req *c)
+void ap_proxy_cache_error(ap_cache_el **c)
{
- if (c != NULL) {
- if (c->fp != NULL) {
- ap_pclosef(c->req->pool, c->fp->fd);
- c->fp = NULL;
- }
- if (c->tempfile) unlink(c->tempfile);
+ if (c && *c) {
+ const char *name = (*c)->name;
+ ap_cache_el_finalize((*c));
+ ap_cache_remove((*c)->cache, name);
+ *c = NULL;
}
- return NULL;
}
int ap_proxyerror(request_rec *r, int statuscode, const char *message)
{
ap_table_setn(r->notes, "error-notes",
- ap_pstrcat(r->pool,
- "The proxy server could not handle the request "
- "<EM><A HREF=\"", ap_escape_uri(r->pool, r->uri),
- "\">", ap_escape_html(r->pool, r->method),
- " ",
- ap_escape_html(r->pool, r->uri), "</A></EM>.<P>\n"
- "Reason: <STRONG>",
- ap_escape_html(r->pool, message),
- "</STRONG>", NULL));
+ ap_pstrcat(r->pool,
+ "The proxy server could not handle the request "
+ "<EM><A HREF=\"", ap_escape_uri(r->pool, r->uri),
+ "\">", ap_escape_html(r->pool, r->method),
+ " ",
+ ap_escape_html(r->pool, r->uri), "</A></EM>.<P>\n"
+ "Reason: <STRONG>",
+ ap_escape_html(r->pool, message),
+ "</STRONG>", NULL));
/* Allow "error-notes" string to be printed by ap_send_error_response() */
ap_table_setn(r->notes, "verbose-error-to", ap_pstrdup(r->pool, "*"));
/*
* This routine returns its own error message
*/
-const char *
- ap_proxy_host2addr(const char *host, struct hostent *reqhp)
+const char *ap_proxy_host2addr(const char *host, struct hostent *reqhp)
{
int i;
struct hostent *hp;
static APACHE_TLS char *charpbuf[2];
for (i = 0; host[i] != '\0'; i++)
- if (!ap_isdigit(host[i]) && host[i] != '.')
- break;
+ if (!ap_isdigit(host[i]) && host[i] != '.')
+ break;
if (host[i] != '\0') {
- hp = gethostbyname(host);
- if (hp == NULL)
- return "Host not found";
+ hp = gethostbyname(host);
+ if (hp == NULL)
+ return "Host not found";
}
else {
- ipaddr = ap_inet_addr(host);
- hp = gethostbyaddr((char *) &ipaddr, sizeof(u_long), AF_INET);
- if (hp == NULL) {
- memset(&hpbuf, 0, sizeof(hpbuf));
- hpbuf.h_name = 0;
- hpbuf.h_addrtype = AF_INET;
- hpbuf.h_length = sizeof(u_long);
- hpbuf.h_addr_list = charpbuf;
- hpbuf.h_addr_list[0] = (char *) &ipaddr;
- hpbuf.h_addr_list[1] = 0;
- hp = &hpbuf;
- }
+ ipaddr = ap_inet_addr(host);
+ hp = gethostbyaddr((char *) &ipaddr, sizeof(u_long), AF_INET);
+ if (hp == NULL) {
+ memset(&hpbuf, 0, sizeof(hpbuf));
+ hpbuf.h_name = 0;
+ hpbuf.h_addrtype = AF_INET;
+ hpbuf.h_length = sizeof(u_long);
+ hpbuf.h_addr_list = charpbuf;
+ hpbuf.h_addr_list[0] = (char *) &ipaddr;
+ hpbuf.h_addr_list[1] = 0;
+ hp = &hpbuf;
+ }
}
*reqhp = *hp;
return NULL;
int port = -1;
if (r->hostname != NULL)
- return r->hostname;
+ return r->hostname;
/* Set url to the first char after "scheme://" */
if ((url = strchr(r->uri, ':')) == NULL
- || url[1] != '/' || url[2] != '/')
- return NULL;
+ || url[1] != '/' || url[2] != '/')
+ return NULL;
- url = ap_pstrdup(r->pool, &url[1]); /* make it point to "//", which is what proxy_canon_netloc expects */
+ url = ap_pstrdup(r->pool, &url[1]); /* make it point to "//", which is what proxy_canon_netloc expects */
err = ap_proxy_canon_netloc(r->pool, &url, &user, &password, &host, &port);
if (err != NULL)
- ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, r,
- "%s", err);
+ ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, r,
+ "%s", err);
r->hostname = host;
- return host; /* ought to return the port, too */
+ return host; /* ought to return the port, too */
}
/* Return TRUE if addr represents an IP address (or an IP network address) */
/* Iterate over up to 4 (dotted) quads. */
for (quads = 0; quads < 4 && *addr != '\0'; ++quads) {
- char *tmp;
+ char *tmp;
- if (*addr == '/' && quads > 0) /* netmask starts here. */
- break;
+ if (*addr == '/' && quads > 0) /* netmask starts here. */
+ break;
- if (!ap_isdigit(*addr))
- return 0; /* no digit at start of quad */
+ if (!ap_isdigit(*addr))
+ return 0; /* no digit at start of quad */
- ip_addr[quads] = strtol(addr, &tmp, 0);
+ ip_addr[quads] = strtol(addr, &tmp, 0);
- if (tmp == addr) /* expected a digit, found something else */
- return 0;
+ if (tmp == addr) /* expected a digit, found something else */
+ return 0;
- if (ip_addr[quads] < 0 || ip_addr[quads] > 255) {
- /* invalid octet */
- return 0;
- }
+ if (ip_addr[quads] < 0 || ip_addr[quads] > 255) {
+ /* invalid octet */
+ return 0;
+ }
- addr = tmp;
+ addr = tmp;
- if (*addr == '.' && quads != 3)
- ++addr; /* after the 4th quad, a dot would be illegal */
+ if (*addr == '.' && quads != 3)
+ ++addr; /* after the 4th quad, a dot would be illegal */
}
for (This->addr.s_addr = 0, i = 0; i < quads; ++i)
- This->addr.s_addr |= htonl(ip_addr[i] << (24 - 8 * i));
+ This->addr.s_addr |= htonl(ip_addr[i] << (24 - 8 * i));
- if (addr[0] == '/' && ap_isdigit(addr[1])) { /* net mask follows: */
- char *tmp;
+ if (addr[0] == '/' && ap_isdigit(addr[1])) { /* net mask follows: */
+ char *tmp;
- ++addr;
+ ++addr;
- bits = strtol(addr, &tmp, 0);
+ bits = strtol(addr, &tmp, 0);
- if (tmp == addr) /* expected a digit, found something else */
- return 0;
+ if (tmp == addr) /* expected a digit, found something else */
+ return 0;
- addr = tmp;
+ addr = tmp;
- if (bits < 0 || bits > 32) /* netmask must be between 0 and 32 */
- return 0;
+ if (bits < 0 || bits > 32) /* netmask must be between 0 and 32 */
+ return 0;
}
else {
- /* Determine (i.e., "guess") netmask by counting the */
- /* number of trailing .0's; reduce #quads appropriately */
- /* (so that 192.168.0.0 is equivalent to 192.168.) */
- while (quads > 0 && ip_addr[quads - 1] == 0)
- --quads;
+ /* Determine (i.e., "guess") netmask by counting the */
+ /* number of trailing .0's; reduce #quads appropriately */
+ /* (so that 192.168.0.0 is equivalent to 192.168.) */
+ while (quads > 0 && ip_addr[quads - 1] == 0)
+ --quads;
- /* "IP Address should be given in dotted-quad form, optionally followed by a netmask (e.g., 192.168.111.0/24)"; */
- if (quads < 1)
- return 0;
+ /* "IP Address should be given in dotted-quad form, optionally followed by a netmask (e.g., 192.168.111.0/24)"; */
+ if (quads < 1)
+ return 0;
- /* every zero-byte counts as 8 zero-bits */
- bits = 8 * quads;
+ /* every zero-byte counts as 8 zero-bits */
+ bits = 8 * quads;
- if (bits != 32) /* no warning for fully qualified IP address */
- ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
+ if (bits != 32) /* no warning for fully qualified IP address */
+ ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
"Warning: NetMask not supplied with IP-Addr; guessing: %s/%ld",
- inet_ntoa(This->addr), bits);
+ inet_ntoa(This->addr), bits);
}
This->mask.s_addr = htonl(INADDR_NONE << (32 - bits));
if (*addr == '\0' && (This->addr.s_addr & ~This->mask.s_addr) != 0) {
- ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, "Warning: NetMask and IP-Addr disagree in %s/%ld\n",
- inet_ntoa(This->addr), bits);
- This->addr.s_addr &= This->mask.s_addr;
- ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
+ ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, "Warning: NetMask and IP-Addr disagree in %s/%ld\n",
+ inet_ntoa(This->addr), bits);
+ This->addr.s_addr &= This->mask.s_addr;
+ ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
" Set to %s/%ld",
- inet_ntoa(This->addr), bits);
+ inet_ntoa(This->addr), bits);
}
if (*addr == '\0') {
- This->matcher = proxy_match_ipaddr;
- return 1;
+ This->matcher = proxy_match_ipaddr;
+ return 1;
}
else
- return (*addr == '\0'); /* okay iff we've parsed the whole string */
+ return (*addr == '\0'); /* okay iff we've parsed the whole string */
}
/* Return TRUE if addr represents an IP address (or an IP network address) */
memset(ip_addr, '\0', sizeof ip_addr);
if (4 == sscanf(host, "%d.%d.%d.%d", &ip_addr[0], &ip_addr[1], &ip_addr[2], &ip_addr[3])) {
- for (addr.s_addr = 0, i = 0; i < 4; ++i)
- addr.s_addr |= htonl(ip_addr[i] << (24 - 8 * i));
+ for (addr.s_addr = 0, i = 0; i < 4; ++i)
+ addr.s_addr |= htonl(ip_addr[i] << (24 - 8 * i));
- if (This->addr.s_addr == (addr.s_addr & This->mask.s_addr)) {
+ if (This->addr.s_addr == (addr.s_addr & This->mask.s_addr)) {
#if DEBUGGING
- ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
+ ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
"1)IP-Match: %s[%s] <-> ", host, inet_ntoa(addr));
- ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
+ ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
"%s/", inet_ntoa(This->addr));
- ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
+ ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
"%s", inet_ntoa(This->mask));
#endif
- return 1;
- }
+ return 1;
+ }
#if DEBUGGING
- else {
- ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
+ else {
+ ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
"1)IP-NoMatch: %s[%s] <-> ", host, inet_ntoa(addr));
- ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
+ ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
"%s/", inet_ntoa(This->addr));
- ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
+ ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
"%s", inet_ntoa(This->mask));
- }
+ }
#endif
}
else {
- struct hostent the_host;
+ struct hostent the_host;
- memset(&the_host, '\0', sizeof the_host);
- found = ap_proxy_host2addr(host, &the_host);
+ memset(&the_host, '\0', sizeof the_host);
+ found = ap_proxy_host2addr(host, &the_host);
- if (found != NULL) {
+ if (found != NULL) {
#if DEBUGGING
- ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
+ ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
"2)IP-NoMatch: hostname=%s msg=%s", host, found);
#endif
- return 0;
- }
-
- if (the_host.h_name != NULL)
- found = the_host.h_name;
- else
- found = host;
-
- /* Try to deal with multiple IP addr's for a host */
- for (ip_listptr = the_host.h_addr_list; *ip_listptr; ++ip_listptr) {
- ip_list = (struct in_addr *) *ip_listptr;
- if (This->addr.s_addr == (ip_list->s_addr & This->mask.s_addr)) {
+ return 0;
+ }
+
+ if (the_host.h_name != NULL)
+ found = the_host.h_name;
+ else
+ found = host;
+
+ /* Try to deal with multiple IP addr's for a host */
+ for (ip_listptr = the_host.h_addr_list; *ip_listptr; ++ip_listptr) {
+ ip_list = (struct in_addr *) *ip_listptr;
+ if (This->addr.s_addr == (ip_list->s_addr & This->mask.s_addr)) {
#if DEBUGGING
- ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
+ ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
"3)IP-Match: %s[%s] <-> ", found, inet_ntoa(*ip_list));
- ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
+ ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
"%s/", inet_ntoa(This->addr));
- ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
+ ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
"%s", inet_ntoa(This->mask));
#endif
- return 1;
- }
+ return 1;
+ }
#if DEBUGGING
- else {
- ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
+ else {
+ ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
"3)IP-NoMatch: %s[%s] <-> ", found, inet_ntoa(*ip_list));
- ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
+ ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
"%s/", inet_ntoa(This->addr));
- ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
+ ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
"%s", inet_ntoa(This->mask));
- }
+ }
#endif
- }
+ }
}
return 0;
/* Domain name must start with a '.' */
if (addr[0] != '.')
- return 0;
+ return 0;
/* rfc1035 says DNS names must consist of "[-a-zA-Z0-9]" and '.' */
for (i = 0; ap_isalnum(addr[i]) || addr[i] == '-' || addr[i] == '.'; ++i)
- continue;
+ continue;
#if 0
if (addr[i] == ':') {
- ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
+ ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
"@@@@ handle optional port in proxy_is_domainname()");
- /* @@@@ handle optional port */
+ /* @@@@ handle optional port */
}
#endif
if (addr[i] != '\0')
- return 0;
+ return 0;
/* Strip trailing dots */
for (i = strlen(addr) - 1; i > 0 && addr[i] == '.'; --i)
- addr[i] = '\0';
+ addr[i] = '\0';
This->matcher = proxy_match_domainname;
return 1;
const char *host = proxy_get_host_of_request(r);
int d_len = strlen(This->name), h_len;
- if (host == NULL) /* some error was logged already */
- return 0;
+ if (host == NULL) /* some error was logged already */
+ return 0;
h_len = strlen(host);
/* @@@ do this within the setup? */
/* Ignore trailing dots in domain comparison: */
while (d_len > 0 && This->name[d_len - 1] == '.')
- --d_len;
+ --d_len;
while (h_len > 0 && host[h_len - 1] == '.')
- --h_len;
+ --h_len;
return h_len > d_len
- && strncasecmp(&host[h_len - d_len], This->name, d_len) == 0;
+ && strncasecmp(&host[h_len - d_len], This->name, d_len) == 0;
}
/* Return TRUE if addr represents a host name */
/* Host names must not start with a '.' */
if (addr[0] == '.')
- return 0;
+ return 0;
/* rfc1035 says DNS names must consist of "[-a-zA-Z0-9]" and '.' */
for (i = 0; ap_isalnum(addr[i]) || addr[i] == '-' || addr[i] == '.'; ++i);
#if 0
if (addr[i] == ':') {
- ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
+ ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
"@@@@ handle optional port in proxy_is_hostname()");
- /* @@@@ handle optional port */
+ /* @@@@ handle optional port */
}
#endif
if (addr[i] != '\0' || ap_proxy_host2addr(addr, &host) != NULL)
- return 0;
+ return 0;
This->hostentry = ap_pduphostent (p, &host);
/* Strip trailing dots */
for (i = strlen(addr) - 1; i > 0 && addr[i] == '.'; --i)
- addr[i] = '\0';
+ addr[i] = '\0';
This->matcher = proxy_match_hostname;
return 1;
/* Try to deal with multiple IP addr's for a host */
for (ip_list = *This->hostentry->h_addr_list; *ip_list != 0UL; ++ip_list)
- if (*ip_list == ? ? ? ? ? ? ? ? ? ? ? ? ?)
- return 1;
+ if (*ip_list == ? ? ? ? ? ? ? ? ? ? ? ? ?)
+ return 1;
#endif
/* Ignore trailing dots in host2 comparison: */
while (h2_len > 0 && host2[h2_len - 1] == '.')
- --h2_len;
+ --h2_len;
while (h1_len > 0 && host[h1_len - 1] == '.')
- --h1_len;
+ --h1_len;
return h1_len == h2_len
- && strncasecmp(host, host2, h1_len) == 0;
+ && strncasecmp(host, host2, h1_len) == 0;
}
/* Return TRUE if addr is to be matched as a word */
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;
+ for (i = 0; host[i] != '\0'; i++)
+ if (!ap_isdigit(host[i]) && host[i] != '.')
+ break;
- do {
- i = connect(sock, (struct sockaddr *) addr, sizeof(struct sockaddr_in));
-#ifdef WIN32
- if (i == SOCKET_ERROR)
- 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));
+ ap_set_remote_port(sock, port);
+ if (host[i] == '\0') {
+ ap_set_remote_ipaddr(sock, host);
+ host = NULL;
}
-
- return i;
+ for(;;)
+ {
+ 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 */
/* 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)
{
- 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')
- return 1;
- if (!parm->req->assbackwards)
- ap_rvputs(parm->req, 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;
+ if (!r->assbackwards)
+ ap_rvputs(r, key, ": ", value, CRLF, NULL);
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 */
-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);
- if (cache != NULL && cache->fp != NULL)
- ap_bputs(data, cache->fp);
+ BUFF *cachefp = NULL;
+
+ if (ap_cache_el_data(cache, &cachefp) == APR_SUCCESS)
+ ap_bputs(data, cachefp);
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;
+}