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;

Reply via email to