diff --git a/modules/proxy/Makefile.in b/modules/proxy/Makefile.in new file mode 100644 index 0000000000..b6a0fc991f --- /dev/null +++ b/modules/proxy/Makefile.in @@ -0,0 +1,5 @@ + +LTLIBRARY_NAME = libapachemod_proxy.la +LTLIBRARY_SOURCES = mod_proxy.lo proxy_connect.lo proxy_ftp.lo proxy_http.lo proxy_util.lo + +include $(top_srcdir)/build/ltlib.mk diff --git a/modules/proxy/config.m4 b/modules/proxy/config.m4 new file mode 100644 index 0000000000..f6d5efdf71 --- /dev/null +++ b/modules/proxy/config.m4 @@ -0,0 +1,32 @@ +dnl modules enabled in this directory by default + +dnl AC_DEFUN(modulename, modulestructname, defaultonoroff, configmacros) +dnl XXX - Need to add help text to --enable-module flags +dnl XXX - Need to allow --enable-module to fail if optional config fails + +AC_DEFUN(APACHE_CHECK_PROXY_MODULE, [ + APACHE_MODULE($1,,,$2,$3,$4) +]) + +APACHE_MODPATH_INIT(proxy) + +APACHE_CHECK_PROXY_MODULE(proxy, , yes) + +dnl APACHE_CHECK_STANDARD_MODULE(auth_db, , no, [ +dnl AC_CHECK_HEADERS(db.h) +dnl AC_CHECK_LIB(db,main) +dnl ]) + +dnl APACHE_CHECK_STANDARD_MODULE(usertrack, , no, [ +dnl AC_CHECK_HEADERS(sys/times.h) +dnl AC_CHECK_FUNCS(times) +dnl ]) + +APACHE_MODPATH_FINISH + +if test "$sharedobjs" = "yes"; then + LIBS="$LIBS -ldl" + LTFLAGS="$LTFLAGS -export-dynamic" +fi + +APACHE_SUBST(STANDARD_LIBS) diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c index 1d086f3000..773d019e86 100644 --- a/modules/proxy/mod_proxy.c +++ b/modules/proxy/mod_proxy.c @@ -63,6 +63,7 @@ #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 */ @@ -76,7 +77,7 @@ static struct proxy_services defports[] = {"wais", DEFAULT_WAIS_PORT}, {"snews", DEFAULT_SNEWS_PORT}, {"prospero", DEFAULT_PROSPERO_PORT}, - {NULL, -1} /* unknown port */ + {NULL, -1} /* unknown port */ }; /* @@ -98,29 +99,29 @@ static int alias_match(const char *uri, const char *alias_fakename) 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; + 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; - } + 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 @@ -149,25 +150,25 @@ static int proxy_detect(request_rec *r) 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; } @@ -181,10 +182,10 @@ static int proxy_trans(request_rec *r) 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 @@ -194,14 +195,14 @@ static int proxy_trans(request_rec *r) 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; } @@ -217,36 +218,30 @@ static int proxy_fixup(request_rec *r) 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; @@ -254,29 +249,29 @@ static int proxy_needsdomain(request_rec *r, const char *url, const char *domain /* 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; } @@ -288,51 +283,99 @@ static int proxy_handler(request_rec *r) { 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; + 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 (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; + return HTTP_BAD_REQUEST; - rc = ap_proxy_cache_check(r, url, &conf->cache, &cr); - if (rc != DECLINED) - return rc; + 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'; @@ -344,47 +387,47 @@ static int proxy_handler(request_rec *r) /* 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; + 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 */ - } - } + /* 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 @@ -392,20 +435,19 @@ static int proxy_handler(request_rec *r) */ /* 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)); @@ -416,21 +458,12 @@ static void * 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; } @@ -446,26 +479,26 @@ static const char * 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); @@ -476,6 +509,36 @@ static const char * 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) { @@ -505,8 +568,7 @@ static const char * 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 = @@ -519,19 +581,19 @@ static const char * /* 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; } @@ -548,7 +610,7 @@ static const char * 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); @@ -571,44 +633,44 @@ static const char * /* 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; } @@ -620,7 +682,7 @@ static const char * 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; @@ -637,146 +699,6 @@ static const char * } -static const char * - set_cache_size(cmd_parms *parms, char *struct_ptr, char *arg) -{ - proxy_server_conf *psf = - ap_get_module_config(parms->server->module_config, &proxy_module); - int val; - - if (sscanf(arg, "%d", &val) != 1) - return "CacheSize value must be an integer (kBytes)"; - psf->cache.space = val; - return NULL; -} - -static const char * - set_cache_root(cmd_parms *parms, void *dummy, char *arg) -{ - proxy_server_conf *psf = - ap_get_module_config(parms->server->module_config, &proxy_module); - - psf->cache.root = arg; - - return NULL; -} - -static const char * - set_cache_factor(cmd_parms *parms, void *dummy, char *arg) -{ - proxy_server_conf *psf = - ap_get_module_config(parms->server->module_config, &proxy_module); - double val; - - if (sscanf(arg, "%lg", &val) != 1) - return "CacheLastModifiedFactor value must be a float"; - psf->cache.lmfactor = val; - - return NULL; -} - -static const char * - set_cache_maxex(cmd_parms *parms, void *dummy, char *arg) -{ - proxy_server_conf *psf = - ap_get_module_config(parms->server->module_config, &proxy_module); - double val; - - if (sscanf(arg, "%lg", &val) != 1) - return "CacheMaxExpire value must be a float"; - psf->cache.maxexpire = (int) (val * (double) SEC_ONE_HR); - return NULL; -} - -static const char * - set_cache_defex(cmd_parms *parms, void *dummy, char *arg) -{ - proxy_server_conf *psf = - ap_get_module_config(parms->server->module_config, &proxy_module); - double val; - - if (sscanf(arg, "%lg", &val) != 1) - return "CacheDefaultExpire value must be a float"; - psf->cache.defaultexpire = (int) (val * (double) SEC_ONE_HR); - return NULL; -} - -static const char * - set_cache_gcint(cmd_parms *parms, void *dummy, char *arg) -{ - proxy_server_conf *psf = - ap_get_module_config(parms->server->module_config, &proxy_module); - double val; - - if (sscanf(arg, "%lg", &val) != 1) - return "CacheGcInterval value must be a float"; - psf->cache.gcinterval = (int) (val * (double) SEC_ONE_HR); - return NULL; -} - -static const char * - set_cache_dirlevels(cmd_parms *parms, char *struct_ptr, char *arg) -{ - proxy_server_conf *psf = - ap_get_module_config(parms->server->module_config, &proxy_module); - int val; - - val = atoi(arg); - if (val < 1) - return "CacheDirLevels value must be an integer greater than 0"; - if (val * psf->cache.dirlength > CACHEFILE_LEN) - return "CacheDirLevels*CacheDirLength value must not be higher than 20"; - psf->cache.dirlevels = val; - return NULL; -} - -static const char * - set_cache_dirlength(cmd_parms *parms, char *struct_ptr, char *arg) -{ - proxy_server_conf *psf = - ap_get_module_config(parms->server->module_config, &proxy_module); - int val; - - val = atoi(arg); - if (val < 1) - return "CacheDirLength value must be an integer greater than 0"; - if (val * psf->cache.dirlevels > CACHEFILE_LEN) - return "CacheDirLevels*CacheDirLength value must not be higher than 20"; - psf->cache.dirlength = val; - return NULL; -} - -static const char * - set_cache_exclude(cmd_parms *parms, void *dummy, char *arg) -{ - server_rec *s = parms->server; - proxy_server_conf *conf = - ap_get_module_config(s->module_config, &proxy_module); - struct nocache_entry *new; - struct nocache_entry *list = (struct nocache_entry *) conf->nocaches->elts; - struct hostent hp; - int found = 0; - int i; - - /* Don't duplicate entries */ - for (i = 0; i < conf->nocaches->nelts; i++) { - if (strcasecmp(arg, list[i].name) == 0) /* ignore case for host names */ - found = 1; - } - - if (!found) { - new = ap_push_array(conf->nocaches); - new->name = arg; - /* Don't do name lookups on things that aren't dotted */ - if (strchr(arg, '.') != NULL && ap_proxy_host2addr(new->name, &hp) == NULL) - /*@@@FIXME: This copies only the first of (possibly many) IP addrs */ - memcpy(&new->addr, hp.h_addr, sizeof(struct in_addr)); - else - new->addr.s_addr = 0; - } - return NULL; -} - static const char * set_recv_buffer_size(cmd_parms *parms, void *dummy, char *arg) { @@ -784,34 +706,17 @@ static const char * 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; @@ -822,13 +727,28 @@ static const char* 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}, @@ -855,50 +775,34 @@ static const command_rec proxy_cmds[] = "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 }; diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h index 7d0a5753ea..abda37568a 100644 --- a/modules/proxy/mod_proxy.h +++ b/modules/proxy/mod_proxy.h @@ -75,13 +75,13 @@ 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 30 Mar 96 @@ -103,12 +103,13 @@ */ -#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" @@ -120,27 +121,25 @@ enum enctype { 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; @@ -149,10 +148,10 @@ struct proxy_services { /* 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 { @@ -177,27 +176,7 @@ struct nocache_entry { 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; @@ -205,8 +184,10 @@ typedef struct { 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, @@ -214,97 +195,60 @@ typedef struct { 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*/ diff --git a/modules/proxy/proxy_connect.c b/modules/proxy/proxy_connect.c index b87d81b9ac..db7d3a0966 100644 --- a/modules/proxy/proxy_connect.c +++ b/modules/proxy/proxy_connect.c @@ -61,13 +61,12 @@ #include "mod_proxy.h" #include "http_log.h" #include "http_main.h" +#include "iol_socket.h" #ifdef HAVE_BSTRING_H -#include /* for IRIX, FD_SET calls bzero() */ +#include /* 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 @@ -105,187 +104,195 @@ allowed_port(proxy_server_conf *conf, int port) 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); + ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL, + "CONNECT to %s on port %d", host, port); } - server.sin_port = (proxyport ? htons(proxyport) : htons(port)); - 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; + 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; } -#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; - } -#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:
", - 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:
", + 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 (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; + 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; } - ap_pclosesocket(r->pool, sock); + /* 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_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; } diff --git a/modules/proxy/proxy_ftp.c b/modules/proxy/proxy_ftp.c index 8b2e6ec086..301bffeb62 100644 --- a/modules/proxy/proxy_ftp.c +++ b/modules/proxy/proxy_ftp.c @@ -62,10 +62,18 @@ #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 @@ -75,15 +83,15 @@ static int decodeenc(char *x) 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; @@ -98,17 +106,17 @@ static int ftp_check_string(const char *x) 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; } @@ -126,11 +134,11 @@ int ap_proxy_ftp_canon(request_rec *r, char *url) 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 @@ -140,48 +148,48 @@ int ap_proxy_ftp_canon(request_rec *r, char *url) */ 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; } @@ -197,30 +205,30 @@ static int ftp_getrc(BUFF *f) 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; @@ -235,39 +243,39 @@ static int ftp_getrc_msg(BUFF *f, char *msgbuf, int msglen) 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]; @@ -275,11 +283,15 @@ static long int send_dir(BUFF *f, request_rec *r, cache_req *c, char *cwd) 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 */ @@ -289,117 +301,118 @@ static long int send_dir(BUFF *f, request_rec *r, cache_req *c, char *cwd) /* 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 - "%s%s\n" - "\n" - "

Directory of " - "%s/", - site, path, site, path, site); + "%s%s\n" + "\n" + "

Directory of " + "%s/", + 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), "%s/", 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), "%s/", 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), "

\n
");
+    ap_snprintf(buf, sizeof(buf), "\n
");
     } else {
-	ap_snprintf(buf, sizeof(buf), "\n(%s)\n
", cwd);
+    ap_snprintf(buf, sizeof(buf), "\n(%s)\n
", 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;
+    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 %s %s\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 = ']';
-	    }
+        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 %s %s\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;
+        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];
-	    }
+        /* 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 %s\n",
-		    buf, filename, filename);
-	    }
-	    else {
-		ap_snprintf(buf2, sizeof(buf2), "%s %s\n", buf, filename, filename);
-	    }
-	    ap_cpystrn(buf, buf2, sizeof(buf));
-	    n = strlen(buf);
-	}
+        /* Special handling for '.' and '..' */
+        if (!strcmp(filename, ".") || !strcmp(filename, "..") || buf[0] == 'd') {
+        ap_snprintf(buf2, sizeof(buf2), "%s %s\n",
+            buf, filename, filename);
+        }
+        else {
+        ap_snprintf(buf2, sizeof(buf2), "%s %s\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("

\n", con->client, c); @@ -425,16 +438,16 @@ static int ftp_unauthorized (request_rec *r, int log_it) * (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; } @@ -445,28 +458,25 @@ static int ftp_unauthorized (request_rec *r, int log_it) * Troy Morrison * 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); @@ -480,8 +490,11 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url) 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; @@ -489,14 +502,14 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url) /* 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] : ""; @@ -509,111 +522,77 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url) * 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'; + *(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 ((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 > 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"); + 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 (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &one, - sizeof(one)) == -1) { + + 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 @@ -625,36 +604,39 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url) /* 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 */ @@ -667,48 +649,51 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url) /* 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): @@ -716,58 +701,61 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url) * machine */ for (;;) { - strp = strchr(path, '/'); - if (strp == NULL) - break; - *strp = '\0'; + 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 = '/'; + 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; - } + } + if (i == 550) { + return HTTP_NOT_FOUND; + } + if (i != 250) { + return HTTP_BAD_GATEWAY; + } - path = strp + 1; + 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. */ @@ -775,40 +763,38 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url) /* 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. */ @@ -818,13 +804,45 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url) /* 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) { @@ -858,8 +876,35 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url) 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)); } @@ -890,27 +935,27 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url) if (setsockopt(dsock, SOL_SOCKET, SO_REUSEADDR, (void *) &one, 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]; + if (ap_bind(dsock) != APR_SUCCESS) { + 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 */ + 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 */ @@ -919,58 +964,64 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url) /* 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 "" */ /* 421 Service not available, closing control connection. */ @@ -979,30 +1030,33 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url) /* 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 @@ -1022,195 +1076,203 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url) /* 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 "" */ - /* 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 "" */ + /* 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; + 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(nocache || !ap_proxy_cache_should_cache(r, resp_hdrs, 0)) + ap_proxy_cache_error(&c); + else + ap_cache_el_data(c, &cachefp); - if (i != DECLINED) { - ap_pclosesocket(p, dsock); - ap_bclose(f); - return i; - } - - 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 (!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 (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); + 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 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. */ @@ -1218,29 +1280,28 @@ int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url) /* 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; } diff --git a/modules/proxy/proxy_http.c b/modules/proxy/proxy_http.c index 71f24c9b70..b4cf2a2809 100644 --- a/modules/proxy/proxy_http.c +++ b/modules/proxy/proxy_http.c @@ -63,6 +63,7 @@ #include "http_main.h" #include "http_core.h" #include "util_date.h" +#include "iol_socket.h" /* * Canonicalise http-like URLs. @@ -82,7 +83,7 @@ int ap_proxy_http_canon(request_rec *r, char *url, const char *scheme, int def_p 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_ @@ -90,25 +91,25 @@ int ap_proxy_http_canon(request_rec *r, char *url, const char *scheme, int def_p * == r->unparsed_uri, and no others have that property. */ 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; } @@ -142,17 +143,17 @@ static void clear_connection(ap_pool_t *p, ap_table_t *headers) 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"); } @@ -166,33 +167,34 @@ static void clear_connection(ap_pool_t *p, ap_table_t *headers) * we return DECLINED so that we can try another proxy. (Or the direct * 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; @@ -204,308 +206,259 @@ int ap_proxy_http_handler(request_rec *r, cache_req *c, char *url, 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 ((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 ((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 > 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 (proxyhost != NULL) { - server.sin_port = htons(proxyport); - err = ap_proxy_host2addr(proxyhost, &server_hp); - if (err != NULL) - return DECLINED; /* try another */ + i = ap_proxy_doconnect(sock, (char *)proxyhost, proxyport, r); } 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); + i = ap_proxy_doconnect(sock, (char *)desthost, destport, r); } - 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) { - 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"); - } - } - -#ifdef SINIX_D_RESOLVER_BUG - { - struct in_addr *ip_addr = (struct in_addr *) *server_hp.h_addr_list; - - for (; ip_addr->s_addr != 0; ++ip_addr) { - memcpy(&server.sin_addr, ip_addr, sizeof(struct in_addr)); - i = ap_proxy_doconnect(sock, &server, r); - if (i == 0) - break; - } - } -#else - j = 0; - while (server_hp.h_addr_list[j] != NULL) { - memcpy(&server.sin_addr, server_hp.h_addr_list[j], - sizeof(struct in_addr)); - i = ap_proxy_doconnect(sock, &server, r); - if (i == 0) - break; - j++; - } -#endif if (i == -1) { - if (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'; + 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]); + 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 (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 ((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, "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 */ + if (ap_cache_el_header(c, "Content-Length", &clen) == APR_SUCCESS) + content_length = atoi(clen ? clen : "-1"); + for (i = 0; i < conf->nocaches->nelts; i++) { - 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; - } - - i = ap_proxy_cache_update(c, resp_hdrs, !backasswards, nocache); - if (i != DECLINED) { - ap_bclose(f); - return 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 @@ -516,19 +469,17 @@ int ap_proxy_http_handler(request_rec *r, cache_req *c, char *url, ap_bsetflag(r->connection->client, B_ASCII2EBCDIC|B_EBCDIC2ASCII, 0); #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; } diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c index 79f346ab96..b2fb14db17 100644 --- a/modules/proxy/proxy_util.c +++ b/modules/proxy/proxy_util.c @@ -62,7 +62,7 @@ #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 @@ -79,20 +79,20 @@ int ap_proxy_hex2c(const char *x) #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; @@ -107,15 +107,15 @@ void ap_proxy_c2hex(int ch, char *x) 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; @@ -141,8 +141,8 @@ char * { 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 @@ -152,51 +152,51 @@ char * * 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; @@ -214,73 +214,73 @@ char * */ 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)"; - } + 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)"; + 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'; + *(strp++) = '\0'; - for (i = 0; strp[i] != '\0'; i++) - if (!ap_isdigit(strp[i])) - break; + 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"; - } + /* 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)) @@ -288,7 +288,7 @@ char * 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) @@ -319,49 +319,49 @@ const char * 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; } @@ -416,7 +416,7 @@ static int proxy_getline(char *s, int n, BUFF *in, int fold) * 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; @@ -430,7 +430,7 @@ static int proxy_getline(char *s, int n, BUFF *in, int fold) * @@@: XXX: FIXME: currently the headers are passed thru un-merged. * 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; @@ -444,71 +444,74 @@ table *ap_proxy_read_headers(request_rec *r, char *buffer, int size, BUFF *f) * the connection closes (EOF), or we timeout. */ while ((len = proxy_getline(buffer, size, f, 1)) > 0) { - - if (!(value = strchr(buffer, ':'))) { /* Find the colon separator */ + + 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 */ + /* 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; - } + 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; - } + 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 @@ -527,7 +530,7 @@ long int ap_proxy_send_fb(BUFF *f, request_rec *r, cache_req *c) * BUT, if we *can't* continue anyway, just use hard_timeout. */ - 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 @@ -536,66 +539,60 @@ long int ap_proxy_send_fb(BUFF *f, request_rec *r, cache_req *c) * 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); + ok = (completion->content_length > 0) && + (completion->cache_completion > 0) && + (completion->content_length * completion->cache_completion < total_bytes_rcvd); - if (! ok) { - ap_pclosef(c->req->pool, c->fp->fd); - c->fp = NULL; - unlink(c->tempfile); - c = NULL; - } + 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; } @@ -611,15 +608,15 @@ void ap_proxy_send_headers(request_rec *r, const char *respline, ap_table_t *t) { 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); @@ -640,127 +637,25 @@ int ap_proxy_liststr(const char *list, const char *val) 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); + 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; + 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]; - } -/* one byte left */ - x = digest[15]; - tmp[k++] = enc_table[x >> 3]; /* use up 5 bits */ - tmp[k++] = enc_table[x & 0x7]; - /* now split into directory levels */ - - for (i = k = d = 0; d < ndepth; ++d) { - memcpy(&val[i], &tmp[k], nlength); - k += nlength; - val[i + nlength] = '/'; - i += nlength + 1; - } - memcpy(&val[i], &tmp[k], 26 - k); - val[i + 26 - k] = '\0'; -} - -#else - -void ap_proxy_hash(const char *it, char *val, int ndepth, int nlength) -{ - ap_md5_ctx_t context; - unsigned char digest[MD5_DIGESTSIZE]; - char tmp[22]; - int i, k, d; - unsigned int x; -#if defined(AIX) && defined(__ps2__) - /* Believe it or not, AIX 1.x does not allow you to name a file '@', - * so hack around it in the encoding. */ - static const char enc_table[64] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_%"; -#else - static const char enc_table[64] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_@"; -#endif - - ap_MD5Init(&context); - ap_MD5Update(&context, (const unsigned char *) it, strlen(it)); - ap_MD5Final(digest, &context); - -/* encode 128 bits as 22 characters, using a modified uuencoding */ -/* the encoding is 3 bytes -> 4 characters - * i.e. 128 bits is 5 x 3 bytes + 1 byte -> 5 * 4 characters + 2 characters - */ - for (i = 0, k = 0; i < 15; i += 3) { - x = (digest[i] << 16) | (digest[i + 1] << 8) | digest[i + 2]; - tmp[k++] = enc_table[x >> 18]; - tmp[k++] = enc_table[(x >> 12) & 0x3f]; - tmp[k++] = enc_table[(x >> 6) & 0x3f]; - tmp[k++] = enc_table[x & 0x3f]; - } -/* one byte left */ - x = digest[15]; - tmp[k++] = enc_table[x >> 2]; /* use up 6 bits */ - tmp[k++] = enc_table[(x << 4) & 0x3f]; - /* now split into directory levels */ - - for (i = k = d = 0; d < ndepth; ++d) { - memcpy(&val[i], &tmp[k], nlength); - k += nlength; - val[i + nlength] = '/'; - i += nlength + 1; - } - memcpy(&val[i], &tmp[k], 22 - k); - val[i + 22 - k] = '\0'; -} - -#endif /* CASE_BLIND_FILESYSTEM */ /* * Converts 8 hex digits to a time integer @@ -771,19 +666,19 @@ int ap_proxy_hex2sec(const char *x) 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; } /* @@ -795,41 +690,39 @@ void ap_proxy_sec2hex(int t, char *y) 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 " - "pool, r->uri), - "\">", ap_escape_html(r->pool, r->method), - " ", - ap_escape_html(r->pool, r->uri), ".

\n" - "Reason: ", - ap_escape_html(r->pool, message), - "", NULL)); + ap_pstrcat(r->pool, + "The proxy server could not handle the request " + "pool, r->uri), + "\">", ap_escape_html(r->pool, r->method), + " ", + ap_escape_html(r->pool, r->uri), ".

\n" + "Reason: ", + ap_escape_html(r->pool, message), + "", 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, "*")); @@ -841,8 +734,7 @@ int ap_proxyerror(request_rec *r, int statuscode, const char *message) /* * 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; @@ -853,27 +745,27 @@ const char * 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; @@ -886,24 +778,24 @@ static const char * 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) */ @@ -928,86 +820,86 @@ int ap_proxy_is_ipaddr(struct dirconn_entry *This, ap_pool_t *p) /* 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) */ @@ -1028,75 +920,75 @@ static int proxy_match_ipaddr(struct dirconn_entry *This, request_rec *r) 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; - } + return 0; + } - if (the_host.h_name != NULL) - found = the_host.h_name; - else - found = host; + 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)) { + /* 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; @@ -1110,26 +1002,26 @@ int ap_proxy_is_domainname(struct dirconn_entry *This, ap_pool_t *p) /* 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; @@ -1141,19 +1033,19 @@ static int proxy_match_domainname(struct dirconn_entry *This, request_rec *r) 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 */ @@ -1165,27 +1057,27 @@ int ap_proxy_is_hostname(struct dirconn_entry *This, ap_pool_t *p) /* 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; @@ -1210,17 +1102,17 @@ static int proxy_match_hostname(struct dirconn_entry *This, request_rec *r) /* 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 */ @@ -1237,24 +1129,32 @@ static int proxy_match_word(struct dirconn_entry *This, request_rec *r) 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 */ @@ -1262,27 +1162,86 @@ int ap_proxy_doconnect(int sock, struct sockaddr_in *addr, request_rec *r) /* It is passed a table_do_args struct pointer and a MIME field and value pair */ 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; +}