winhttp: Implement WinHttpGetProxyForUrl.

This commit is contained in:
Hans Leidekker 2011-11-18 10:36:04 +01:00 committed by Alexandre Julliard
parent e3a5423478
commit 768300c8aa
4 changed files with 409 additions and 4 deletions

View File

@ -1,7 +1,7 @@
MODULE = winhttp.dll
IMPORTLIB = winhttp
IMPORTS = uuid user32 advapi32
DELAYIMPORTS = oleaut32 crypt32
DELAYIMPORTS = oleaut32 ole32 crypt32
EXTRALIBS = @SOCKETLIBS@
C_SRCS = \

View File

@ -28,6 +28,9 @@
#include "winhttp.h"
#include "wincrypt.h"
#include "winreg.h"
#define COBJMACROS
#include "ole2.h"
#include "activscp.h"
#include "winhttp_private.h"
@ -1474,17 +1477,325 @@ done:
return ret;
}
static HRESULT WINAPI site_QueryInterface(
IActiveScriptSite *iface, REFIID riid, void **ppv )
{
*ppv = NULL;
if (IsEqualGUID( &IID_IUnknown, riid ))
*ppv = iface;
else if (IsEqualGUID( &IID_IActiveScriptSite, riid ))
*ppv = iface;
else
return E_NOINTERFACE;
IUnknown_AddRef( (IUnknown *)*ppv );
return S_OK;
}
static ULONG WINAPI site_AddRef(
IActiveScriptSite *iface )
{
return 2;
}
static ULONG WINAPI site_Release(
IActiveScriptSite *iface )
{
return 1;
}
static HRESULT WINAPI site_GetLCID(
IActiveScriptSite *iface, LCID *lcid )
{
return E_NOTIMPL;
}
static HRESULT WINAPI site_GetItemInfo(
IActiveScriptSite *iface, LPCOLESTR name, DWORD mask,
IUnknown **item, ITypeInfo **type_info )
{
return E_NOTIMPL;
}
static HRESULT WINAPI site_GetDocVersionString(
IActiveScriptSite *iface, BSTR *version )
{
return E_NOTIMPL;
}
static HRESULT WINAPI site_OnScriptTerminate(
IActiveScriptSite *iface, const VARIANT *result, const EXCEPINFO *info )
{
return E_NOTIMPL;
}
static HRESULT WINAPI site_OnStateChange(
IActiveScriptSite *iface, SCRIPTSTATE state )
{
return E_NOTIMPL;
}
static HRESULT WINAPI site_OnScriptError(
IActiveScriptSite *iface, IActiveScriptError *error )
{
return E_NOTIMPL;
}
static HRESULT WINAPI site_OnEnterScript(
IActiveScriptSite *iface )
{
return E_NOTIMPL;
}
static HRESULT WINAPI site_OnLeaveScript(
IActiveScriptSite *iface )
{
return E_NOTIMPL;
}
static const IActiveScriptSiteVtbl site_vtbl =
{
site_QueryInterface,
site_AddRef,
site_Release,
site_GetLCID,
site_GetItemInfo,
site_GetDocVersionString,
site_OnScriptTerminate,
site_OnStateChange,
site_OnScriptError,
site_OnEnterScript,
site_OnLeaveScript
};
static IActiveScriptSite script_site = { &site_vtbl };
static BOOL parse_script_result( VARIANT result, WINHTTP_PROXY_INFO *info )
{
static const WCHAR proxyW[] = {'P','R','O','X','Y'};
const WCHAR *p;
WCHAR *q;
int len;
info->dwAccessType = WINHTTP_ACCESS_TYPE_NO_PROXY;
info->lpszProxy = NULL;
info->lpszProxyBypass = NULL;
if (V_VT( &result ) != VT_BSTR) return TRUE;
TRACE("%s\n", debugstr_w( V_BSTR( &result ) ));
p = V_BSTR( &result );
while (*p == ' ') p++;
len = strlenW( p );
if (len >= 5 && !memicmpW( p, proxyW, sizeof(proxyW)/sizeof(WCHAR) ))
{
p += 5;
while (*p == ' ') p++;
if (!*p || *p == ';') return TRUE;
if (!(info->lpszProxy = q = strdupW( p ))) return FALSE;
info->dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
for (; *q; q++)
{
if (*q == ' ' || *q == ';')
{
*q = 0;
break;
}
}
}
return TRUE;
}
static BOOL run_script( const BSTR script, const WCHAR *url, WINHTTP_PROXY_INFO *info )
{
static const WCHAR jscriptW[] = {'J','S','c','r','i','p','t',0};
static const WCHAR findproxyW[] = {'F','i','n','d','P','r','o','x','y','F','o','r','U','R','L',0};
IActiveScriptParse *parser = NULL;
IActiveScript *engine = NULL;
IDispatch *dispatch = NULL;
BOOL ret = FALSE;
CLSID clsid;
DISPID dispid;
BSTR func = NULL, hostname = NULL;
URL_COMPONENTSW uc;
VARIANT args[2], result;
DISPPARAMS params;
HRESULT hr, init;
memset( &uc, 0, sizeof(uc) );
uc.dwStructSize = sizeof(uc);
if (!WinHttpCrackUrl( url, 0, 0, &uc )) return FALSE;
if (!(hostname = SysAllocStringLen( NULL, uc.dwHostNameLength + 1 ))) return FALSE;
memcpy( hostname, uc.lpszHostName, uc.dwHostNameLength * sizeof(WCHAR) );
hostname[uc.dwHostNameLength] = 0;
init = CoInitialize( NULL );
CLSIDFromProgID( jscriptW, &clsid );
hr = CoCreateInstance( &clsid, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
&IID_IActiveScript, (void **)&engine );
if (hr != S_OK) goto done;
hr = IActiveScript_QueryInterface( engine, &IID_IActiveScriptParse, (void **)&parser );
if (hr != S_OK) goto done;
hr = IActiveScriptParse64_InitNew( parser );
if (hr != S_OK) goto done;
hr = IActiveScript_SetScriptSite( engine, &script_site );
if (hr != S_OK) goto done;
/* FIXME: make standard functions available to script */
hr = IActiveScriptParse64_ParseScriptText( parser, script, NULL, NULL, NULL, 0, 0, 0, NULL, NULL );
if (hr != S_OK) goto done;
hr = IActiveScript_SetScriptState( engine, SCRIPTSTATE_STARTED );
if (hr != S_OK) goto done;
hr = IActiveScript_GetScriptDispatch( engine, NULL, &dispatch );
if (hr != S_OK) goto done;
if (!(func = SysAllocString( findproxyW ))) goto done;
hr = IDispatch_GetIDsOfNames( dispatch, &IID_NULL, &func, 1, LOCALE_SYSTEM_DEFAULT, &dispid );
if (hr != S_OK) goto done;
V_VT( &args[0] ) = VT_BSTR;
V_BSTR( &args[0] ) = SysAllocString( url );
V_VT( &args[1] ) = VT_BSTR;
V_BSTR( &args[1] ) = hostname;
params.rgvarg = args;
params.rgdispidNamedArgs = NULL;
params.cArgs = 2;
params.cNamedArgs = 0;
hr = IDispatch_Invoke( dispatch, dispid, &IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD,
&params, &result, NULL, NULL );
VariantClear( &args[0] );
VariantClear( &args[1] );
if (hr != S_OK) goto done;
ret = parse_script_result( result, info );
done:
SysFreeString( func );
if (dispatch) IDispatch_Release( dispatch );
if (parser) IUnknown_Release( parser );
if (engine) IActiveScript_Release( engine );
if (SUCCEEDED( init )) CoUninitialize();
if (!ret) set_last_error( ERROR_WINHTTP_BAD_AUTO_PROXY_SCRIPT );
return ret;
}
static BSTR download_script( HINTERNET ses, const WCHAR *url )
{
static const WCHAR typeW[] = {'*','/','*',0};
static const WCHAR *acceptW[] = {typeW, NULL};
HINTERNET con, req = NULL;
WCHAR *hostname;
URL_COMPONENTSW uc;
DWORD size = 4096, offset, to_read, bytes_read, flags = 0;
char *tmp, *buffer = NULL;
BSTR script = NULL;
int len;
memset( &uc, 0, sizeof(uc) );
uc.dwStructSize = sizeof(uc);
if (!WinHttpCrackUrl( url, 0, 0, &uc )) return NULL;
if (!(hostname = heap_alloc( (uc.dwHostNameLength + 1) * sizeof(WCHAR) ))) return NULL;
memcpy( hostname, uc.lpszHostName, uc.dwHostNameLength * sizeof(WCHAR) );
hostname[uc.dwHostNameLength] = 0;
if (!(con = WinHttpConnect( ses, hostname, uc.nPort, 0 ))) goto done;
if (uc.nScheme == INTERNET_SCHEME_HTTPS) flags |= WINHTTP_FLAG_SECURE;
if (!(req = WinHttpOpenRequest( con, NULL, uc.lpszUrlPath, NULL, NULL, acceptW, flags ))) goto done;
if (!WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 )) goto done;
if (!(WinHttpReceiveResponse( req, 0 ))) goto done;
if (!(buffer = heap_alloc( size ))) goto done;
to_read = size;
offset = 0;
for (;;)
{
if (!WinHttpReadData( req, buffer + offset, to_read, &bytes_read )) goto done;
if (!bytes_read) break;
to_read -= bytes_read;
offset += bytes_read;
if (!to_read)
{
to_read = size;
size *= 2;
if (!(tmp = heap_realloc( buffer, size ))) goto done;
buffer = tmp;
}
}
len = MultiByteToWideChar( CP_ACP, 0, buffer, offset, NULL, 0 );
if (!(script = SysAllocStringLen( NULL, len ))) goto done;
MultiByteToWideChar( CP_ACP, 0, buffer, offset, script, len );
script[len] = 0;
done:
WinHttpCloseHandle( req );
WinHttpCloseHandle( con );
heap_free( buffer );
heap_free( hostname );
if (!script) set_last_error( ERROR_WINHTTP_UNABLE_TO_DOWNLOAD_SCRIPT );
return script;
}
/***********************************************************************
* WinHttpGetProxyForUrl (winhttp.@)
*/
BOOL WINAPI WinHttpGetProxyForUrl( HINTERNET hsession, LPCWSTR url, WINHTTP_AUTOPROXY_OPTIONS *options,
WINHTTP_PROXY_INFO *info )
{
FIXME("%p, %s, %p, %p\n", hsession, debugstr_w(url), options, info);
WCHAR *detected_pac_url = NULL;
const WCHAR *pac_url;
session_t *session;
BSTR script;
BOOL ret = FALSE;
set_last_error( ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR );
TRACE("%p, %s, %p, %p\n", hsession, debugstr_w(url), options, info);
if (!(session = (session_t *)grab_object( hsession )))
{
set_last_error( ERROR_INVALID_HANDLE );
return FALSE;
}
if (session->hdr.type != WINHTTP_HANDLE_TYPE_SESSION)
{
release_object( &session->hdr );
set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
return FALSE;
}
if (!url || !options || !info ||
!(options->dwFlags & (WINHTTP_AUTOPROXY_AUTO_DETECT|WINHTTP_AUTOPROXY_CONFIG_URL)) ||
((options->dwFlags & WINHTTP_AUTOPROXY_AUTO_DETECT) && !options->dwAutoDetectFlags) ||
((options->dwFlags & WINHTTP_AUTOPROXY_AUTO_DETECT) &&
(options->dwFlags & WINHTTP_AUTOPROXY_CONFIG_URL)))
{
release_object( &session->hdr );
set_last_error( ERROR_INVALID_PARAMETER );
return FALSE;
}
if (options->dwFlags & WINHTTP_AUTOPROXY_AUTO_DETECT &&
!WinHttpDetectAutoProxyConfigUrl( options->dwAutoDetectFlags, &detected_pac_url ))
{
set_last_error( ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR );
goto done;
}
if (options->dwFlags & WINHTTP_AUTOPROXY_CONFIG_URL) pac_url = options->lpszAutoConfigUrl;
else pac_url = detected_pac_url;
if (!(script = download_script( hsession, pac_url ))) goto done;
ret = run_script( script, url, info );
SysFreeString( script );
done:
GlobalFree( detected_pac_url );
release_object( &session->hdr );
return ret;
}
/***********************************************************************
* WinHttpSetDefaultProxyConfiguration (winhttp.@)

View File

@ -2581,6 +2581,94 @@ static void test_WinHttpGetIEProxyConfigForCurrentUser(void)
GlobalFree( cfg.lpszProxyBypass );
}
static void test_WinHttpGetProxyForUrl(void)
{
static const WCHAR urlW[] = {'h','t','t','p',':','/','/','w','i','n','e','h','q','.','o','r','g',0};
static const WCHAR emptyW[] = {0};
BOOL ret;
DWORD error;
HINTERNET session;
WINHTTP_AUTOPROXY_OPTIONS options;
WINHTTP_PROXY_INFO info;
memset( &options, 0, sizeof(options) );
SetLastError(0xdeadbeef);
ret = WinHttpGetProxyForUrl( NULL, NULL, NULL, NULL );
error = GetLastError();
ok( !ret, "expected failure\n" );
ok( error == ERROR_INVALID_HANDLE, "got %u\n", error );
session = WinHttpOpen( test_useragent, 0, NULL, NULL, 0 );
ok( session != NULL, "failed to open session %u\n", GetLastError() );
SetLastError(0xdeadbeef);
ret = WinHttpGetProxyForUrl( session, NULL, NULL, NULL );
error = GetLastError();
ok( !ret, "expected failure\n" );
ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error );
SetLastError(0xdeadbeef);
ret = WinHttpGetProxyForUrl( session, emptyW, NULL, NULL );
error = GetLastError();
ok( !ret, "expected failure\n" );
ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error );
SetLastError(0xdeadbeef);
ret = WinHttpGetProxyForUrl( session, urlW, NULL, NULL );
error = GetLastError();
ok( !ret, "expected failure\n" );
ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error );
SetLastError(0xdeadbeef);
ret = WinHttpGetProxyForUrl( session, urlW, &options, &info );
error = GetLastError();
ok( !ret, "expected failure\n" );
ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error );
options.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT;
options.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DNS_A;
SetLastError(0xdeadbeef);
ret = WinHttpGetProxyForUrl( session, urlW, &options, NULL );
error = GetLastError();
ok( !ret, "expected failure\n" );
ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error );
options.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT;
options.dwAutoDetectFlags = 0;
SetLastError(0xdeadbeef);
ret = WinHttpGetProxyForUrl( session, urlW, &options, &info );
error = GetLastError();
ok( !ret, "expected failure\n" );
ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error );
options.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT | WINHTTP_AUTOPROXY_CONFIG_URL;
options.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DNS_A;
SetLastError(0xdeadbeef);
ret = WinHttpGetProxyForUrl( session, urlW, &options, &info );
error = GetLastError();
ok( !ret, "expected failure\n" );
ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error );
options.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT;
options.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DNS_A;
memset( &info, 0, sizeof(info) );
ret = WinHttpGetProxyForUrl( session, urlW, &options, &info );
if (ret)
{
trace("%u\n", info.dwAccessType);
trace("%s\n", wine_dbgstr_w(info.lpszProxy));
trace("%s\n", wine_dbgstr_w(info.lpszProxyBypass));
GlobalFree( (WCHAR *)info.lpszProxy );
GlobalFree( (WCHAR *)info.lpszProxyBypass );
}
WinHttpCloseHandle( session );
}
START_TEST (winhttp)
{
static const WCHAR basicW[] = {'/','b','a','s','i','c',0};
@ -2605,6 +2693,7 @@ START_TEST (winhttp)
test_IWinHttpRequest();
test_WinHttpDetectAutoProxyConfigUrl();
test_WinHttpGetIEProxyConfigForCurrentUser();
test_WinHttpGetProxyForUrl();
si.event = CreateEvent(NULL, 0, 0, NULL);
si.port = 7532;

View File

@ -506,6 +506,11 @@ typedef VOID (CALLBACK *WINHTTP_STATUS_CALLBACK)(HINTERNET,DWORD_PTR,DWORD,LPVOI
#define WINHTTP_AUTO_DETECT_TYPE_DHCP 0x00000001
#define WINHTTP_AUTO_DETECT_TYPE_DNS_A 0x00000002
#define WINHTTP_AUTOPROXY_AUTO_DETECT 0x00000001
#define WINHTTP_AUTOPROXY_CONFIG_URL 0x00000002
#define WINHTTP_AUTOPROXY_RUN_INPROCESS 0x00010000
#define WINHTTP_AUTOPROXY_RUN_OUTPROCESS_ONLY 0x00020000
typedef struct
{
DWORD dwFlags;