Hi. I'm using apache as proxy server to access the internet. Unfortunately, rpm still tries to open a "real" ftp connection for 'ftp://...' urls, even when a proxy is given.
So i modified the openpkg rpm sources. There are two new settings: 'l_force_httpproxy' and 'l_noproxy'. If 'l_force_httpproxy' is set to any value, the http proxy is also used for urls of the form "ftp://...". 'l_noproxy' holds a comma separated list of hosts/domains where no proxy should be used (independent from l_force_httpproxy). Example settings, e.g. in $HOME/.rpmmacros: %_httpproxy myProxy.local.domain %l_force_httpproxy 1 %l_noproxy localhost,local.domain -- Matthias Kurz; Fuldastr. 3; D-28199 Bremen; VOICE +49 421 53 600 47 >> Im prämotorischen Cortex kann jeder ein Held sein. (bdw) <<
diff -u -r rpm-4.0.2-opkg/rpmio/rpmio.c rpm-4.0.2-mk/rpmio/rpmio.c --- rpm-4.0.2-opkg/rpmio/rpmio.c Mon Mar 12 19:20:29 2001 +++ rpm-4.0.2-mk/rpmio/rpmio.c Mon Dec 30 16:53:30 2002 @@ -1325,7 +1325,7 @@ const char * path; int port; int rc; - char * req; + char * req, * h; size_t len; int retrying = 0; @@ -1362,23 +1362,30 @@ req = alloca(len); *req = '\0'; + /* if forceHttpProxy is given, the "Host:"-part is left up to the Proxy */ + len = sizeof("Host: y:z\r\n") + strlen(host) + 20; + h = alloca(len); + *h = '\0'; + if (!u->forceHttpProxy) + sprintf(h, "Host: %s:%d\n\n", host, port); + if (!strcmp(httpCmd, "PUT")) { sprintf(req, "\ %s %s HTTP/1.%d\r\n\ User-Agent: rpm/%s\r\n\ -Host: %s:%d\r\n\ +%s\ Accept: text/plain\r\n\ Transfer-Encoding: chunked\r\n\ \r\n\ -", httpCmd, path, (u->httpVersion ? 1 : 0), VERSION, host, port); +", httpCmd, path, (u->httpVersion ? 1 : 0), VERSION, h); } else { sprintf(req, "\ %s %s HTTP/1.%d\r\n\ User-Agent: rpm/%s\r\n\ -Host: %s:%d\r\n\ +%s\ Accept: text/plain\r\n\ \r\n\ -", httpCmd, path, (u->httpVersion ? 1 : 0), VERSION, host, port); +", httpCmd, path, (u->httpVersion ? 1 : 0), VERSION, h); } if (_ftp_debug) diff -u -r rpm-4.0.2-opkg/rpmio/rpmurl.h rpm-4.0.2-mk/rpmio/rpmurl.h --- rpm-4.0.2-opkg/rpmio/rpmurl.h Mon Dec 11 19:41:27 2000 +++ rpm-4.0.2-mk/rpmio/rpmurl.h Mon Dec 30 14:36:03 2002 @@ -35,6 +35,7 @@ const char * proxyu; /*!< FTP: proxy user */ const char * proxyh; /*!< FTP/HTTP: proxy host */ int proxyp; /*!< FTP/HTTP: proxy port */ + int forceHttpProxy; /*!< FTP over HTTP proxy */ int port; int urltype; FD_t ctrl; /*!< control channel */ @@ -87,8 +88,41 @@ */ void urlFreeCache(void); + +/** + * Checks whether host is equal to or ends in an entry from l_noproxy. + * @param host host name + * @return 1 if entry found, 0 if not + */ +int noProxy(const char *host); + +/** + * Return host that should be used as ftp proxy. Checks also for l_noproxy. + * @param host host name (checked against l_noproxy if not NULL) + * @return host to use as proxy, NULL if none + */ +char *getFtpProxy(const char *host); + +/** + * Return host that should be used as http proxy. Checks also for l_noproxy. + * @param host host name (checked against l_noproxy if not NULL) + * @return host to use as proxy, NULL if none + */ +char *getHttpProxy(const char *host); + +/** + * Check, whether l_force_HttpProxy is defined. Makes only sense, if there + * is also a _httpproxy setting ! + * Either url or host name must be NULL. + * @param url url + * @param host host name + * @return 1 if defined, 0 if not + */ +int forceHttpProxy(const char *url, const char *host); + /** * Return type of URL. + * Lie (return URL_IS_HTTP), when l_forceHttpProxy is set * @param url url string * @return type of url */ diff -u -r rpm-4.0.2-opkg/rpmio/url.c rpm-4.0.2-mk/rpmio/url.c --- rpm-4.0.2-opkg/rpmio/url.c Mon Dec 11 19:41:27 2000 +++ rpm-4.0.2-mk/rpmio/url.c Mon Dec 30 14:44:10 2002 @@ -54,6 +54,7 @@ return NULL; memset(u, 0, sizeof(*u)); u->proxyp = -1; + u->forceHttpProxy = 0; u->port = -1; u->urltype = URL_IS_UNKNOWN; u->ctrl = NULL; @@ -217,6 +218,7 @@ /* Perform one-time FTP initialization */ if (u->urltype == URL_IS_FTP) { + int ignoreProxy = noProxy(u->host); if (mustAsk || (u->user != NULL && u->password == NULL)) { char * prompt; @@ -227,8 +229,8 @@ u->password = xstrdup(u->password); /* XXX xstrdup has side effects. */ } - if (u->proxyh == NULL) { - const char *proxy = rpmExpand("%{_ftpproxy}", NULL); + if (u->proxyh == NULL && !ignoreProxy) { + const char *proxy = getFtpProxy(NULL); if (proxy && *proxy != '%') { const char *uu = (u->user ? u->user : "anonymous"); char *nu = xmalloc(strlen(uu) + sizeof("@") + strlen(u->host)); @@ -239,7 +241,7 @@ free((void *)proxy); } - if (u->proxyp < 0) { + if (u->proxyp < 0 && !ignoreProxy) { const char *proxy = rpmExpand("%{_ftpport}", NULL); if (proxy && *proxy != '%') { char *end; @@ -257,15 +259,18 @@ /* Perform one-time HTTP initialization */ if (u->urltype == URL_IS_HTTP) { + int ignoreProxy = noProxy(u->host); - if (u->proxyh == NULL) { - const char *proxy = rpmExpand("%{_httpproxy}", NULL); - if (proxy && *proxy != '%') + if (u->proxyh == NULL && !ignoreProxy) { + const char *proxy = getHttpProxy(NULL); + if (proxy && *proxy != '%') { u->proxyh = xstrdup(proxy); + u->forceHttpProxy = forceHttpProxy(NULL, u->host); + } free((void *)proxy); } - if (u->proxyp < 0) { + if (u->proxyp < 0 && !ignoreProxy) { const char *proxy = rpmExpand("%{_httpport}", NULL); if (proxy && *proxy != '%') { char *end; @@ -296,6 +301,92 @@ { NULL, URL_IS_UNKNOWN } }; +/* l_noproxy is a comma-separated list of hosts/domains where no proxy + * should be used. E.g. with l_noproxy == "localhost,local-domain.org", + * no proxy will be used for hosts with names equal to "localhost" or + * "local-domain.org" or ending in ".localhost" or ".local-domain.org" + */ +int noProxy(const char *host) +{ + char *noProxy = rpmExpand("%{l_noproxy}", NULL), *eStart, *eEnd, *dot; + int hLen, eLen; + + if (noProxy == NULL || *noProxy == '%') { + free((void *)noProxy); + return 0; + } + + eStart = noProxy; + hLen = strlen(host); + do { + eEnd = strchr(eStart, ','); + if (eEnd != NULL) { + *eEnd = '\0'; + eLen = eEnd - eStart; + } else { + eLen = strlen(eStart); + } + if (eLen <= hLen) { + if (eLen == hLen && strcasecmp(eStart, host) == 0) { + free((void *)noProxy); + return 1; + } else { + dot = (char *)host; /* discard 'const', avoid compiler + * warning for next statement */ + dot = &dot[hLen-eLen-1]; + if (*dot == '.' && strcasecmp(eStart, dot+1) == 0) { + free((void *)noProxy); + return 1; + } + } + } + if (eEnd != NULL) eStart = eEnd + 1; + } while (eEnd != NULL); + free((void *)noProxy); + return 0; +} + +char *getFtpProxy(const char *host) +{ + if (host && noProxy(host)) return NULL; + return rpmExpand("%{_ftpproxy}", NULL); +} + +char *getHttpProxy(const char *host) +{ + if (host && noProxy(host)) return NULL; + return rpmExpand("%{_httpproxy}", NULL); +} + +int forceHttpProxy(const char *url, const char *host) +{ + char *rcEntryForce = rpmExpand("%{l_force_httpproxy}", NULL); + int set; + + set = (rcEntryForce && *rcEntryForce != '%'); + free((void *)rcEntryForce); + if (!set) return 0; + + if (host != NULL) { + set = !noProxy(host); + } else { + char *myUrl = strdup(url), *hStart, *hEnd; + + set = 0; + hStart = strchr(myUrl, '/'); + if (hStart != NULL && hStart[1] == '/') { + hStart += 2; + hEnd = strchr(hStart, '/'); + if (hEnd != NULL) *hEnd = '\0'; + hEnd = strchr(hStart, ':'); + if (hEnd != NULL) *hEnd = '\0'; + set = !noProxy(hStart); + } + free((void *)myUrl); + } + return set; +} + urltype urlIsURL(const char * url) { struct urlstring *us; @@ -303,6 +394,9 @@ for (us = urlstrings; us->leadin != NULL; us++) { if (strncmp(url, us->leadin, strlen(us->leadin))) continue; + if (us->ret == URL_IS_FTP && forceHttpProxy(url, NULL)) { + return URL_IS_HTTP; + } return us->ret; } } @@ -326,8 +420,10 @@ break; case URL_IS_HTTP: case URL_IS_PATH: - url += sizeof("file://") - 1; + /* caution: -> forceHttpProxy; better 2 times strchr(url, '/') */ + /* url += sizeof("file://") - 1; */ path = strchr(url, '/'); + if (path != NULL && path[1] == '/') path = strchr(path+2, '/'); if (path == NULL) path = url + strlen(url); break; case URL_IS_UNKNOWN: @@ -373,7 +469,12 @@ /* Item was service. Save service and go for the rest ...*/ if (*se && (se != s) && se[-1] == ':' && se[0] == '/' && se[1] == '/') { se[-1] = '\0'; - u->service = xstrdup(s); + switch (u->urltype) { + case URL_IS_HTTP: + u->service = xstrdup("http"); break; + default: + u->service = xstrdup(s); + } se += 2; /* skip over "//" */ s = se++; continue;