[vlc-devel] [PATCH] win32/netconf: detect proxy URL from system configuration

Pierre Lamot pierre at videolabs.io
Tue Feb 13 18:50:08 CET 2018


---
 configure.ac        |   4 +
 src/win32/netconf.c | 262 ++++++++++++++++++++++++++++++++++++++++------------
 2 files changed, 207 insertions(+), 59 deletions(-)

diff --git a/configure.ac b/configure.ac
index 1750b0391f..4c448a9564 100644
--- a/configure.ac
+++ b/configure.ac
@@ -721,6 +721,10 @@ AS_IF([test "${ac_cv_struct_sockaddr_storage}" = no], [
   AC_DEFINE(ss_family, sa_family)
 ])
 
+AS_IF([test "${SYS}" = "mingw32" -a "${enable_winstore_app}" != "yes"], [
+  VLC_ADD_LIBS([libvlccore], [-lwinhttp])
+])
+
 dnl FreeBSD has a gnugetopt library for this:
 GNUGETOPT_LIBS=""
 AC_CHECK_FUNC(getopt_long,, [
diff --git a/src/win32/netconf.c b/src/win32/netconf.c
index 81458ab37a..b5118879ce 100644
--- a/src/win32/netconf.c
+++ b/src/win32/netconf.c
@@ -24,87 +24,231 @@
 
 #include <string.h>
 #include <windows.h>
+#if !VLC_WINSTORE_APP
+#  include <winhttp.h>
+#endif
 
 #include <vlc_common.h>
+#include <vlc_charset.h>
 #include <vlc_network.h>
 #include <vlc_url.h>
 
-char *vlc_getProxyUrl(const char *psz_url)
+#define PROXY_TYPE_UNKNOWNED 0
+#define PROXY_TYPE_SOCKS 1
+#define PROXY_TYPE_HTTP 2
+#define PROXY_TYPE_HTTPS 3
+
+/*
+ * this function parses the proxy list returned by WinHttpGetProxyForUrl.
+ * it returns the first proxy found using the prefered protocol (https > http > socks)
+ *
+ * The proxy server list contains one or more of the following strings
+ * separated by semicolons or whitespace.
+ * ([<scheme>=][<scheme>"://"]<server>[":"<port>])
+ */
+static char* parse_proxy( char* psz_proxy )
 {
-    VLC_UNUSED(psz_url);
+#define SET_PROXY( proxy_type )               \
+    do {                                      \
+        free( psz_ret_proxy );                \
+        psz_ret_proxy = strdup( psz_proxy );  \
+        if( psz_ret_proxy == NULL )           \
+            return NULL;                      \
+        i_ret_proxy_type = proxy_type;        \
+    } while( 0 )
+
+#define SET_PROXY_FMT( proxy_type, fmt )                        \
+    do {                                                        \
+        free( psz_ret_proxy );                                  \
+        if( asprintf( &psz_ret_proxy, fmt, psz_proxy ) == -1 )  \
+            return NULL;                                        \
+        i_ret_proxy_type = proxy_type;                          \
+    } while( 0 )
+
+    int i_ret_proxy_type = PROXY_TYPE_UNKNOWNED;
+    char* psz_ret_proxy = NULL;
+    char* psz_next_proxy = NULL;
+    char* psz_equal;
+
+    const char* psz_end = strchr( psz_proxy, '\0' );
+
+    while( psz_proxy < psz_end )
+    {
+        int i_proxy_type = PROXY_TYPE_HTTP;
 
-    char *proxy = config_GetPsz( (vlc_object_t *)(NULL), "http-proxy" );
-    if (proxy == NULL)
-        return NULL;
+        //strip leading space / empty proxies
+        psz_proxy += strspn( psz_proxy, " \t;" );
+        if( psz_proxy == psz_end )
+            return psz_ret_proxy;
 
-    char *proxy_pwd = config_GetPsz( (vlc_object_t *)(NULL), "http-proxy-pwd" );
-    if (proxy_pwd == NULL)
-        return proxy;
+        //detect [<scheme>=]
+        if( ( psz_equal =  strchr( psz_proxy, '=' ) ) )
+        {
+            *psz_equal = '\0';
+            if( strcasecmp( psz_proxy, "https" ) == 0 )
+                i_proxy_type = PROXY_TYPE_HTTPS;
+            else if( strcasecmp( psz_proxy, "http" ) == 0 )
+                i_proxy_type = PROXY_TYPE_HTTP;
+            else if( strcasecmp( psz_proxy, "socks" ) == 0 )
+                i_proxy_type = PROXY_TYPE_SOCKS;
+            else
+                i_proxy_type = PROXY_TYPE_UNKNOWNED;
+            psz_proxy = psz_equal + 1;
+        }
 
-    vlc_url_t url;
-    if (vlc_UrlParse(&url, proxy) < 0) {
-        vlc_UrlClean(&url);
-        free (proxy);
-        free (proxy_pwd);
-        return NULL;
+        int i_proxylen = strcspn( psz_proxy, " \t;" );
+        psz_proxy[i_proxylen] = '\0';
+        psz_next_proxy = psz_proxy + i_proxylen + 1;
+
+        if( strncasecmp( psz_proxy, "http://", 7 ) == 0
+            && PROXY_TYPE_HTTP > i_ret_proxy_type )
+            SET_PROXY( PROXY_TYPE_HTTP );
+        else if( strncasecmp( psz_proxy, "https://", 8 ) == 0
+                 && PROXY_TYPE_HTTPS > i_ret_proxy_type )
+            SET_PROXY( PROXY_TYPE_HTTPS );
+        else if( strncasecmp( psz_proxy, "socks://", 8 ) == 0
+                 && PROXY_TYPE_SOCKS > i_ret_proxy_type )
+            SET_PROXY( PROXY_TYPE_SOCKS );
+        else if( i_proxy_type > i_ret_proxy_type
+                 && !strstr( psz_proxy, "://" ) )
+        {
+            switch ( i_proxy_type ) {
+            case PROXY_TYPE_HTTPS:
+                SET_PROXY_FMT( PROXY_TYPE_HTTPS, "https://%s" );
+                break;
+            case PROXY_TYPE_SOCKS:
+                SET_PROXY_FMT( PROXY_TYPE_SOCKS, "socks://%s" );
+                break;
+            case PROXY_TYPE_UNKNOWNED:
+                break;
+            default:
+                SET_PROXY_FMT( PROXY_TYPE_HTTP, "http://%s" );
+                break;
+            }
+        }
+
+        psz_proxy = psz_next_proxy;
     }
+    return psz_ret_proxy;
+
+#undef SET_PROXY
+#undef SET_PROXY_FMT
+}
+
+char *vlc_getProxyUrl(const char *psz_url)
+{
+    char *proxy = config_GetPsz( (vlc_object_t *)(NULL), "http-proxy" );
+    if (proxy != NULL)
+    {
+        char *proxy_pwd = config_GetPsz( (vlc_object_t *)(NULL), "http-proxy-pwd" );
+        if (proxy_pwd == NULL)
+            return proxy;
 
-    if (url.psz_password == NULL )
-        url.psz_password = proxy_pwd;
+        vlc_url_t url;
+        if (vlc_UrlParse(&url, proxy) < 0)
+        {
+            vlc_UrlClean(&url);
+            free (proxy);
+            free (proxy_pwd);
+            return NULL;
+        }
 
-    char *proxy_url = vlc_uri_compose (&url);
-    vlc_UrlClean (&url);
+        if (url.psz_password == NULL )
+            url.psz_password = proxy_pwd;
 
-    free (proxy_pwd);
-    free (proxy);
+        char *proxy_url = vlc_uri_compose (&url);
+        vlc_UrlClean (&url);
 
-#if 0
-    /* Try to get the proxy server address from Windows internet settings. */
-    HKEY h_key;
+        free (proxy_pwd);
+        free (proxy);
+        return proxy_url;
+    }
 
-    /* Open the key */
-    if( RegOpenKeyEx( HKEY_CURRENT_USER, "Software\\Microsoft"
-                      "\\Windows\\CurrentVersion\\Internet Settings",
-                      0, KEY_READ, &h_key ) == ERROR_SUCCESS )
+#if VLC_WINSTORE_APP
+    return NULL;
+#else
+    if ( psz_url == NULL )
         return NULL;
 
-    DWORD len = sizeof( DWORD );
-    BYTE proxyEnable;
-
-    /* Get the proxy enable value */
-    if( RegQueryValueEx( h_key, "ProxyEnable", NULL, NULL,
-                         &proxyEnable, &len ) != ERROR_SUCCESS
-     || !proxyEnable )
-        goto out;
-
-    /* Proxy is enabled */
-    /* Get the proxy URL :
-       Proxy server value in the registry can be something like "address:port"
-       or "ftp=address1:port1;http=address2:port2 ..."
-       depending of the configuration. */
-    unsigned char key[256];
-
-    len = sizeof( key );
-    if( RegQueryValueEx( h_key, "ProxyServer", NULL, NULL,
-                         key, &len ) == ERROR_SUCCESS )
+    char *psz_proxy = NULL;
+    wchar_t *pwsz_url = ToWide( psz_url );
+    bool b_autoproxy = false;
+
+    WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ieConfig;
+    WINHTTP_AUTOPROXY_OPTIONS autoProxyOptions;
+    WINHTTP_PROXY_INFO autoProxyInfo;
+
+    memset( &ieConfig, 0, sizeof(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG) );
+    memset( &autoProxyOptions, 0, sizeof(WINHTTP_AUTOPROXY_OPTIONS) );
+    memset( &autoProxyInfo, 0, sizeof(WINHTTP_PROXY_INFO) );
+
+    if( WinHttpGetIEProxyConfigForCurrentUser(&ieConfig) )
     {
-        /* FIXME: This is lame. The string should be tokenized. */
-#warning FIXME.
-        char *psz_proxy = strstr( (char *)key, "http=" );
-        if( psz_proxy != NULL )
+        if( ieConfig.fAutoDetect )
+            b_autoproxy = true;
+        if( ieConfig.lpszAutoConfigUrl != NULL )
         {
-            psz_proxy += 5;
-            char *end = strchr( psz_proxy, ';' );
-            if( end != NULL )
-                *end = '\0';
+            b_autoproxy = true;
+            autoProxyOptions.lpszAutoConfigUrl = ieConfig.lpszAutoConfigUrl;
         }
+    }
+    else
+        b_autoproxy = true;
+
+    if( b_autoproxy )
+    {
+        if( autoProxyOptions.lpszAutoConfigUrl != NULL )
+            autoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL;
         else
-            psz_proxy = (char *)key;
-        proxy_url = strdup( psz_proxy );
+        {
+            autoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT;
+            autoProxyOptions.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP
+                                                 | WINHTTP_AUTO_DETECT_TYPE_DNS_A;
+        }
+        autoProxyOptions.fAutoLogonIfChallenged = TRUE;
+
+        HINTERNET handle = WinHttpOpen( L"VLC Proxy Lookup/1.0",
+                                        WINHTTP_ACCESS_TYPE_NO_PROXY, WINHTTP_NO_PROXY_NAME,
+                                        WINHTTP_NO_PROXY_BYPASS, 0 );
+
+        if( !handle )
+            goto end;
+
+        b_autoproxy = WinHttpGetProxyForUrl( handle, pwsz_url, &autoProxyOptions, &autoProxyInfo );
+
+        WinHttpCloseHandle(handle);
+    }
+
+    if( b_autoproxy )
+    {
+        if( autoProxyInfo.dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY )
+            psz_proxy = FromWide( autoProxyInfo.lpszProxy );
     }
+    else if( ieConfig.lpszProxy )
+        psz_proxy = FromWide( ieConfig.lpszProxy );;
+
+    if( psz_proxy )
+    {
+        char* tmp = parse_proxy( psz_proxy );
+        free( psz_proxy );
+        psz_proxy = tmp;
+    }
+
+end:
+    if( autoProxyInfo.lpszProxy != NULL )
+        GlobalFree( autoProxyInfo.lpszProxy );
+    if( autoProxyInfo.lpszProxyBypass != NULL )
+        GlobalFree( autoProxyInfo.lpszProxyBypass );
+
+    if( ieConfig.lpszAutoConfigUrl != NULL )
+        GlobalFree( ieConfig.lpszAutoConfigUrl );
+    if( ieConfig.lpszProxy != NULL )
+        GlobalFree( ieConfig.lpszProxy );
+    if( ieConfig.lpszProxyBypass != NULL )
+        GlobalFree( ieConfig.lpszProxyBypass );
+
+    free( pwsz_url );
 
-out:
-    RegCloseKey( h_key );
+    return psz_proxy;
 #endif
-    return proxy_url;
 }
-- 
2.14.1



More information about the vlc-devel mailing list