diff --git a/dlls/winhttp/session.c b/dlls/winhttp/session.c index b7cc31b1127..c187079fc82 100644 --- a/dlls/winhttp/session.c +++ b/dlls/winhttp/session.c @@ -1113,15 +1113,116 @@ BOOL WINAPI WinHttpSetOption( HINTERNET handle, DWORD option, LPVOID buffer, DWO return ret; } +static char *get_computer_name( COMPUTER_NAME_FORMAT format ) +{ + char *ret; + DWORD size = 0; + + GetComputerNameExA( format, NULL, &size ); + if (GetLastError() != ERROR_MORE_DATA) return NULL; + if (!(ret = heap_alloc( size ))) return NULL; + if (!GetComputerNameExA( format, ret, &size )) + { + heap_free( ret ); + return NULL; + } + return ret; +} + +static BOOL is_domain_suffix( const char *domain, const char *suffix ) +{ + int len_domain = strlen( domain ), len_suffix = strlen( suffix ); + + if (len_suffix > len_domain) return FALSE; + if (!strcasecmp( domain + len_domain - len_suffix, suffix )) return TRUE; + return FALSE; +} + +static WCHAR *build_wpad_url( const struct addrinfo *ai ) +{ + static const WCHAR fmtW[] = + {'h','t','t','p',':','/','/','%','u','.','%','u','.','%','u','.','%','u', + '/','w','p','a','d','.','d','a','t',0}; + struct sockaddr_in *addr; + WCHAR *ret; + + while (ai && ai->ai_family != AF_INET) ai = ai->ai_next; + if (!ai) return NULL; + + if (!(ret = GlobalAlloc( 0, sizeof(fmtW) + 12 * sizeof(WCHAR) ))) return NULL; + addr = (struct sockaddr_in *)ai->ai_addr; + sprintfW( ret, fmtW, + (unsigned int)(ntohl( addr->sin_addr.s_addr ) >> 24 & 0xff), + (unsigned int)(ntohl( addr->sin_addr.s_addr ) >> 16 & 0xff), + (unsigned int)(ntohl( addr->sin_addr.s_addr ) >> 8 & 0xff), + (unsigned int)(ntohl( addr->sin_addr.s_addr ) & 0xff) ); + return ret; +} + /*********************************************************************** * WinHttpDetectAutoProxyConfigUrl (winhttp.@) */ BOOL WINAPI WinHttpDetectAutoProxyConfigUrl( DWORD flags, LPWSTR *url ) { - FIXME("0x%08x, %p\n", flags, url); + BOOL ret = FALSE; - set_last_error( ERROR_WINHTTP_AUTODETECTION_FAILED ); - return FALSE; + TRACE("0x%08x, %p\n", flags, url); + + if (!flags || !url) + { + set_last_error( ERROR_INVALID_PARAMETER ); + return FALSE; + } + if (flags & WINHTTP_AUTO_DETECT_TYPE_DHCP) FIXME("discovery via DHCP not supported\n"); + if (flags & WINHTTP_AUTO_DETECT_TYPE_DNS_A) + { +#ifdef HAVE_GETADDRINFO + char *fqdn, *domain, *p; + + if (!(fqdn = get_computer_name( ComputerNamePhysicalDnsFullyQualified ))) return FALSE; + if (!(domain = get_computer_name( ComputerNamePhysicalDnsDomain ))) + { + heap_free( fqdn ); + return FALSE; + } + p = fqdn; + while ((p = strchr( p, '.' )) && is_domain_suffix( p + 1, domain )) + { + struct addrinfo *ai; + char *name; + int res; + + if (!(name = heap_alloc( sizeof("wpad") + strlen(p) ))) + { + heap_free( fqdn ); + heap_free( domain ); + return FALSE; + } + strcpy( name, "wpad" ); + strcat( name, p ); + res = getaddrinfo( name, NULL, NULL, &ai ); + heap_free( name ); + if (!res) + { + *url = build_wpad_url( ai ); + freeaddrinfo( ai ); + if (*url) + { + TRACE("returning %s\n", debugstr_w(*url)); + ret = TRUE; + break; + } + } + p++; + } + heap_free( domain ); + heap_free( fqdn ); +#else + FIXME("getaddrinfo not found at build time\n"); +#endif + } + if (!ret) set_last_error( ERROR_WINHTTP_AUTODETECTION_FAILED ); + return ret; } static const WCHAR Connections[] = { diff --git a/dlls/winhttp/tests/winhttp.c b/dlls/winhttp/tests/winhttp.c index acf88dc4379..f481a82e8e7 100644 --- a/dlls/winhttp/tests/winhttp.c +++ b/dlls/winhttp/tests/winhttp.c @@ -2518,6 +2518,44 @@ static void test_IWinHttpRequest(void) CoUninitialize(); } +static void test_WinHttpDetectAutoProxyConfigUrl(void) +{ + BOOL ret; + WCHAR *url; + DWORD error; + + SetLastError(0xdeadbeef); + ret = WinHttpDetectAutoProxyConfigUrl( 0, NULL ); + error = GetLastError(); + ok( !ret, "expected failure\n" ); + ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + + url = NULL; + SetLastError(0xdeadbeef); + ret = WinHttpDetectAutoProxyConfigUrl( 0, &url ); + error = GetLastError(); + ok( !ret, "expected failure\n" ); + ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + + SetLastError(0xdeadbeef); + ret = WinHttpDetectAutoProxyConfigUrl( WINHTTP_AUTO_DETECT_TYPE_DNS_A, NULL ); + error = GetLastError(); + ok( !ret, "expected failure\n" ); + ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + + url = NULL; + SetLastError(0xdeadbeef); + ret = WinHttpDetectAutoProxyConfigUrl( WINHTTP_AUTO_DETECT_TYPE_DNS_A, &url ); + error = GetLastError(); + if (!ret) + ok( error == ERROR_WINHTTP_AUTODETECTION_FAILED, "got %u\n", error ); + else + { + trace("%s\n", wine_dbgstr_w(url)); + GlobalFree( url ); + } +} + START_TEST (winhttp) { static const WCHAR basicW[] = {'/','b','a','s','i','c',0}; @@ -2540,6 +2578,7 @@ START_TEST (winhttp) test_resolve_timeout(); test_credentials(); test_IWinHttpRequest(); + test_WinHttpDetectAutoProxyConfigUrl(); si.event = CreateEvent(NULL, 0, 0, NULL); si.port = 7532; diff --git a/include/winhttp.h b/include/winhttp.h index 68bec0a433d..36f8b9df5ef 100644 --- a/include/winhttp.h +++ b/include/winhttp.h @@ -503,6 +503,9 @@ typedef struct typedef VOID (CALLBACK *WINHTTP_STATUS_CALLBACK)(HINTERNET,DWORD_PTR,DWORD,LPVOID,DWORD); +#define WINHTTP_AUTO_DETECT_TYPE_DHCP 0x00000001 +#define WINHTTP_AUTO_DETECT_TYPE_DNS_A 0x00000002 + typedef struct { DWORD dwFlags;