From de9cd1b173bab185e97995db09d40318378ab9ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= Date: Wed, 27 Feb 2013 11:13:47 +0200 Subject: [PATCH 1/2] lavf: Handle the environment variable no_proxy more properly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The handling of the environment variable no_proxy, present since one of the initial commits (de6d9b6404), is inconsistent with how many other applications and libraries interpret this variable. Its bare presence does not indicate that the use of proxies should be skipped, but it is some sort of pattern for hosts that does not need using a proxy (e.g. for a local network). As investigated by Rudolf Polzer, different libraries handle this in different ways, some supporting IP address masks, some supporting arbitrary globbing using *, some just checking that the pattern matches the end of the hostname without regard for whether it actually is the right domain or a domain that ends in the same string. This simple logic should be pretty similar to the logic used by lynx and curl. Signed-off-by: Martin Storsjö --- libavformat/http.c | 8 +++---- libavformat/internal.h | 2 ++ libavformat/tls.c | 8 +++---- libavformat/utils.c | 54 ++++++++++++++++++++++++++++++++++++++++++ libavformat/version.h | 2 +- 5 files changed, 65 insertions(+), 9 deletions(-) diff --git a/libavformat/http.c b/libavformat/http.c index 9666ca3206..9645bd1ffb 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -106,10 +106,6 @@ static int http_open_cnx(URLContext *h) HTTPAuthType cur_auth_type, cur_proxy_auth_type; HTTPContext *s = h->priv_data; - proxy_path = getenv("http_proxy"); - use_proxy = (proxy_path != NULL) && !getenv("no_proxy") && - av_strstart(proxy_path, "http://", NULL); - /* fill the dest addr */ redo: /* needed in any case to build the host string */ @@ -118,6 +114,10 @@ static int http_open_cnx(URLContext *h) path1, sizeof(path1), s->location); ff_url_join(hoststr, sizeof(hoststr), NULL, NULL, hostname, port, NULL); + proxy_path = getenv("http_proxy"); + use_proxy = !ff_http_match_no_proxy(getenv("no_proxy"), hostname) && + proxy_path != NULL && av_strstart(proxy_path, "http://", NULL); + if (!strcmp(proto, "https")) { lower_proto = "tls"; use_proxy = 0; diff --git a/libavformat/internal.h b/libavformat/internal.h index 3ca2d8fb97..7367369647 100644 --- a/libavformat/internal.h +++ b/libavformat/internal.h @@ -375,4 +375,6 @@ enum AVCodecID ff_codec_get_id(const AVCodecTag *tags, unsigned int tag); */ enum AVCodecID ff_get_pcm_codec_id(int bps, int flt, int be, int sflags); +int ff_http_match_no_proxy(const char *no_proxy, const char *hostname); + #endif /* AVFORMAT_INTERNAL_H */ diff --git a/libavformat/tls.c b/libavformat/tls.c index 866e55f2ba..fecf096b02 100644 --- a/libavformat/tls.c +++ b/libavformat/tls.c @@ -116,10 +116,6 @@ static int tls_open(URLContext *h, const char *uri, int flags) ff_tls_init(); - proxy_path = getenv("http_proxy"); - use_proxy = (proxy_path != NULL) && !getenv("no_proxy") && - av_strstart(proxy_path, "http://", NULL); - av_url_split(NULL, 0, NULL, 0, host, sizeof(host), &port, NULL, 0, uri); ff_url_join(buf, sizeof(buf), "tcp", NULL, host, port, NULL); @@ -129,6 +125,10 @@ static int tls_open(URLContext *h, const char *uri, int flags) freeaddrinfo(ai); } + proxy_path = getenv("http_proxy"); + use_proxy = !ff_http_match_no_proxy(getenv("no_proxy"), host) && + proxy_path != NULL && av_strstart(proxy_path, "http://", NULL); + if (use_proxy) { char proxy_host[200], proxy_auth[200], dest[200]; int proxy_port; diff --git a/libavformat/utils.c b/libavformat/utils.c index cd46caf3fd..be5a5caabf 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -3589,3 +3589,57 @@ const struct AVCodecTag *avformat_get_riff_audio_tags(void) { return ff_codec_wav_tags; } + +static int match_host_pattern(const char *pattern, const char *hostname) +{ + int len_p, len_h; + if (!strcmp(pattern, "*")) + return 1; + // Skip a possible *. at the start of the pattern + if (pattern[0] == '*') + pattern++; + if (pattern[0] == '.') + pattern++; + len_p = strlen(pattern); + len_h = strlen(hostname); + if (len_p > len_h) + return 0; + // Simply check if the end of hostname is equal to 'pattern' + if (!strcmp(pattern, &hostname[len_h - len_p])) { + if (len_h == len_p) + return 1; // Exact match + if (hostname[len_h - len_p - 1] == '.') + return 1; // The matched substring is a domain and not just a substring of a domain + } + return 0; +} + +int ff_http_match_no_proxy(const char *no_proxy, const char *hostname) +{ + char *buf, *start; + int ret = 0; + if (!no_proxy) + return 0; + if (!hostname) + return 0; + buf = av_strdup(no_proxy); + if (!buf) + return 0; + start = buf; + while (start) { + char *sep, *next = NULL; + start += strspn(start, " ,"); + sep = start + strcspn(start, " ,"); + if (*sep) { + next = sep + 1; + *sep = '\0'; + } + if (match_host_pattern(start, hostname)) { + ret = 1; + break; + } + start = next; + } + av_free(buf); + return ret; +} diff --git a/libavformat/version.h b/libavformat/version.h index a9d542af2f..763c9df303 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -31,7 +31,7 @@ #define LIBAVFORMAT_VERSION_MAJOR 54 #define LIBAVFORMAT_VERSION_MINOR 21 -#define LIBAVFORMAT_VERSION_MICRO 2 +#define LIBAVFORMAT_VERSION_MICRO 3 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ LIBAVFORMAT_VERSION_MINOR, \ From 5c8696555abd30a200d0d882e2913f66619fba68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= Date: Wed, 27 Feb 2013 11:45:16 +0200 Subject: [PATCH 2/2] lavf: Add a fate test for the noproxy pattern matching MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Martin Storsjö --- libavformat/Makefile | 3 ++- libavformat/noproxy-test.c | 43 ++++++++++++++++++++++++++++++++++++++ tests/fate/libavformat.mak | 4 ++++ tests/ref/fate/noproxy | 9 ++++++++ 4 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 libavformat/noproxy-test.c create mode 100644 tests/ref/fate/noproxy diff --git a/libavformat/Makefile b/libavformat/Makefile index 25b8157d2c..110e683b2e 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -380,7 +380,8 @@ SKIPHEADERS-$(CONFIG_NETWORK) += network.h rtsp.h EXAMPLES = metadata \ output \ -TESTPROGS = seek \ +TESTPROGS = noproxy \ + seek \ srtp \ url \ diff --git a/libavformat/noproxy-test.c b/libavformat/noproxy-test.c new file mode 100644 index 0000000000..59a435e30a --- /dev/null +++ b/libavformat/noproxy-test.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2013 Martin Storsjo + * + * This file is part of Libav. + * + * Libav is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * Libav is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Libav; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "internal.h" + +static void test(const char *pattern, const char *host) +{ + int res = ff_http_match_no_proxy(pattern, host); + printf("The pattern \"%s\" %s the hostname %s\n", + pattern ? pattern : "(null)", res ? "matches" : "does not match", + host); +} + +int main(void) +{ + test(NULL, "domain.com"); + test("example.com domain.com", "domain.com"); + test("example.com other.com", "domain.com"); + test("example.com,domain.com", "domain.com"); + test("example.com,domain.com", "otherdomain.com"); + test("example.com, *.domain.com", "sub.domain.com"); + test("example.com, *.domain.com", "domain.com"); + test("example.com, .domain.com", "domain.com"); + test("*", "domain.com"); + return 0; +} diff --git a/tests/fate/libavformat.mak b/tests/fate/libavformat.mak index 20bc31999f..8332246949 100644 --- a/tests/fate/libavformat.mak +++ b/tests/fate/libavformat.mak @@ -1,3 +1,7 @@ +FATE_LIBAVFORMAT += fate-noproxy +fate-noproxy: libavformat/noproxy-test$(EXESUF) +fate-noproxy: CMD = run libavformat/noproxy-test + FATE_LIBAVFORMAT += fate-srtp fate-srtp: libavformat/srtp-test$(EXESUF) fate-srtp: CMD = run libavformat/srtp-test diff --git a/tests/ref/fate/noproxy b/tests/ref/fate/noproxy new file mode 100644 index 0000000000..7707609d0f --- /dev/null +++ b/tests/ref/fate/noproxy @@ -0,0 +1,9 @@ +The pattern "(null)" does not match the hostname domain.com +The pattern "example.com domain.com" matches the hostname domain.com +The pattern "example.com other.com" does not match the hostname domain.com +The pattern "example.com,domain.com" matches the hostname domain.com +The pattern "example.com,domain.com" does not match the hostname otherdomain.com +The pattern "example.com, *.domain.com" matches the hostname sub.domain.com +The pattern "example.com, *.domain.com" matches the hostname domain.com +The pattern "example.com, .domain.com" matches the hostname domain.com +The pattern "*" matches the hostname domain.com