summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2021-01-19 16:37:39 +0200
committerTimo Teräs <timo.teras@iki.fi>2021-01-19 16:49:10 +0200
commitaa1f935c05129288f1550782e34d529fc77dda0a (patch)
tree1d1a7b8bde7bb608379f12b50585d37ebdb4bff0
parentc37b385beefd0e8324bf70f011e52a8c65f7fddf (diff)
downloadapk-tools-aa1f935c05129288f1550782e34d529fc77dda0a.tar.gz
apk-tools-aa1f935c05129288f1550782e34d529fc77dda0a.tar.bz2
apk-tools-aa1f935c05129288f1550782e34d529fc77dda0a.tar.xz
apk-tools-aa1f935c05129288f1550782e34d529fc77dda0a.zip
libfetch: fix connection pooling for proxied http/https requests
The connection pooling was broken in two ways: 1. The original URL was always used as the connection pool URL, resulting in duplicate connections to the proxy for http URLs (each http URL would get separate proxy connection) 2. The cache_url stored was always the socket level connect URL. In case of HTTPS, the lookup was done done with the real URL, but the proxy URL was stored as the "cache URL". Thus HTTPS CONNECT connections were never re-used. This fixes the code with following logic: 1. The cache key url is the real URL when no-proxy, or when HTTPS with proxy (the socket is connected to proxy, but logically it is connected to the real URL due to HTTP CONNECT request). And for HTTP with proxy, it's the proxy URL so same proxy connection can be reused for all requests going through it. 2. fetch_connect() now gets cache key URL separately, and it always gets the same value as the fetch_cache_get() calls.
-rw-r--r--libfetch/common.c4
-rw-r--r--libfetch/common.h2
-rw-r--r--libfetch/ftp.c4
-rw-r--r--libfetch/http.c19
4 files changed, 14 insertions, 15 deletions
diff --git a/libfetch/common.c b/libfetch/common.c
index aabe218..e91b0c6 100644
--- a/libfetch/common.c
+++ b/libfetch/common.c
@@ -251,7 +251,7 @@ fetch_bind(int sd, int af, const char *addr)
* Establish a TCP connection to the specified port on the specified host.
*/
conn_t *
-fetch_connect(struct url *url, int af, int verbose)
+fetch_connect(struct url *cache_url, struct url *url, int af, int verbose)
{
conn_t *conn;
char pbuf[10];
@@ -303,7 +303,7 @@ fetch_connect(struct url *url, int af, int verbose)
close(sd);
return (NULL);
}
- conn->cache_url = fetchCopyURL(url);
+ conn->cache_url = fetchCopyURL(cache_url);
conn->cache_af = af;
return (conn);
}
diff --git a/libfetch/common.h b/libfetch/common.h
index fc78f16..dd5c14c 100644
--- a/libfetch/common.h
+++ b/libfetch/common.h
@@ -91,7 +91,7 @@ int fetch_default_proxy_port(const char *);
int fetch_bind(int, int, const char *);
conn_t *fetch_cache_get(const struct url *, int);
void fetch_cache_put(conn_t *, int (*)(conn_t *));
-conn_t *fetch_connect(struct url *, int, int);
+conn_t *fetch_connect(struct url *, struct url *, int, int);
conn_t *fetch_reopen(int);
int fetch_ssl(conn_t *, const struct url *, int);
ssize_t fetch_read(conn_t *, char *, size_t);
diff --git a/libfetch/ftp.c b/libfetch/ftp.c
index 80f77d9..d489559 100644
--- a/libfetch/ftp.c
+++ b/libfetch/ftp.c
@@ -1020,7 +1020,7 @@ ftp_connect(struct url *url, struct url *purl, const char *flags)
if (!purl->port)
purl->port = fetch_default_port(purl->scheme);
- conn = fetch_connect(purl, af, verbose);
+ conn = fetch_connect(purl, purl, af, verbose);
} else {
/* no proxy, go straight to target */
if (!url->port)
@@ -1032,7 +1032,7 @@ ftp_connect(struct url *url, struct url *purl, const char *flags)
return conn;
fetch_close(conn);
}
- conn = fetch_connect(url, af, verbose);
+ conn = fetch_connect(url, url, af, verbose);
purl = NULL;
}
diff --git a/libfetch/http.c b/libfetch/http.c
index 95c57f6..8239313 100644
--- a/libfetch/http.c
+++ b/libfetch/http.c
@@ -690,33 +690,33 @@ http_cork(conn_t *conn, int val)
static conn_t *
http_connect(struct url *URL, struct url *purl, const char *flags, int *cached)
{
- struct url *curl;
+ struct url *cache_url;
conn_t *conn;
hdr_t h;
const char *p;
- int af, verbose;
+ int af, verbose, is_https;
*cached = 0;
-
af = AF_UNSPEC;
-
verbose = CHECK_FLAG('v');
if (CHECK_FLAG('4'))
af = AF_INET;
else if (CHECK_FLAG('6'))
af = AF_INET6;
- curl = (purl != NULL) ? purl : URL;
+ is_https = strcasecmp(URL->scheme, SCHEME_HTTPS) == 0;
+ cache_url = (is_https || !purl) ? URL : purl;
- if ((conn = fetch_cache_get(URL, af)) != NULL) {
+ if ((conn = fetch_cache_get(cache_url, af)) != NULL) {
*cached = 1;
return (conn);
}
- if ((conn = fetch_connect(curl, af, verbose)) == NULL)
+ if ((conn = fetch_connect(cache_url, purl ?: URL, af, verbose)) == NULL)
/* fetch_connect() has already set an error code */
return (NULL);
- if (strcasecmp(URL->scheme, SCHEME_HTTPS) == 0 && purl) {
+
+ if (is_https && purl) {
http_cork(conn, 1);
http_cmd(conn, "CONNECT %s:%d HTTP/1.1\r\nHost: %s:%d\r\n\r\n",
URL->host, URL->port, URL->host, URL->port);
@@ -738,8 +738,7 @@ http_connect(struct url *URL, struct url *purl, const char *flags, int *cached)
}
} while (h > hdr_end);
}
- if (strcasecmp(URL->scheme, SCHEME_HTTPS) == 0 &&
- fetch_ssl(conn, URL, verbose) == -1) {
+ if (is_https && fetch_ssl(conn, URL, verbose) == -1) {
/* grrr */
#ifdef EAUTH
errno = EAUTH;