From ac322153b65363093419a520cdbbc9d71e2dab96 Mon Sep 17 00:00:00 2001 From: winesync Date: Fri, 3 Jan 2025 15:13:56 -0500 Subject: [PATCH] [WINHTTP] Winesync to Wine-10.0 --- dll/win32/winhttp/CMakeLists.txt | 9 +- dll/win32/winhttp/cookie.c | 107 +- dll/win32/winhttp/handle.c | 31 +- dll/win32/winhttp/inet_ntop.c | 7 + dll/win32/winhttp/main.c | 29 +- dll/win32/winhttp/net.c | 510 ++- dll/win32/winhttp/precomp.h | 2 +- dll/win32/winhttp/request.c | 3551 ++++++++++----- dll/win32/winhttp/session.c | 1273 ++++-- dll/win32/winhttp/url.c | 106 +- dll/win32/winhttp/winhttp.spec | 18 + dll/win32/winhttp/winhttp_private.h | 297 +- media/doc/WINESYNC.txt | 2 +- .../rostests/winetests/winhttp/CMakeLists.txt | 1 + .../rostests/winetests/winhttp/notification.c | 1471 +++++- modules/rostests/winetests/winhttp/url.c | 314 +- modules/rostests/winetests/winhttp/winhttp.c | 3994 +++++++++++------ sdk/include/psdk/winhttp.h | 437 +- sdk/include/psdk/ws2def.h | 6 + sdk/tools/winesync/winhttp.cfg | 7 + 20 files changed, 8535 insertions(+), 3637 deletions(-) create mode 100644 sdk/tools/winesync/winhttp.cfg diff --git a/dll/win32/winhttp/CMakeLists.txt b/dll/win32/winhttp/CMakeLists.txt index bac4baaaa17..a635649a0c1 100644 --- a/dll/win32/winhttp/CMakeLists.txt +++ b/dll/win32/winhttp/CMakeLists.txt @@ -1,9 +1,10 @@ -remove_definitions(-D_WIN32_WINNT=0x502) +remove_definitions(-D_WIN32_WINNT=0x502 -D_CRT_NON_CONFORMING_SWPRINTFS) add_definitions(-D_WIN32_WINNT=0x600) add_definitions( - -D_WINE) + -D_WINE + -D_WINHTTP_INTERNAL_) spec2def(winhttp.dll winhttp.spec ADD_IMPORTLIB) @@ -26,8 +27,8 @@ add_library(winhttp MODULE ${CMAKE_CURRENT_BINARY_DIR}/winhttp.def) set_module_type(winhttp win32dll) -target_link_libraries(winhttp uuid wine) -add_delay_importlibs(winhttp oleaut32 crypt32 secur32) +target_link_libraries(winhttp uuid wine oldnames wine_dll_register) +add_delay_importlibs(winhttp oleaut32 crypt32 secur32 iphlpapi dhcpcsvc) add_importlibs(winhttp user32 advapi32 ws2_32 jsproxy kernel32_vista msvcrt kernel32 ntdll) add_dependencies(winhttp stdole2) add_pch(winhttp precomp.h SOURCE) diff --git a/dll/win32/winhttp/cookie.c b/dll/win32/winhttp/cookie.c index 40c11c6f71c..e1f75639ff8 100644 --- a/dll/win32/winhttp/cookie.c +++ b/dll/win32/winhttp/cookie.c @@ -16,12 +16,12 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include "config.h" -#include "ws2tcpip.h" #include +#include #include "windef.h" #include "winbase.h" +#include "ws2tcpip.h" #include "winhttp.h" #include "wine/debug.h" @@ -49,12 +49,12 @@ static struct domain *add_domain( struct session *session, WCHAR *name ) { struct domain *domain; - if (!(domain = heap_alloc_zero( sizeof(struct domain) ))) return NULL; + if (!(domain = calloc( 1, sizeof(*domain) ))) return NULL; list_init( &domain->entry ); list_init( &domain->cookies ); - domain->name = strdupW( name ); + domain->name = wcsdup( name ); list_add_tail( &session->cookie_cache, &domain->entry ); TRACE("%s\n", debugstr_w(domain->name)); @@ -69,7 +69,7 @@ static struct cookie *find_cookie( struct domain *domain, const WCHAR *path, con LIST_FOR_EACH( item, &domain->cookies ) { cookie = LIST_ENTRY( item, struct cookie, entry ); - if (!strcmpW( cookie->path, path ) && !strcmpW( cookie->name, name )) + if (!wcscmp( cookie->path, path ) && !wcscmp( cookie->name, name )) { TRACE("found %s=%s\n", debugstr_w(cookie->name), debugstr_w(cookie->value)); return cookie; @@ -82,17 +82,17 @@ static BOOL domain_match( const WCHAR *name, struct domain *domain, BOOL partial { TRACE("comparing %s with %s\n", debugstr_w(name), debugstr_w(domain->name)); - if (partial && !strstrW( name, domain->name )) return FALSE; - else if (!partial && strcmpW( name, domain->name )) return FALSE; + if (partial && !wcsstr( name, domain->name )) return FALSE; + else if (!partial && wcscmp( name, domain->name )) return FALSE; return TRUE; } static void free_cookie( struct cookie *cookie ) { - heap_free( cookie->name ); - heap_free( cookie->value ); - heap_free( cookie->path ); - heap_free( cookie ); + free( cookie->name ); + free( cookie->value ); + free( cookie->path ); + free( cookie ); } static void delete_cookie( struct cookie *cookie ) @@ -113,8 +113,8 @@ static void delete_domain( struct domain *domain ) } list_remove( &domain->entry ); - heap_free( domain->name ); - heap_free( domain ); + free( domain->name ); + free( domain ); } void destroy_cookies( struct session *session ) @@ -135,7 +135,7 @@ static BOOL add_cookie( struct session *session, struct cookie *cookie, WCHAR *d struct cookie *old_cookie; struct list *item; - if (!(cookie->path = strdupW( path ))) return FALSE; + if (!(cookie->path = wcsdup( path ))) return FALSE; EnterCriticalSection( &session->cs ); @@ -165,17 +165,17 @@ static struct cookie *parse_cookie( const WCHAR *string ) const WCHAR *p; int len; - if (!(p = strchrW( string, '=' ))) p = string + strlenW( string ); + if (!(p = wcschr( string, '=' ))) p = string + lstrlenW( string ); len = p - string; while (len && string[len - 1] == ' ') len--; if (!len) return NULL; - if (!(cookie = heap_alloc_zero( sizeof(struct cookie) ))) return NULL; + if (!(cookie = calloc( 1, sizeof(*cookie) ))) return NULL; list_init( &cookie->entry ); - if (!(cookie->name = heap_alloc( (len + 1) * sizeof(WCHAR) ))) + if (!(cookie->name = malloc( (len + 1) * sizeof(WCHAR) ))) { - heap_free( cookie ); + free( cookie ); return NULL; } memcpy( cookie->name, string, len * sizeof(WCHAR) ); @@ -184,10 +184,10 @@ static struct cookie *parse_cookie( const WCHAR *string ) if (*p++ == '=') { while (*p == ' ') p++; - len = strlenW( p ); + len = lstrlenW( p ); while (len && p[len - 1] == ' ') len--; - if (!(cookie->value = heap_alloc( (len + 1) * sizeof(WCHAR) ))) + if (!(cookie->value = malloc( (len + 1) * sizeof(WCHAR) ))) { free_cookie( cookie ); return NULL; @@ -207,9 +207,9 @@ struct attr static void free_attr( struct attr *attr ) { if (!attr) return; - heap_free( attr->name ); - heap_free( attr->value ); - heap_free( attr ); + free( attr->name ); + free( attr->value ); + free( attr ); } static struct attr *parse_attr( const WCHAR *str, int *used ) @@ -224,10 +224,10 @@ static struct attr *parse_attr( const WCHAR *str, int *used ) len = q - p; if (!len) return NULL; - if (!(attr = heap_alloc( sizeof(struct attr) ))) return NULL; - if (!(attr->name = heap_alloc( (len + 1) * sizeof(WCHAR) ))) + if (!(attr = malloc( sizeof(*attr) ))) return NULL; + if (!(attr->name = malloc( (len + 1) * sizeof(WCHAR) ))) { - heap_free( attr ); + free( attr ); return NULL; } memcpy( attr->name, p, len * sizeof(WCHAR) ); @@ -244,7 +244,7 @@ static struct attr *parse_attr( const WCHAR *str, int *used ) len = q - p; while (len && p[len - 1] == ' ') len--; - if (!(attr->value = heap_alloc( (len + 1) * sizeof(WCHAR) ))) + if (!(attr->value = malloc( (len + 1) * sizeof(WCHAR) ))) { free_attr( attr ); return NULL; @@ -262,8 +262,6 @@ static struct attr *parse_attr( const WCHAR *str, int *used ) BOOL set_cookies( struct request *request, const WCHAR *cookies ) { - static const WCHAR pathW[] = {'p','a','t','h',0}; - static const WCHAR domainW[] = {'d','o','m','a','i','n',0}; BOOL ret = FALSE; WCHAR *buffer, *p; WCHAR *cookie_domain = NULL, *cookie_path = NULL; @@ -272,27 +270,27 @@ BOOL set_cookies( struct request *request, const WCHAR *cookies ) struct cookie *cookie; int len, used; - len = strlenW( cookies ); - if (!(buffer = heap_alloc( (len + 1) * sizeof(WCHAR) ))) return FALSE; - strcpyW( buffer, cookies ); + len = lstrlenW( cookies ); + if (!(buffer = malloc( (len + 1) * sizeof(WCHAR) ))) return FALSE; + lstrcpyW( buffer, cookies ); p = buffer; while (*p && *p != ';') p++; if (*p == ';') *p++ = 0; if (!(cookie = parse_cookie( buffer ))) { - heap_free( buffer ); + free( buffer ); return FALSE; } - len = strlenW( p ); + len = lstrlenW( p ); while (len && (attr = parse_attr( p, &used ))) { - if (!strcmpiW( attr->name, domainW )) + if (!wcsicmp( attr->name, L"domain" )) { domain = attr; cookie_domain = attr->value; } - else if (!strcmpiW( attr->name, pathW )) + else if (!wcsicmp( attr->name, L"path" )) { path = attr; cookie_path = attr->value; @@ -305,26 +303,27 @@ BOOL set_cookies( struct request *request, const WCHAR *cookies ) len -= used; p += used; } - if (!cookie_domain && !(cookie_domain = strdupW( request->connect->servername ))) goto end; - if (!cookie_path && !(cookie_path = strdupW( request->path ))) goto end; + if (!cookie_domain && !(cookie_domain = wcsdup( request->connect->servername ))) goto end; + if (!cookie_path && !(cookie_path = wcsdup( request->path ))) goto end; - if ((p = strrchrW( cookie_path, '/' )) && p != cookie_path) *p = 0; + if ((p = wcsrchr( cookie_path, '/' )) && p != cookie_path) *p = 0; ret = add_cookie( session, cookie, cookie_domain, cookie_path ); end: if (!ret) free_cookie( cookie ); if (domain) free_attr( domain ); - else heap_free( cookie_domain ); + else free( cookie_domain ); if (path) free_attr( path ); - else heap_free( cookie_path ); - heap_free( buffer ); + else free( cookie_path ); + free( buffer ); return ret; } -BOOL add_cookie_headers( struct request *request ) +DWORD add_cookie_headers( struct request *request ) { struct list *domain_cursor; struct session *session = request->connect->session; + DWORD ret = ERROR_SUCCESS; EnterCriticalSection( &session->cs ); @@ -342,37 +341,37 @@ BOOL add_cookie_headers( struct request *request ) TRACE("comparing path %s with %s\n", debugstr_w(request->path), debugstr_w(cookie->path)); - if (strstrW( request->path, cookie->path ) == request->path) + if (wcsstr( request->path, cookie->path ) == request->path) { static const WCHAR cookieW[] = {'C','o','o','k','i','e',':',' '}; - int len, len_cookie = ARRAY_SIZE( cookieW ), len_name = strlenW( cookie->name ); + int len, len_cookie = ARRAY_SIZE( cookieW ), len_name = lstrlenW( cookie->name ); WCHAR *header; len = len_cookie + len_name; - if (cookie->value) len += strlenW( cookie->value ) + 1; - if (!(header = heap_alloc( (len + 1) * sizeof(WCHAR) ))) + if (cookie->value) len += lstrlenW( cookie->value ) + 1; + if (!(header = malloc( (len + 1) * sizeof(WCHAR) ))) { LeaveCriticalSection( &session->cs ); - return FALSE; + return ERROR_OUTOFMEMORY; } memcpy( header, cookieW, len_cookie * sizeof(WCHAR) ); - strcpyW( header + len_cookie, cookie->name ); + lstrcpyW( header + len_cookie, cookie->name ); if (cookie->value) { header[len_cookie + len_name] = '='; - strcpyW( header + len_cookie + len_name + 1, cookie->value ); + lstrcpyW( header + len_cookie + len_name + 1, cookie->value ); } TRACE("%s\n", debugstr_w(header)); - add_request_headers( request, header, len, - WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON ); - heap_free( header ); + ret = add_request_headers( request, header, len, + WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON ); + free( header ); } } } } LeaveCriticalSection( &session->cs ); - return TRUE; + return ret; } diff --git a/dll/win32/winhttp/handle.c b/dll/win32/winhttp/handle.c index 6711cd91727..6b68f7b4c23 100644 --- a/dll/win32/winhttp/handle.c +++ b/dll/win32/winhttp/handle.c @@ -18,12 +18,11 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include "config.h" -#include "ws2tcpip.h" #include #include "windef.h" #include "winbase.h" +#include "ws2tcpip.h" #include "winhttp.h" #include "wine/debug.h" @@ -49,7 +48,7 @@ static ULONG_PTR max_handles; struct object_header *addref_object( struct object_header *hdr ) { ULONG refs = InterlockedIncrement( &hdr->refs ); - TRACE("%p -> refcount = %d\n", hdr, refs); + TRACE( "%p -> refcount = %lu\n", hdr, refs ); return hdr; } @@ -65,22 +64,21 @@ struct object_header *grab_object( HINTERNET hinternet ) LeaveCriticalSection( &handle_cs ); - TRACE("handle 0x%lx -> %p\n", handle, hdr); + TRACE( "handle %Ix -> %p\n", handle, hdr ); return hdr; } void release_object( struct object_header *hdr ) { ULONG refs = InterlockedDecrement( &hdr->refs ); - TRACE("object %p refcount = %d\n", hdr, refs); + TRACE( "object %p refcount = %lu\n", hdr, refs ); if (!refs) { if (hdr->type == WINHTTP_HANDLE_TYPE_REQUEST) close_connection( (struct request *)hdr ); send_callback( hdr, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, &hdr->handle, sizeof(HINTERNET) ); - TRACE("destroying object %p\n", hdr); - if (hdr->type != WINHTTP_HANDLE_TYPE_SESSION) list_remove( &hdr->entry ); + TRACE( "destroying object %p\n", hdr ); hdr->vtbl->destroy( hdr ); } } @@ -90,21 +88,23 @@ HINTERNET alloc_handle( struct object_header *hdr ) struct object_header **p; ULONG_PTR handle, num; - list_init( &hdr->children ); hdr->handle = NULL; EnterCriticalSection( &handle_cs ); if (!max_handles) { num = HANDLE_CHUNK_SIZE; - if (!(p = heap_alloc_zero( sizeof(ULONG_PTR) * num ))) goto end; + if (!(p = calloc( 1, sizeof(*p) * num ))) goto end; handles = p; max_handles = num; } if (max_handles == next_handle) { + size_t new_size, old_size = max_handles * sizeof(*handles); num = max_handles * 2; - if (!(p = heap_realloc_zero( handles, sizeof(ULONG_PTR) * num ))) goto end; + new_size = num * sizeof(*handles); + if (!(p = realloc( handles, new_size ))) goto end; + memset( (char *)p + old_size, 0, new_size - old_size ); handles = p; max_handles = num; } @@ -124,7 +124,7 @@ BOOL free_handle( HINTERNET hinternet ) { BOOL ret = FALSE; ULONG_PTR handle = (ULONG_PTR)hinternet; - struct object_header *hdr = NULL, *child, *next; + struct object_header *hdr = NULL; EnterCriticalSection( &handle_cs ); @@ -134,7 +134,7 @@ BOOL free_handle( HINTERNET hinternet ) if (handles[handle]) { hdr = handles[handle]; - TRACE("destroying handle 0x%lx for object %p\n", handle + 1, hdr); + TRACE( "destroying handle %Ix for object %p\n", handle + 1, hdr ); handles[handle] = NULL; ret = TRUE; } @@ -144,11 +144,8 @@ BOOL free_handle( HINTERNET hinternet ) if (hdr) { - LIST_FOR_EACH_ENTRY_SAFE( child, next, &hdr->children, struct object_header, entry ) - { - TRACE("freeing child handle %p for parent handle 0x%lx\n", child->handle, handle + 1); - free_handle( child->handle ); - } + if (hdr->vtbl->handle_closing) + hdr->vtbl->handle_closing( hdr ); release_object( hdr ); } diff --git a/dll/win32/winhttp/inet_ntop.c b/dll/win32/winhttp/inet_ntop.c index 8e40e261e33..524e35a116e 100644 --- a/dll/win32/winhttp/inet_ntop.c +++ b/dll/win32/winhttp/inet_ntop.c @@ -191,3 +191,10 @@ inet_ntop6(const u_char *src, char *dst, size_t size) } #endif +/****************************************************************** + * DllCanUnloadNow (winhttp.@) + */ +HRESULT WINAPI DllCanUnloadNow(void) +{ + return S_FALSE; +} diff --git a/dll/win32/winhttp/main.c b/dll/win32/winhttp/main.c index e6c084b979b..e4449364386 100644 --- a/dll/win32/winhttp/main.c +++ b/dll/win32/winhttp/main.c @@ -16,13 +16,12 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#define COBJMACROS -#include "config.h" -#include "ws2tcpip.h" #include +#define COBJMACROS #include "windef.h" #include "winbase.h" +#include "ws2tcpip.h" #include "objbase.h" #include "rpcproxy.h" #include "httprequest.h" @@ -156,27 +155,3 @@ HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) if (!cf) return CLASS_E_CLASSNOTAVAILABLE; return IClassFactory_QueryInterface( cf, riid, ppv ); } - -/****************************************************************** - * DllCanUnloadNow (winhttp.@) - */ -HRESULT WINAPI DllCanUnloadNow(void) -{ - return S_FALSE; -} - -/*********************************************************************** - * DllRegisterServer (winhttp.@) - */ -HRESULT WINAPI DllRegisterServer(void) -{ - return __wine_register_resources( winhttp_instance ); -} - -/*********************************************************************** - * DllUnregisterServer (winhttp.@) - */ -HRESULT WINAPI DllUnregisterServer(void) -{ - return __wine_unregister_resources( winhttp_instance ); -} diff --git a/dll/win32/winhttp/net.c b/dll/win32/winhttp/net.c index fcec7adde92..9d4254737e7 100644 --- a/dll/win32/winhttp/net.c +++ b/dll/win32/winhttp/net.c @@ -17,33 +17,57 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include "config.h" -#define NONAMELESSUNION -#include "ws2tcpip.h" -#include -#include #include +#include #include "windef.h" #include "winbase.h" +#include "ws2tcpip.h" #include "winhttp.h" #include "schannel.h" +#include "winternl.h" #include "wine/debug.h" -#include "wine/library.h" #include "winhttp_private.h" WINE_DEFAULT_DEBUG_CHANNEL(winhttp); -static int sock_send(int fd, const void *msg, size_t len, int flags) +static int sock_send(int fd, const void *msg, size_t len, WSAOVERLAPPED *ovr) { - int ret; - do + WSABUF wsabuf; + DWORD size; + int err; + + wsabuf.len = len; + wsabuf.buf = (void *)msg; + + if (!WSASend( (SOCKET)fd, &wsabuf, 1, &size, 0, ovr, NULL )) { - if ((ret = send(fd, msg, len, flags)) == -1) WARN("send error %u\n", WSAGetLastError()); + assert( size == len ); + return size; } - while(ret == -1 && WSAGetLastError() == WSAEINTR); - return ret; + err = WSAGetLastError(); + if (!(ovr && err == WSA_IO_PENDING)) WARN( "send error %d\n", err ); + return -1; +} + +BOOL netconn_wait_overlapped_result( struct netconn *conn, WSAOVERLAPPED *ovr, DWORD *len ) +{ + OVERLAPPED *completion_ovr; + ULONG_PTR key; + + while (1) + { + if (!GetQueuedCompletionStatus( conn->port, len, &key, &completion_ovr, INFINITE )) + { + WARN( "GetQueuedCompletionStatus failed, err %lu.\n", GetLastError() ); + return FALSE; + } + if (completion_ovr == (OVERLAPPED *)ovr && (key == conn->socket || conn->socket == -1)) + break; + ERR( "Unexpected completion key %Ix, completion ovr %p, ovr %p.\n", key, completion_ovr, ovr ); + } + return TRUE; } static int sock_recv(int fd, void *msg, size_t len, int flags) @@ -51,7 +75,7 @@ static int sock_recv(int fd, void *msg, size_t len, int flags) int ret; do { - if ((ret = recv(fd, msg, len, flags)) == -1) WARN("recv error %u\n", WSAGetLastError()); + if ((ret = recv(fd, msg, len, flags)) == -1) WARN( "recv error %d\n", WSAGetLastError() ); } while(ret == -1 && WSAGetLastError() == WSAEINTR); return ret; @@ -87,8 +111,10 @@ static DWORD netconn_verify_cert( PCCERT_CONTEXT cert, WCHAR *server, DWORD secu if (!(security_flags & SECURITY_FLAG_IGNORE_CERT_DATE_INVALID)) err = ERROR_WINHTTP_SECURE_CERT_DATE_INVALID; } - else if (chain->TrustStatus.dwErrorStatus & - CERT_TRUST_IS_UNTRUSTED_ROOT) + else if ((chain->TrustStatus.dwErrorStatus & + CERT_TRUST_IS_UNTRUSTED_ROOT) || + (chain->TrustStatus.dwErrorStatus & + CERT_TRUST_IS_PARTIAL_CHAIN)) { if (!(security_flags & SECURITY_FLAG_IGNORE_UNKNOWN_CA)) err = ERROR_WINHTTP_SECURE_INVALID_CA; @@ -122,7 +148,7 @@ static DWORD netconn_verify_cert( PCCERT_CONTEXT cert, WCHAR *server, DWORD secu */ memcpy(&chainCopy, chain, sizeof(chainCopy)); chainCopy.TrustStatus.dwErrorStatus = 0; - sslExtraPolicyPara.u.cbSize = sizeof(sslExtraPolicyPara); + sslExtraPolicyPara.cbSize = sizeof(sslExtraPolicyPara); sslExtraPolicyPara.dwAuthType = AUTHTYPE_SERVER; sslExtraPolicyPara.pwszServerName = server; sslExtraPolicyPara.fdwChecks = security_flags; @@ -147,7 +173,7 @@ static DWORD netconn_verify_cert( PCCERT_CONTEXT cert, WCHAR *server, DWORD secu } else err = ERROR_WINHTTP_SECURE_CHANNEL_ERROR; - TRACE("returning %08x\n", err); + TRACE( "returning %#lx\n", err ); return err; } @@ -183,26 +209,30 @@ static void set_blocking( struct netconn *conn, BOOL blocking ) ioctlsocket( conn->socket, FIONBIO, &state ); } -struct netconn *netconn_create( struct hostdata *host, const struct sockaddr_storage *sockaddr, int timeout ) +DWORD netconn_create( struct hostdata *host, const struct sockaddr_storage *sockaddr, int timeout, + struct netconn **ret_conn ) { struct netconn *conn; unsigned int addr_len; - BOOL ret = FALSE; + DWORD ret; #ifndef __REACTOS__ winsock_init(); #endif - conn = heap_alloc_zero(sizeof(*conn)); - if (!conn) return NULL; + if (!(conn = calloc( 1, sizeof(*conn) ))) return ERROR_OUTOFMEMORY; + conn->refs = 1; conn->host = host; conn->sockaddr = *sockaddr; - if ((conn->socket = socket( sockaddr->ss_family, SOCK_STREAM, 0 )) == -1) + if ((conn->socket = WSASocketW( sockaddr->ss_family, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED )) == -1) { - WARN("unable to create socket (%u)\n", WSAGetLastError()); - heap_free(conn); - return NULL; + ret = WSAGetLastError(); + WARN( "unable to create socket (%lu)\n", ret ); + free( conn ); + return ret; } + if (!SetFileCompletionNotificationModes( (HANDLE)(UINT_PTR)conn->socket, FILE_SKIP_COMPLETION_PORT_ON_SUCCESS )) + ERR( "SetFileCompletionNotificationModes failed.\n" ); switch (conn->sockaddr.ss_family) { @@ -213,56 +243,77 @@ struct netconn *netconn_create( struct hostdata *host, const struct sockaddr_sto addr_len = sizeof(struct sockaddr_in6); break; default: - assert(0); + ERR( "unhandled family %u\n", conn->sockaddr.ss_family ); + free( conn ); + return ERROR_INVALID_PARAMETER; } if (timeout > 0) set_blocking( conn, FALSE ); - if (!connect( conn->socket, (const struct sockaddr *)&conn->sockaddr, addr_len )) ret = TRUE; + if (!connect( conn->socket, (const struct sockaddr *)&conn->sockaddr, addr_len )) ret = ERROR_SUCCESS; else { - DWORD err = WSAGetLastError(); - if (err == WSAEWOULDBLOCK || err == WSAEINPROGRESS) + ret = WSAGetLastError(); + if (ret == WSAEWOULDBLOCK || ret == WSAEINPROGRESS) { - FD_SET set; - TIMEVAL timeval = { 0, timeout * 1000 }; + TIMEVAL timeval = { timeout / 1000, (timeout % 1000) * 1000 }; + FD_SET set_read, set_error; int res; - FD_ZERO( &set ); - FD_SET( conn->socket, &set ); - if ((res = select( conn->socket + 1, NULL, &set, NULL, &timeval )) > 0) ret = TRUE; - else if (!res) SetLastError( ERROR_WINHTTP_TIMEOUT ); + FD_ZERO( &set_read ); + FD_SET( conn->socket, &set_read ); + FD_ZERO( &set_error ); + FD_SET( conn->socket, &set_error ); + if ((res = select( conn->socket + 1, NULL, &set_read, &set_error, &timeval )) > 0) + { + if (FD_ISSET(conn->socket, &set_read)) ret = ERROR_SUCCESS; + else assert( FD_ISSET(conn->socket, &set_error) ); + } + else if (!res) ret = ERROR_WINHTTP_TIMEOUT; } } if (timeout > 0) set_blocking( conn, TRUE ); - if (!ret) + if (ret) { - WARN("unable to connect to host (%u)\n", GetLastError()); + WARN( "unable to connect to host (%lu)\n", ret ); closesocket( conn->socket ); - heap_free( conn ); - return NULL; + free( conn ); + return ret == ERROR_WINHTTP_TIMEOUT ? ERROR_WINHTTP_TIMEOUT : ERROR_WINHTTP_CANNOT_CONNECT; } - return conn; + + *ret_conn = conn; + return ERROR_SUCCESS; } -void netconn_close( struct netconn *conn ) +void netconn_addref( struct netconn *conn ) { + InterlockedIncrement( &conn->refs ); +} + +void netconn_release( struct netconn *conn ) +{ + if (InterlockedDecrement( &conn->refs )) return; + TRACE( "Closing connection %p.\n", conn ); if (conn->secure) { - heap_free( conn->peek_msg_mem ); - heap_free(conn->ssl_buf); - heap_free(conn->extra_buf); + free( conn->peek_msg_mem ); + free(conn->ssl_read_buf); + free(conn->ssl_write_buf); + free(conn->extra_buf); DeleteSecurityContext(&conn->ssl_ctx); } - closesocket( conn->socket ); + if (conn->socket != -1) + closesocket( conn->socket ); release_host( conn->host ); - heap_free(conn); + if (conn->port) + CloseHandle( conn->port ); + free(conn); } -BOOL netconn_secure_connect( struct netconn *conn, WCHAR *hostname, DWORD security_flags, CredHandle *cred_handle, - BOOL check_revocation) +DWORD netconn_secure_connect( struct netconn *conn, WCHAR *hostname, DWORD security_flags, CredHandle *cred_handle, + BOOL check_revocation ) { SecBuffer out_buf = {0, SECBUFFER_TOKEN, NULL}, in_bufs[2] = {{0, SECBUFFER_TOKEN}, {0, SECBUFFER_EMPTY}}; SecBufferDesc out_desc = {SECBUFFER_VERSION, 1, &out_buf}, in_desc = {SECBUFFER_VERSION, 2, in_bufs}; @@ -278,10 +329,9 @@ BOOL netconn_secure_connect( struct netconn *conn, WCHAR *hostname, DWORD securi const DWORD isc_req_flags = ISC_REQ_ALLOCATE_MEMORY|ISC_REQ_USE_SESSION_KEY|ISC_REQ_CONFIDENTIALITY |ISC_REQ_SEQUENCE_DETECT|ISC_REQ_REPLAY_DETECT|ISC_REQ_MANUAL_CRED_VALIDATION; - read_buf = heap_alloc(read_buf_size); - if(!read_buf) - return FALSE; + if (!(read_buf = malloc( read_buf_size ))) return ERROR_OUTOFMEMORY; + memset( &ctx, 0, sizeof(ctx) ); status = InitializeSecurityContextW(cred_handle, NULL, hostname, isc_req_flags, 0, 0, NULL, 0, &ctx, &out_desc, &attrs, NULL); @@ -291,9 +341,9 @@ BOOL netconn_secure_connect( struct netconn *conn, WCHAR *hostname, DWORD securi if(out_buf.cbBuffer) { assert(status == SEC_I_CONTINUE_NEEDED); - TRACE("sending %u bytes\n", out_buf.cbBuffer); + TRACE( "sending %lu bytes\n", out_buf.cbBuffer ); - size = sock_send(conn->socket, out_buf.pvBuffer, out_buf.cbBuffer, 0); + size = sock_send(conn->socket, out_buf.pvBuffer, out_buf.cbBuffer, NULL); if(size != out_buf.cbBuffer) { ERR("send failed\n"); res = ERROR_WINHTTP_SECURE_CHANNEL_ERROR; @@ -310,19 +360,17 @@ BOOL netconn_secure_connect( struct netconn *conn, WCHAR *hostname, DWORD securi memmove(read_buf, (BYTE*)in_bufs[0].pvBuffer+in_bufs[0].cbBuffer-in_bufs[1].cbBuffer, in_bufs[1].cbBuffer); in_bufs[0].cbBuffer = in_bufs[1].cbBuffer; - - in_bufs[1].BufferType = SECBUFFER_EMPTY; - in_bufs[1].cbBuffer = 0; - in_bufs[1].pvBuffer = NULL; } assert(in_bufs[0].BufferType == SECBUFFER_TOKEN); - assert(in_bufs[1].BufferType == SECBUFFER_EMPTY); + in_bufs[1].BufferType = SECBUFFER_EMPTY; + in_bufs[1].cbBuffer = 0; + in_bufs[1].pvBuffer = NULL; if(in_bufs[0].cbBuffer + 1024 > read_buf_size) { BYTE *new_read_buf; - new_read_buf = heap_realloc(read_buf, read_buf_size + 1024); + new_read_buf = realloc(read_buf, read_buf_size + 1024); if(!new_read_buf) { status = E_OUTOFMEMORY; break; @@ -338,13 +386,13 @@ BOOL netconn_secure_connect( struct netconn *conn, WCHAR *hostname, DWORD securi break; } - TRACE("recv %lu bytes\n", size); + TRACE( "recv %Iu bytes\n", size ); in_bufs[0].cbBuffer += size; in_bufs[0].pvBuffer = read_buf; status = InitializeSecurityContextW(cred_handle, &ctx, hostname, isc_req_flags, 0, 0, &in_desc, 0, NULL, &out_desc, &attrs, NULL); - TRACE("InitializeSecurityContext ret %08x\n", status); + TRACE( "InitializeSecurityContext ret %#lx\n", status ); if(status == SEC_E_OK) { if(in_bufs[1].BufferType == SECBUFFER_EXTRA) @@ -361,7 +409,7 @@ BOOL netconn_secure_connect( struct netconn *conn, WCHAR *hostname, DWORD securi res = netconn_verify_cert(cert, hostname, security_flags, check_revocation); CertFreeCertificateContext(cert); if(res != ERROR_SUCCESS) { - WARN("cert verify failed: %u\n", res); + WARN( "cert verify failed: %lu\n", res ); break; } }else { @@ -369,83 +417,108 @@ BOOL netconn_secure_connect( struct netconn *conn, WCHAR *hostname, DWORD securi break; } - conn->ssl_buf = heap_alloc(conn->ssl_sizes.cbHeader + conn->ssl_sizes.cbMaximumMessage + conn->ssl_sizes.cbTrailer); - if(!conn->ssl_buf) { - res = GetLastError(); + conn->ssl_read_buf = malloc(conn->ssl_sizes.cbHeader + conn->ssl_sizes.cbMaximumMessage + conn->ssl_sizes.cbTrailer); + if(!conn->ssl_read_buf) { + res = ERROR_OUTOFMEMORY; + break; + } + conn->ssl_write_buf = malloc(conn->ssl_sizes.cbHeader + conn->ssl_sizes.cbMaximumMessage + conn->ssl_sizes.cbTrailer); + if(!conn->ssl_write_buf) { + res = ERROR_OUTOFMEMORY; break; } } } - heap_free(read_buf); + free(read_buf); if(status != SEC_E_OK || res != ERROR_SUCCESS) { - WARN("Failed to initialize security context failed: %08x\n", status); - heap_free(conn->ssl_buf); - conn->ssl_buf = NULL; + WARN( "Failed to initialize security context: %#lx\n", status ); + free(conn->ssl_read_buf); + conn->ssl_read_buf = NULL; + free(conn->ssl_write_buf); + conn->ssl_write_buf = NULL; DeleteSecurityContext(&ctx); - SetLastError(res ? res : ERROR_WINHTTP_SECURE_CHANNEL_ERROR); - return FALSE; + return ERROR_WINHTTP_SECURE_CHANNEL_ERROR; } TRACE("established SSL connection\n"); conn->secure = TRUE; conn->ssl_ctx = ctx; - return TRUE; + return ERROR_SUCCESS; } -static BOOL send_ssl_chunk(struct netconn *conn, const void *msg, size_t size) +static DWORD send_ssl_chunk( struct netconn *conn, const void *msg, size_t size, WSAOVERLAPPED *ovr ) { SecBuffer bufs[4] = { - {conn->ssl_sizes.cbHeader, SECBUFFER_STREAM_HEADER, conn->ssl_buf}, - {size, SECBUFFER_DATA, conn->ssl_buf+conn->ssl_sizes.cbHeader}, - {conn->ssl_sizes.cbTrailer, SECBUFFER_STREAM_TRAILER, conn->ssl_buf+conn->ssl_sizes.cbHeader+size}, + {conn->ssl_sizes.cbHeader, SECBUFFER_STREAM_HEADER, conn->ssl_write_buf}, + {size, SECBUFFER_DATA, conn->ssl_write_buf+conn->ssl_sizes.cbHeader}, + {conn->ssl_sizes.cbTrailer, SECBUFFER_STREAM_TRAILER, conn->ssl_write_buf+conn->ssl_sizes.cbHeader+size}, {0, SECBUFFER_EMPTY, NULL} }; SecBufferDesc buf_desc = {SECBUFFER_VERSION, ARRAY_SIZE(bufs), bufs}; SECURITY_STATUS res; - memcpy(bufs[1].pvBuffer, msg, size); - res = EncryptMessage(&conn->ssl_ctx, 0, &buf_desc, 0); - if(res != SEC_E_OK) { - WARN("EncryptMessage failed\n"); - return FALSE; + memcpy( bufs[1].pvBuffer, msg, size ); + if ((res = EncryptMessage(&conn->ssl_ctx, 0, &buf_desc, 0)) != SEC_E_OK) + { + WARN( "EncryptMessage failed: %#lx\n", res ); + return res; } - if(sock_send(conn->socket, conn->ssl_buf, bufs[0].cbBuffer+bufs[1].cbBuffer+bufs[2].cbBuffer, 0) < 1) { + if (sock_send( conn->socket, conn->ssl_write_buf, bufs[0].cbBuffer + bufs[1].cbBuffer + bufs[2].cbBuffer, ovr ) < 1) + { WARN("send failed\n"); - return FALSE; + return WSAGetLastError(); } - return TRUE; + return ERROR_SUCCESS; } -BOOL netconn_send( struct netconn *conn, const void *msg, size_t len, int *sent ) +DWORD netconn_send( struct netconn *conn, const void *msg, size_t len, int *sent, WSAOVERLAPPED *ovr ) { + DWORD err; + + if (ovr && !conn->port) + { + if (!(conn->port = CreateIoCompletionPort( (HANDLE)(SOCKET)conn->socket, NULL, (ULONG_PTR)conn->socket, 0 ))) + ERR( "Failed to create port.\n" ); + } + if (conn->secure) { const BYTE *ptr = msg; size_t chunk_size; + DWORD res; *sent = 0; - - while(len) { - chunk_size = min(len, conn->ssl_sizes.cbMaximumMessage); - if(!send_ssl_chunk(conn, ptr, chunk_size)) - return FALSE; - + while (len) + { + chunk_size = min( len, conn->ssl_sizes.cbMaximumMessage ); + if ((res = send_ssl_chunk( conn, ptr, chunk_size, ovr ))) + { + if (res == WSA_IO_PENDING) *sent += chunk_size; + return res; + } *sent += chunk_size; ptr += chunk_size; len -= chunk_size; } - return TRUE; + return ERROR_SUCCESS; } - return ((*sent = sock_send( conn->socket, msg, len, 0 )) != -1); + + if ((*sent = sock_send( conn->socket, msg, len, ovr )) < 0) + { + err = WSAGetLastError(); + *sent = (err == WSA_IO_PENDING) ? len : 0; + return err; + } + return ERROR_SUCCESS; } -static BOOL read_ssl_chunk(struct netconn *conn, void *buf, SIZE_T buf_size, SIZE_T *ret_size, BOOL *eof) +static DWORD read_ssl_chunk( struct netconn *conn, void *buf, SIZE_T buf_size, SIZE_T *ret_size, BOOL *eof ) { const SIZE_T ssl_buf_size = conn->ssl_sizes.cbHeader+conn->ssl_sizes.cbMaximumMessage+conn->ssl_sizes.cbTrailer; SecBuffer bufs[4]; @@ -457,19 +530,19 @@ static BOOL read_ssl_chunk(struct netconn *conn, void *buf, SIZE_T buf_size, SIZ assert(conn->extra_len < ssl_buf_size); if(conn->extra_len) { - memcpy(conn->ssl_buf, conn->extra_buf, conn->extra_len); + memcpy(conn->ssl_read_buf, conn->extra_buf, conn->extra_len); buf_len = conn->extra_len; conn->extra_len = 0; - heap_free(conn->extra_buf); + free(conn->extra_buf); conn->extra_buf = NULL; }else { - buf_len = sock_recv(conn->socket, conn->ssl_buf+conn->extra_len, ssl_buf_size-conn->extra_len, 0); - if(buf_len < 0) - return FALSE; + if ((buf_len = sock_recv( conn->socket, conn->ssl_read_buf + conn->extra_len, ssl_buf_size - conn->extra_len, 0)) < 0) + return WSAGetLastError(); - if(!buf_len) { + if (!buf_len) + { *eof = TRUE; - return TRUE; + return ERROR_SUCCESS; } } @@ -480,30 +553,36 @@ static BOOL read_ssl_chunk(struct netconn *conn, void *buf, SIZE_T buf_size, SIZ memset(bufs, 0, sizeof(bufs)); bufs[0].BufferType = SECBUFFER_DATA; bufs[0].cbBuffer = buf_len; - bufs[0].pvBuffer = conn->ssl_buf; + bufs[0].pvBuffer = conn->ssl_read_buf; - res = DecryptMessage(&conn->ssl_ctx, &buf_desc, 0, NULL); - switch(res) { + switch ((res = DecryptMessage( &conn->ssl_ctx, &buf_desc, 0, NULL ))) + { case SEC_E_OK: break; + + case SEC_I_RENEGOTIATE: + TRACE("renegotiate\n"); + return ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED; + case SEC_I_CONTEXT_EXPIRED: TRACE("context expired\n"); *eof = TRUE; - return TRUE; + return ERROR_SUCCESS; + case SEC_E_INCOMPLETE_MESSAGE: assert(buf_len < ssl_buf_size); - size = sock_recv(conn->socket, conn->ssl_buf+buf_len, ssl_buf_size-buf_len, 0); - if(size < 1) - return FALSE; + if ((size = sock_recv( conn->socket, conn->ssl_read_buf + buf_len, ssl_buf_size - buf_len, 0 )) < 1) + return SEC_E_INCOMPLETE_MESSAGE; buf_len += size; continue; + default: - WARN("failed: %08x\n", res); - return FALSE; + WARN( "failed: %#lx\n", res ); + return res; } - } while(res != SEC_E_OK); + } while (res != SEC_E_OK); for(i = 0; i < ARRAY_SIZE(bufs); i++) { if(bufs[i].BufferType == SECBUFFER_DATA) { @@ -511,9 +590,9 @@ static BOOL read_ssl_chunk(struct netconn *conn, void *buf, SIZE_T buf_size, SIZ memcpy(buf, bufs[i].pvBuffer, size); if(size < bufs[i].cbBuffer) { assert(!conn->peek_len); - conn->peek_msg_mem = conn->peek_msg = heap_alloc(bufs[i].cbBuffer - size); + conn->peek_msg_mem = conn->peek_msg = malloc(bufs[i].cbBuffer - size); if(!conn->peek_msg) - return FALSE; + return ERROR_OUTOFMEMORY; conn->peek_len = bufs[i].cbBuffer-size; memcpy(conn->peek_msg, (char*)bufs[i].pvBuffer+size, conn->peek_len); } @@ -524,27 +603,28 @@ static BOOL read_ssl_chunk(struct netconn *conn, void *buf, SIZE_T buf_size, SIZ for(i = 0; i < ARRAY_SIZE(bufs); i++) { if(bufs[i].BufferType == SECBUFFER_EXTRA) { - conn->extra_buf = heap_alloc(bufs[i].cbBuffer); + conn->extra_buf = malloc(bufs[i].cbBuffer); if(!conn->extra_buf) - return FALSE; + return ERROR_OUTOFMEMORY; conn->extra_len = bufs[i].cbBuffer; memcpy(conn->extra_buf, bufs[i].pvBuffer, conn->extra_len); } } - return TRUE; + return ERROR_SUCCESS; } -BOOL netconn_recv( struct netconn *conn, void *buf, size_t len, int flags, int *recvd ) +DWORD netconn_recv( struct netconn *conn, void *buf, size_t len, int flags, int *recvd ) { *recvd = 0; - if (!len) return TRUE; + if (!len) return ERROR_SUCCESS; if (conn->secure) { - SIZE_T size, cread; - BOOL res, eof; + SIZE_T size; + DWORD res; + BOOL eof; if (conn->peek_msg) { @@ -555,37 +635,47 @@ BOOL netconn_recv( struct netconn *conn, void *buf, size_t len, int flags, int * if (conn->peek_len == 0) { - heap_free( conn->peek_msg_mem ); + free( conn->peek_msg_mem ); conn->peek_msg_mem = NULL; conn->peek_msg = NULL; } /* check if we have enough data from the peek buffer */ - if (!(flags & MSG_WAITALL) || *recvd == len) return TRUE; + if (!(flags & MSG_WAITALL) || *recvd == len) return ERROR_SUCCESS; } size = *recvd; - do { - res = read_ssl_chunk(conn, (BYTE*)buf+size, len-size, &cread, &eof); - if(!res) { - WARN("read_ssl_chunk failed\n"); - if(!size) - return FALSE; + do + { + SIZE_T cread = 0; + if ((res = read_ssl_chunk( conn, (BYTE *)buf + size, len - size, &cread, &eof ))) + { + WARN( "read_ssl_chunk failed: %lu\n", res ); + if (!size) return res; break; } - - if(eof) { + if (eof) + { TRACE("EOF\n"); break; } - size += cread; - }while(!size || ((flags & MSG_WAITALL) && size < len)); - TRACE("received %ld bytes\n", size); + } while (!size || ((flags & MSG_WAITALL) && size < len)); + + TRACE( "received %Iu bytes\n", size ); *recvd = size; - return TRUE; + return ERROR_SUCCESS; } - return ((*recvd = sock_recv( conn->socket, buf, len, flags )) != -1); + + if ((*recvd = sock_recv( conn->socket, buf, len, flags )) < 0) return WSAGetLastError(); + return ERROR_SUCCESS; +} + +void netconn_cancel_io( struct netconn *conn ) +{ + SOCKET socket = InterlockedExchange( (LONG *)&conn->socket, -1 ); + + closesocket( socket ); } ULONG netconn_query_data_available( struct netconn *conn ) @@ -599,7 +689,7 @@ DWORD netconn_set_timeout( struct netconn *netconn, BOOL send, int value ) if (setsockopt( netconn->socket, SOL_SOCKET, opt, (void *)&value, sizeof(value) ) == -1) { DWORD err = WSAGetLastError(); - WARN("setsockopt failed (%u)\n", err ); + WARN( "setsockopt failed (%lu)\n", err ); return err; } return ERROR_SUCCESS; @@ -607,11 +697,31 @@ DWORD netconn_set_timeout( struct netconn *netconn, BOOL send, int value ) BOOL netconn_is_alive( struct netconn *netconn ) { + SIZE_T size; int len; char b; DWORD err; + BOOL eof; set_blocking( netconn, FALSE ); + if (netconn->secure) + { + while (!netconn->peek_msg && !(err = read_ssl_chunk( netconn, NULL, 0, &size, &eof )) && !eof) + ; + + TRACE( "checking secure connection, err %lu\n", err ); + + if (netconn->peek_msg || err == WSAEWOULDBLOCK) + { + set_blocking( netconn, TRUE ); + return TRUE; + } + if (err != SEC_E_OK && err != SEC_E_INCOMPLETE_MESSAGE) + { + set_blocking( netconn, TRUE ); + return FALSE; + } + } len = sock_recv( netconn->socket, &b, 1, MSG_PEEK ); err = WSAGetLastError(); set_blocking( netconn, TRUE ); @@ -657,104 +767,86 @@ static DWORD resolve_hostname( const WCHAR *name, INTERNET_PORT port, struct soc return ERROR_SUCCESS; } -#ifdef __REACTOS__ - -struct resolve_args -{ - const WCHAR *hostname; - INTERNET_PORT port; - struct sockaddr_storage *sa; -}; - -static DWORD CALLBACK resolve_proc( LPVOID arg ) -{ - struct resolve_args *ra = arg; - return resolve_hostname( ra->hostname, ra->port, ra->sa ); -} - -BOOL netconn_resolve( WCHAR *hostname, INTERNET_PORT port, struct sockaddr_storage *sa, int timeout ) -{ - DWORD ret; - - if (timeout) - { - DWORD status; - HANDLE thread; - struct resolve_args ra; - - ra.hostname = hostname; - ra.port = port; - ra.sa = sa; - - thread = CreateThread( NULL, 0, resolve_proc, &ra, 0, NULL ); - if (!thread) return FALSE; - - status = WaitForSingleObject( thread, timeout ); - if (status == WAIT_OBJECT_0) GetExitCodeThread( thread, &ret ); - else ret = ERROR_WINHTTP_TIMEOUT; - CloseHandle( thread ); - } - else ret = resolve_hostname( hostname, port, sa ); - - if (ret) - { - SetLastError( ret ); - return FALSE; - } - return TRUE; -} - -#else /* __REACTOS__ */ - struct async_resolve { - const WCHAR *hostname; + LONG ref; + WCHAR *hostname; INTERNET_PORT port; - struct sockaddr_storage *addr; + struct sockaddr_storage addr; DWORD result; HANDLE done; }; +static struct async_resolve *create_async_resolve( const WCHAR *hostname, INTERNET_PORT port ) +{ + struct async_resolve *ret; + + if (!(ret = malloc(sizeof(*ret)))) + { + ERR( "No memory.\n" ); + return NULL; + } + ret->ref = 1; + ret->hostname = wcsdup( hostname ); + ret->port = port; + if (!(ret->done = CreateEventW( NULL, FALSE, FALSE, NULL ))) + { + free( ret->hostname ); + free( ret ); + return NULL; + } + return ret; +} + +static void async_resolve_release( struct async_resolve *async ) +{ + if (InterlockedDecrement( &async->ref )) return; + + free( async->hostname ); + CloseHandle( async->done ); + free( async ); +} + static void CALLBACK resolve_proc( TP_CALLBACK_INSTANCE *instance, void *ctx ) { struct async_resolve *async = ctx; - async->result = resolve_hostname( async->hostname, async->port, async->addr ); + + async->result = resolve_hostname( async->hostname, async->port, &async->addr ); SetEvent( async->done ); + async_resolve_release( async ); } -BOOL netconn_resolve( WCHAR *hostname, INTERNET_PORT port, struct sockaddr_storage *addr, int timeout ) +DWORD netconn_resolve( WCHAR *hostname, INTERNET_PORT port, struct sockaddr_storage *addr, int timeout ) { DWORD ret; if (!timeout) ret = resolve_hostname( hostname, port, addr ); else { - struct async_resolve async; + struct async_resolve *async; - async.hostname = hostname; - async.port = port; - async.addr = addr; - if (!(async.done = CreateEventW( NULL, FALSE, FALSE, NULL ))) return FALSE; - if (!TrySubmitThreadpoolCallback( resolve_proc, &async, NULL )) + if (!(async = create_async_resolve( hostname, port ))) + return ERROR_OUTOFMEMORY; + + InterlockedIncrement( &async->ref ); + if (!TrySubmitThreadpoolCallback( resolve_proc, async, NULL )) { - CloseHandle( async.done ); - return FALSE; + InterlockedDecrement( &async->ref ); + async_resolve_release( async ); + return GetLastError(); } - if (WaitForSingleObject( async.done, timeout ) != WAIT_OBJECT_0) ret = ERROR_WINHTTP_TIMEOUT; - else ret = async.result; - CloseHandle( async.done ); + if (WaitForSingleObject( async->done, timeout ) != WAIT_OBJECT_0) ret = ERROR_WINHTTP_TIMEOUT; + else + { + *addr = async->addr; + ret = async->result; + } + async_resolve_release( async ); } - if (ret) - { - SetLastError( ret ); - return FALSE; - } - return TRUE; + return ret; } -#endif /* __REACTOS__ */ - const void *netconn_get_certificate( struct netconn *conn ) { const CERT_CONTEXT *ret; @@ -773,6 +865,6 @@ int netconn_get_cipher_strength( struct netconn *conn ) if (!conn->secure) return 0; res = QueryContextAttributesW(&conn->ssl_ctx, SECPKG_ATTR_CONNECTION_INFO, (void*)&conn_info); if(res != SEC_E_OK) - WARN("QueryContextAttributesW failed: %08x\n", res); + WARN( "QueryContextAttributesW failed: %#lx\n", res ); return res == SEC_E_OK ? conn_info.dwCipherStrength : 0; } diff --git a/dll/win32/winhttp/precomp.h b/dll/win32/winhttp/precomp.h index 53f0b1365dc..6ac74e9690a 100644 --- a/dll/win32/winhttp/precomp.h +++ b/dll/win32/winhttp/precomp.h @@ -11,13 +11,13 @@ #define COM_NO_WINDOWS_H #define COBJMACROS -#define NONAMELESSUNION #include #include #include #include #include +#include #include diff --git a/dll/win32/winhttp/request.c b/dll/win32/winhttp/request.c index da28f7b1826..6a20c4ec439 100644 --- a/dll/win32/winhttp/request.c +++ b/dll/win32/winhttp/request.c @@ -19,20 +19,22 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#define COBJMACROS -#include "config.h" -#include "ws2tcpip.h" -#include #include +#include +#include +#define COBJMACROS #include "windef.h" #include "winbase.h" +#include "ws2tcpip.h" #include "ole2.h" #include "initguid.h" #include "httprequest.h" #include "httprequestid.h" #include "schannel.h" #include "winhttp.h" +#include "winternl.h" +#include "ntsecapi.h" #include "wine/debug.h" #include "winhttp_private.h" @@ -45,260 +47,243 @@ WINE_DEFAULT_DEBUG_CHANNEL(winhttp); #define DEFAULT_KEEP_ALIVE_TIMEOUT 30000 -static const WCHAR attr_accept[] = {'A','c','c','e','p','t',0}; -static const WCHAR attr_accept_charset[] = {'A','c','c','e','p','t','-','C','h','a','r','s','e','t', 0}; -static const WCHAR attr_accept_encoding[] = {'A','c','c','e','p','t','-','E','n','c','o','d','i','n','g',0}; -static const WCHAR attr_accept_language[] = {'A','c','c','e','p','t','-','L','a','n','g','u','a','g','e',0}; -static const WCHAR attr_accept_ranges[] = {'A','c','c','e','p','t','-','R','a','n','g','e','s',0}; -static const WCHAR attr_age[] = {'A','g','e',0}; -static const WCHAR attr_allow[] = {'A','l','l','o','w',0}; -static const WCHAR attr_authorization[] = {'A','u','t','h','o','r','i','z','a','t','i','o','n',0}; -static const WCHAR attr_cache_control[] = {'C','a','c','h','e','-','C','o','n','t','r','o','l',0}; -static const WCHAR attr_connection[] = {'C','o','n','n','e','c','t','i','o','n',0}; -static const WCHAR attr_content_base[] = {'C','o','n','t','e','n','t','-','B','a','s','e',0}; -static const WCHAR attr_content_encoding[] = {'C','o','n','t','e','n','t','-','E','n','c','o','d','i','n','g',0}; -static const WCHAR attr_content_id[] = {'C','o','n','t','e','n','t','-','I','D',0}; -static const WCHAR attr_content_language[] = {'C','o','n','t','e','n','t','-','L','a','n','g','u','a','g','e',0}; -static const WCHAR attr_content_length[] = {'C','o','n','t','e','n','t','-','L','e','n','g','t','h',0}; -static const WCHAR attr_content_location[] = {'C','o','n','t','e','n','t','-','L','o','c','a','t','i','o','n',0}; -static const WCHAR attr_content_md5[] = {'C','o','n','t','e','n','t','-','M','D','5',0}; -static const WCHAR attr_content_range[] = {'C','o','n','t','e','n','t','-','R','a','n','g','e',0}; -static const WCHAR attr_content_transfer_encoding[] = {'C','o','n','t','e','n','t','-','T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0}; -static const WCHAR attr_content_type[] = {'C','o','n','t','e','n','t','-','T','y','p','e',0}; -static const WCHAR attr_cookie[] = {'C','o','o','k','i','e',0}; -static const WCHAR attr_date[] = {'D','a','t','e',0}; -static const WCHAR attr_from[] = {'F','r','o','m',0}; -static const WCHAR attr_etag[] = {'E','T','a','g',0}; -static const WCHAR attr_expect[] = {'E','x','p','e','c','t',0}; -static const WCHAR attr_expires[] = {'E','x','p','i','r','e','s',0}; -static const WCHAR attr_host[] = {'H','o','s','t',0}; -static const WCHAR attr_if_match[] = {'I','f','-','M','a','t','c','h',0}; -static const WCHAR attr_if_modified_since[] = {'I','f','-','M','o','d','i','f','i','e','d','-','S','i','n','c','e',0}; -static const WCHAR attr_if_none_match[] = {'I','f','-','N','o','n','e','-','M','a','t','c','h',0}; -static const WCHAR attr_if_range[] = {'I','f','-','R','a','n','g','e',0}; -static const WCHAR attr_if_unmodified_since[] = {'I','f','-','U','n','m','o','d','i','f','i','e','d','-','S','i','n','c','e',0}; -static const WCHAR attr_last_modified[] = {'L','a','s','t','-','M','o','d','i','f','i','e','d',0}; -static const WCHAR attr_location[] = {'L','o','c','a','t','i','o','n',0}; -static const WCHAR attr_max_forwards[] = {'M','a','x','-','F','o','r','w','a','r','d','s',0}; -static const WCHAR attr_mime_version[] = {'M','i','m','e','-','V','e','r','s','i','o','n',0}; -static const WCHAR attr_pragma[] = {'P','r','a','g','m','a',0}; -static const WCHAR attr_proxy_authenticate[] = {'P','r','o','x','y','-','A','u','t','h','e','n','t','i','c','a','t','e',0}; -static const WCHAR attr_proxy_authorization[] = {'P','r','o','x','y','-','A','u','t','h','o','r','i','z','a','t','i','o','n',0}; -static const WCHAR attr_proxy_connection[] = {'P','r','o','x','y','-','C','o','n','n','e','c','t','i','o','n',0}; -static const WCHAR attr_public[] = {'P','u','b','l','i','c',0}; -static const WCHAR attr_range[] = {'R','a','n','g','e',0}; -static const WCHAR attr_referer[] = {'R','e','f','e','r','e','r',0}; -static const WCHAR attr_retry_after[] = {'R','e','t','r','y','-','A','f','t','e','r',0}; -static const WCHAR attr_server[] = {'S','e','r','v','e','r',0}; -static const WCHAR attr_set_cookie[] = {'S','e','t','-','C','o','o','k','i','e',0}; -static const WCHAR attr_status[] = {'S','t','a','t','u','s',0}; -static const WCHAR attr_transfer_encoding[] = {'T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0}; -static const WCHAR attr_unless_modified_since[] = {'U','n','l','e','s','s','-','M','o','d','i','f','i','e','d','-','S','i','n','c','e',0}; -static const WCHAR attr_upgrade[] = {'U','p','g','r','a','d','e',0}; -static const WCHAR attr_uri[] = {'U','R','I',0}; -static const WCHAR attr_user_agent[] = {'U','s','e','r','-','A','g','e','n','t',0}; -static const WCHAR attr_vary[] = {'V','a','r','y',0}; -static const WCHAR attr_via[] = {'V','i','a',0}; -static const WCHAR attr_warning[] = {'W','a','r','n','i','n','g',0}; -static const WCHAR attr_www_authenticate[] = {'W','W','W','-','A','u','t','h','e','n','t','i','c','a','t','e',0}; +#define ACTUAL_DEFAULT_RECEIVE_RESPONSE_TIMEOUT 21000 + +static int request_receive_response_timeout( struct request *req ) +{ + if (req->receive_response_timeout == -1) return ACTUAL_DEFAULT_RECEIVE_RESPONSE_TIMEOUT; + return req->receive_response_timeout; +} static const WCHAR *attribute_table[] = { - attr_mime_version, /* WINHTTP_QUERY_MIME_VERSION = 0 */ - attr_content_type, /* WINHTTP_QUERY_CONTENT_TYPE = 1 */ - attr_content_transfer_encoding, /* WINHTTP_QUERY_CONTENT_TRANSFER_ENCODING = 2 */ - attr_content_id, /* WINHTTP_QUERY_CONTENT_ID = 3 */ + L"Mime-Version", /* WINHTTP_QUERY_MIME_VERSION = 0 */ + L"Content-Type" , /* WINHTTP_QUERY_CONTENT_TYPE = 1 */ + L"Content-Transfer-Encoding", /* WINHTTP_QUERY_CONTENT_TRANSFER_ENCODING = 2 */ + L"Content-ID", /* WINHTTP_QUERY_CONTENT_ID = 3 */ NULL, /* WINHTTP_QUERY_CONTENT_DESCRIPTION = 4 */ - attr_content_length, /* WINHTTP_QUERY_CONTENT_LENGTH = 5 */ - attr_content_language, /* WINHTTP_QUERY_CONTENT_LANGUAGE = 6 */ - attr_allow, /* WINHTTP_QUERY_ALLOW = 7 */ - attr_public, /* WINHTTP_QUERY_PUBLIC = 8 */ - attr_date, /* WINHTTP_QUERY_DATE = 9 */ - attr_expires, /* WINHTTP_QUERY_EXPIRES = 10 */ - attr_last_modified, /* WINHTTP_QUERY_LAST_MODIFIEDcw = 11 */ + L"Content-Length", /* WINHTTP_QUERY_CONTENT_LENGTH = 5 */ + L"Content-Language", /* WINHTTP_QUERY_CONTENT_LANGUAGE = 6 */ + L"Allow", /* WINHTTP_QUERY_ALLOW = 7 */ + L"Public", /* WINHTTP_QUERY_PUBLIC = 8 */ + L"Date", /* WINHTTP_QUERY_DATE = 9 */ + L"Expires", /* WINHTTP_QUERY_EXPIRES = 10 */ + L"Last-Modified", /* WINHTTP_QUERY_LAST_MODIFIEDcw = 11 */ NULL, /* WINHTTP_QUERY_MESSAGE_ID = 12 */ - attr_uri, /* WINHTTP_QUERY_URI = 13 */ - attr_from, /* WINHTTP_QUERY_DERIVED_FROM = 14 */ + L"URI", /* WINHTTP_QUERY_URI = 13 */ + L"From", /* WINHTTP_QUERY_DERIVED_FROM = 14 */ NULL, /* WINHTTP_QUERY_COST = 15 */ NULL, /* WINHTTP_QUERY_LINK = 16 */ - attr_pragma, /* WINHTTP_QUERY_PRAGMA = 17 */ + L"Pragma", /* WINHTTP_QUERY_PRAGMA = 17 */ NULL, /* WINHTTP_QUERY_VERSION = 18 */ - attr_status, /* WINHTTP_QUERY_STATUS_CODE = 19 */ + L"Status", /* WINHTTP_QUERY_STATUS_CODE = 19 */ NULL, /* WINHTTP_QUERY_STATUS_TEXT = 20 */ NULL, /* WINHTTP_QUERY_RAW_HEADERS = 21 */ NULL, /* WINHTTP_QUERY_RAW_HEADERS_CRLF = 22 */ - attr_connection, /* WINHTTP_QUERY_CONNECTION = 23 */ - attr_accept, /* WINHTTP_QUERY_ACCEPT = 24 */ - attr_accept_charset, /* WINHTTP_QUERY_ACCEPT_CHARSET = 25 */ - attr_accept_encoding, /* WINHTTP_QUERY_ACCEPT_ENCODING = 26 */ - attr_accept_language, /* WINHTTP_QUERY_ACCEPT_LANGUAGE = 27 */ - attr_authorization, /* WINHTTP_QUERY_AUTHORIZATION = 28 */ - attr_content_encoding, /* WINHTTP_QUERY_CONTENT_ENCODING = 29 */ + L"Connection", /* WINHTTP_QUERY_CONNECTION = 23 */ + L"Accept", /* WINHTTP_QUERY_ACCEPT = 24 */ + L"Accept-Charset", /* WINHTTP_QUERY_ACCEPT_CHARSET = 25 */ + L"Accept-Encoding", /* WINHTTP_QUERY_ACCEPT_ENCODING = 26 */ + L"Accept-Language", /* WINHTTP_QUERY_ACCEPT_LANGUAGE = 27 */ + L"Authorization", /* WINHTTP_QUERY_AUTHORIZATION = 28 */ + L"Content-Encoding", /* WINHTTP_QUERY_CONTENT_ENCODING = 29 */ NULL, /* WINHTTP_QUERY_FORWARDED = 30 */ NULL, /* WINHTTP_QUERY_FROM = 31 */ - attr_if_modified_since, /* WINHTTP_QUERY_IF_MODIFIED_SINCE = 32 */ - attr_location, /* WINHTTP_QUERY_LOCATION = 33 */ + L"If-Modified-Since", /* WINHTTP_QUERY_IF_MODIFIED_SINCE = 32 */ + L"Location", /* WINHTTP_QUERY_LOCATION = 33 */ NULL, /* WINHTTP_QUERY_ORIG_URI = 34 */ - attr_referer, /* WINHTTP_QUERY_REFERER = 35 */ - attr_retry_after, /* WINHTTP_QUERY_RETRY_AFTER = 36 */ - attr_server, /* WINHTTP_QUERY_SERVER = 37 */ + L"Referer", /* WINHTTP_QUERY_REFERER = 35 */ + L"Retry-After", /* WINHTTP_QUERY_RETRY_AFTER = 36 */ + L"Server", /* WINHTTP_QUERY_SERVER = 37 */ NULL, /* WINHTTP_TITLE = 38 */ - attr_user_agent, /* WINHTTP_QUERY_USER_AGENT = 39 */ - attr_www_authenticate, /* WINHTTP_QUERY_WWW_AUTHENTICATE = 40 */ - attr_proxy_authenticate, /* WINHTTP_QUERY_PROXY_AUTHENTICATE = 41 */ - attr_accept_ranges, /* WINHTTP_QUERY_ACCEPT_RANGES = 42 */ - attr_set_cookie, /* WINHTTP_QUERY_SET_COOKIE = 43 */ - attr_cookie, /* WINHTTP_QUERY_COOKIE = 44 */ + L"User-Agent", /* WINHTTP_QUERY_USER_AGENT = 39 */ + L"WWW-Authenticate", /* WINHTTP_QUERY_WWW_AUTHENTICATE = 40 */ + L"Proxy-Authenticate", /* WINHTTP_QUERY_PROXY_AUTHENTICATE = 41 */ + L"Accept-Ranges", /* WINHTTP_QUERY_ACCEPT_RANGES = 42 */ + L"Set-Cookie", /* WINHTTP_QUERY_SET_COOKIE = 43 */ + L"Cookie", /* WINHTTP_QUERY_COOKIE = 44 */ NULL, /* WINHTTP_QUERY_REQUEST_METHOD = 45 */ NULL, /* WINHTTP_QUERY_REFRESH = 46 */ NULL, /* WINHTTP_QUERY_CONTENT_DISPOSITION = 47 */ - attr_age, /* WINHTTP_QUERY_AGE = 48 */ - attr_cache_control, /* WINHTTP_QUERY_CACHE_CONTROL = 49 */ - attr_content_base, /* WINHTTP_QUERY_CONTENT_BASE = 50 */ - attr_content_location, /* WINHTTP_QUERY_CONTENT_LOCATION = 51 */ - attr_content_md5, /* WINHTTP_QUERY_CONTENT_MD5 = 52 */ - attr_content_range, /* WINHTTP_QUERY_CONTENT_RANGE = 53 */ - attr_etag, /* WINHTTP_QUERY_ETAG = 54 */ - attr_host, /* WINHTTP_QUERY_HOST = 55 */ - attr_if_match, /* WINHTTP_QUERY_IF_MATCH = 56 */ - attr_if_none_match, /* WINHTTP_QUERY_IF_NONE_MATCH = 57 */ - attr_if_range, /* WINHTTP_QUERY_IF_RANGE = 58 */ - attr_if_unmodified_since, /* WINHTTP_QUERY_IF_UNMODIFIED_SINCE = 59 */ - attr_max_forwards, /* WINHTTP_QUERY_MAX_FORWARDS = 60 */ - attr_proxy_authorization, /* WINHTTP_QUERY_PROXY_AUTHORIZATION = 61 */ - attr_range, /* WINHTTP_QUERY_RANGE = 62 */ - attr_transfer_encoding, /* WINHTTP_QUERY_TRANSFER_ENCODING = 63 */ - attr_upgrade, /* WINHTTP_QUERY_UPGRADE = 64 */ - attr_vary, /* WINHTTP_QUERY_VARY = 65 */ - attr_via, /* WINHTTP_QUERY_VIA = 66 */ - attr_warning, /* WINHTTP_QUERY_WARNING = 67 */ - attr_expect, /* WINHTTP_QUERY_EXPECT = 68 */ - attr_proxy_connection, /* WINHTTP_QUERY_PROXY_CONNECTION = 69 */ - attr_unless_modified_since, /* WINHTTP_QUERY_UNLESS_MODIFIED_SINCE = 70 */ + L"Age", /* WINHTTP_QUERY_AGE = 48 */ + L"Cache-Control", /* WINHTTP_QUERY_CACHE_CONTROL = 49 */ + L"Content-Base", /* WINHTTP_QUERY_CONTENT_BASE = 50 */ + L"Content-Location", /* WINHTTP_QUERY_CONTENT_LOCATION = 51 */ + L"Content-MD5", /* WINHTTP_QUERY_CONTENT_MD5 = 52 */ + L"Content-Range", /* WINHTTP_QUERY_CONTENT_RANGE = 53 */ + L"ETag", /* WINHTTP_QUERY_ETAG = 54 */ + L"Host", /* WINHTTP_QUERY_HOST = 55 */ + L"If-Match", /* WINHTTP_QUERY_IF_MATCH = 56 */ + L"If-None-Match", /* WINHTTP_QUERY_IF_NONE_MATCH = 57 */ + L"If-Range", /* WINHTTP_QUERY_IF_RANGE = 58 */ + L"If-Unmodified-Since", /* WINHTTP_QUERY_IF_UNMODIFIED_SINCE = 59 */ + L"Max-Forwards", /* WINHTTP_QUERY_MAX_FORWARDS = 60 */ + L"Proxy-Authorization", /* WINHTTP_QUERY_PROXY_AUTHORIZATION = 61 */ + L"Range", /* WINHTTP_QUERY_RANGE = 62 */ + L"Transfer-Encoding", /* WINHTTP_QUERY_TRANSFER_ENCODING = 63 */ + L"Upgrade", /* WINHTTP_QUERY_UPGRADE = 64 */ + L"Vary", /* WINHTTP_QUERY_VARY = 65 */ + L"Via", /* WINHTTP_QUERY_VIA = 66 */ + L"Warning", /* WINHTTP_QUERY_WARNING = 67 */ + L"Expect", /* WINHTTP_QUERY_EXPECT = 68 */ + L"Proxy-Connection", /* WINHTTP_QUERY_PROXY_CONNECTION = 69 */ + L"Unless-Modified-Since", /* WINHTTP_QUERY_UNLESS_MODIFIED_SINCE = 70 */ NULL, /* WINHTTP_QUERY_PROXY_SUPPORT = 75 */ NULL, /* WINHTTP_QUERY_AUTHENTICATION_INFO = 76 */ NULL, /* WINHTTP_QUERY_PASSPORT_URLS = 77 */ NULL /* WINHTTP_QUERY_PASSPORT_CONFIG = 78 */ }; -static struct task_header *dequeue_task( struct request *request ) +void init_queue( struct queue *queue ) +{ + InitializeSRWLock( &queue->lock ); + list_init( &queue->queued_tasks ); + queue->callback_running = FALSE; +} + +void stop_queue( struct queue *queue ) +{ + assert( list_empty( &queue->queued_tasks )); + TRACE("stopped %p\n", queue); +} + +static void addref_task( struct task_header *task ) +{ + InterlockedIncrement( &task->refs ); +} + +static void release_task( struct task_header *task ) +{ + if (!InterlockedDecrement( &task->refs )) + free( task ); +} + +static struct task_header *get_next_task( struct queue *queue, struct task_header *prev_task ) { struct task_header *task; + struct list *entry; - EnterCriticalSection( &request->task_cs ); - TRACE("%u tasks queued\n", list_count( &request->task_queue )); - task = LIST_ENTRY( list_head( &request->task_queue ), struct task_header, entry ); - if (task) list_remove( &task->entry ); - LeaveCriticalSection( &request->task_cs ); - - TRACE("returning task %p\n", task); + AcquireSRWLockExclusive( &queue->lock ); + assert( queue->callback_running ); + if (prev_task) + { + list_remove( &prev_task->entry ); + release_task( prev_task ); + } + if ((entry = list_head( &queue->queued_tasks ))) + { + task = LIST_ENTRY( entry, struct task_header, entry ); + addref_task( task ); + } + else + { + task = NULL; + queue->callback_running = FALSE; + } + ReleaseSRWLockExclusive( &queue->lock ); return task; } -#ifdef __REACTOS__ -static DWORD CALLBACK task_proc( LPVOID param ) -#else -static void CALLBACK task_proc( TP_CALLBACK_INSTANCE *instance, void *ctx ) -#endif +static void CALLBACK task_callback( TP_CALLBACK_INSTANCE *instance, void *ctx ) { -#ifdef __REACTOS__ - struct request *request = param; -#else - struct request *request = ctx; -#endif - HANDLE handles[2]; + struct task_header *task, *next_task; + struct queue *queue = ctx; - handles[0] = request->task_wait; - handles[1] = request->task_cancel; - for (;;) + TRACE( "instance %p.\n", instance ); + + task = get_next_task( queue, NULL ); + while (task) { - DWORD err = WaitForMultipleObjects( 2, handles, FALSE, INFINITE ); - switch (err) - { - case WAIT_OBJECT_0: - { - struct task_header *task; - while ((task = dequeue_task( request ))) - { - task->proc( task ); - release_object( &task->request->hdr ); - heap_free( task ); - } - break; - } - case WAIT_OBJECT_0 + 1: - TRACE("exiting\n"); - CloseHandle( request->task_cancel ); - CloseHandle( request->task_wait ); - request->task_cs.DebugInfo->Spare[0] = 0; - DeleteCriticalSection( &request->task_cs ); - request->hdr.vtbl->destroy( &request->hdr ); -#ifdef __REACTOS__ - return 0; -#else - return; -#endif - - default: - ERR("wait failed %u (%u)\n", err, GetLastError()); - break; - } + task->callback( task, FALSE ); + /* Queue object may be freed by release_object() unless there is another task referencing it. */ + next_task = get_next_task( queue, task ); + release_object( task->obj ); + release_task( task ); + task = next_task; } -#ifdef __REACTOS__ - return 0; -#endif + TRACE( "instance %p exiting.\n", instance ); } -static BOOL queue_task( struct task_header *task ) +static DWORD queue_task( struct queue *queue, TASK_CALLBACK task, struct task_header *task_hdr, + struct object_header *obj ) { - struct request *request = task->request; + BOOL callback_running; -#ifdef __REACTOS__ - if (!request->task_thread) -#else - if (!request->task_wait) -#endif + TRACE("queueing %p in %p\n", task_hdr, queue); + task_hdr->callback = task; + task_hdr->completion_sent = 0; + task_hdr->refs = 1; + task_hdr->obj = obj; + addref_object( obj ); + + AcquireSRWLockExclusive( &queue->lock ); + list_add_tail( &queue->queued_tasks, &task_hdr->entry ); + if (!(callback_running = queue->callback_running)) { - if (!(request->task_wait = CreateEventW( NULL, FALSE, FALSE, NULL ))) return FALSE; - if (!(request->task_cancel = CreateEventW( NULL, FALSE, FALSE, NULL ))) - { - CloseHandle( request->task_wait ); - request->task_wait = NULL; - return FALSE; - } -#ifdef __REACTOS__ - if (!(request->task_thread = CreateThread( NULL, 0, task_proc, request, 0, NULL ))) -#else - if (!TrySubmitThreadpoolCallback( task_proc, request, NULL )) -#endif - { - CloseHandle( request->task_wait ); - request->task_wait = NULL; - CloseHandle( request->task_cancel ); - request->task_cancel = NULL; - return FALSE; - } -#ifndef __REACTOS__ - request->task_proc_running = TRUE; -#endif - InitializeCriticalSection( &request->task_cs ); - request->task_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": request.task_cs"); + if ((queue->callback_running = TrySubmitThreadpoolCallback( task_callback, queue, NULL ))) + callback_running = TRUE; + else + list_remove( &task_hdr->entry ); + } + ReleaseSRWLockExclusive( &queue->lock ); + + if (!callback_running) + { + release_object( obj ); + ERR( "Submiting threadpool callback failed, err %lu.\n", GetLastError() ); + return ERROR_OUTOFMEMORY; } - EnterCriticalSection( &request->task_cs ); - TRACE("queueing task %p\n", task ); - list_add_tail( &request->task_queue, &task->entry ); - LeaveCriticalSection( &request->task_cs ); + return ERROR_SUCCESS; +} - SetEvent( request->task_wait ); - return TRUE; +static BOOL task_needs_completion( struct task_header *task_hdr ) +{ + return !InterlockedExchange( &task_hdr->completion_sent, 1 ); +} + +static BOOL cancel_queue( struct queue *queue ) +{ + struct task_header *task_hdr, *found; + BOOL cancelled = FALSE; + + while (1) + { + AcquireSRWLockExclusive( &queue->lock ); + found = NULL; + LIST_FOR_EACH_ENTRY( task_hdr, &queue->queued_tasks, struct task_header, entry ) + { + if (task_needs_completion( task_hdr )) + { + found = task_hdr; + addref_task( found ); + break; + } + } + ReleaseSRWLockExclusive( &queue->lock ); + if (!found) break; + cancelled = TRUE; + found->callback( found, TRUE ); + release_task( found ); + } + return cancelled; +} + +static void task_send_callback( void *ctx, BOOL abort ) +{ + struct send_callback *s = ctx; + + if (abort) return; + + TRACE( "running %p\n", ctx ); + send_callback( s->task_hdr.obj, s->status, s->info, s->buflen ); } static void free_header( struct header *header ) { - heap_free( header->field ); - heap_free( header->value ); - heap_free( header ); + free( header->field ); + free( header->value ); + free( header ); } static BOOL valid_token_char( WCHAR c ) @@ -322,24 +307,33 @@ static BOOL valid_token_char( WCHAR c ) } } -static struct header *parse_header( const WCHAR *string ) +static struct header *parse_header( const WCHAR *string, size_t string_len, BOOL reply ) { - const WCHAR *p, *q; + const WCHAR *p, *q, *name_end; struct header *header; int len; p = string; - if (!(q = strchrW( p, ':' ))) + if (!(q = wcschr( p, ':' ))) { WARN("no ':' in line %s\n", debugstr_w(string)); return NULL; } - if (q == string) + name_end = q; + if (reply) + { + while (name_end != string) + { + if (name_end[-1] != ' ') break; + --name_end; + } + } + if (name_end == string) { WARN("empty field name in line %s\n", debugstr_w(string)); return NULL; } - while (*p != ':') + while (p != name_end) { if (!valid_token_char( *p )) { @@ -348,11 +342,11 @@ static struct header *parse_header( const WCHAR *string ) } p++; } - len = q - string; - if (!(header = heap_alloc_zero( sizeof(struct header) ))) return NULL; - if (!(header->field = heap_alloc( (len + 1) * sizeof(WCHAR) ))) + len = name_end - string; + if (!(header = calloc( 1, sizeof(*header) ))) return NULL; + if (!(header->field = malloc( (len + 1) * sizeof(WCHAR) ))) { - heap_free( header ); + free( header ); return NULL; } memcpy( header->field, string, len * sizeof(WCHAR) ); @@ -360,9 +354,9 @@ static struct header *parse_header( const WCHAR *string ) q++; /* skip past colon */ while (*q == ' ') q++; - len = strlenW( q ); + len = (string + string_len) - q; - if (!(header->value = heap_alloc( (len + 1) * sizeof(WCHAR) ))) + if (!(header->value = malloc( (len + 1) * sizeof(WCHAR) ))) { free_header( header ); return NULL; @@ -381,7 +375,7 @@ static int get_header_index( struct request *request, const WCHAR *field, int re for (index = 0; index < request->num_headers; index++) { - if (strcmpiW( request->headers[index].field, field )) continue; + if (wcsicmp( request->headers[index].field, field )) continue; if (request_only && !request->headers[index].is_request) continue; if (!request_only && request->headers[index].is_request) continue; @@ -393,50 +387,50 @@ static int get_header_index( struct request *request, const WCHAR *field, int re return index; } -static BOOL insert_header( struct request *request, struct header *header ) +static DWORD insert_header( struct request *request, struct header *header ) { DWORD count = request->num_headers + 1; struct header *hdrs; if (request->headers) - hdrs = heap_realloc_zero( request->headers, sizeof(struct header) * count ); - else - hdrs = heap_alloc_zero( sizeof(struct header) ); - if (!hdrs) return FALSE; + { + if ((hdrs = realloc( request->headers, sizeof(*header) * count ))) + memset( &hdrs[count - 1], 0, sizeof(*header) ); + } + else hdrs = calloc( 1, sizeof(*header) ); + if (!hdrs) return ERROR_OUTOFMEMORY; request->headers = hdrs; - request->headers[count - 1].field = strdupW( header->field ); - request->headers[count - 1].value = strdupW( header->value ); + request->headers[count - 1].field = wcsdup( header->field ); + request->headers[count - 1].value = wcsdup( header->value ); request->headers[count - 1].is_request = header->is_request; request->num_headers = count; - return TRUE; + return ERROR_SUCCESS; } -static BOOL delete_header( struct request *request, DWORD index ) +static void delete_header( struct request *request, DWORD index ) { - if (!request->num_headers) return FALSE; - if (index >= request->num_headers) return FALSE; + if (!request->num_headers || index >= request->num_headers) return; request->num_headers--; - heap_free( request->headers[index].field ); - heap_free( request->headers[index].value ); + free( request->headers[index].field ); + free( request->headers[index].value ); memmove( &request->headers[index], &request->headers[index + 1], (request->num_headers - index) * sizeof(struct header) ); memset( &request->headers[request->num_headers], 0, sizeof(struct header) ); - return TRUE; } -BOOL process_header( struct request *request, const WCHAR *field, const WCHAR *value, DWORD flags, BOOL request_only ) +DWORD process_header( struct request *request, const WCHAR *field, const WCHAR *value, DWORD flags, BOOL request_only ) { int index; struct header hdr; - TRACE("%s: %s 0x%08x\n", debugstr_w(field), debugstr_w(value), flags); + TRACE( "%s: %s %#lx\n", debugstr_w(field), debugstr_w(value), flags ); if ((index = get_header_index( request, field, 0, request_only )) >= 0) { - if (flags & WINHTTP_ADDREQ_FLAG_ADD_IF_NEW) return FALSE; + if (flags & WINHTTP_ADDREQ_FLAG_ADD_IF_NEW) return ERROR_WINHTTP_HEADER_ALREADY_EXISTS; } if (flags & WINHTTP_ADDREQ_FLAG_REPLACE) @@ -444,13 +438,9 @@ BOOL process_header( struct request *request, const WCHAR *field, const WCHAR *v if (index >= 0) { delete_header( request, index ); - if (!value || !value[0]) return TRUE; - } - else if (!(flags & WINHTTP_ADDREQ_FLAG_ADD)) - { - SetLastError( ERROR_WINHTTP_HEADER_NOT_FOUND ); - return FALSE; + if (!value || !value[0]) return ERROR_SUCCESS; } + else if (!(flags & WINHTTP_ADDREQ_FLAG_ADD)) return ERROR_WINHTTP_HEADER_NOT_FOUND; hdr.field = (LPWSTR)field; hdr.value = (LPWSTR)value; @@ -467,18 +457,18 @@ BOOL process_header( struct request *request, const WCHAR *field, const WCHAR *v int len, len_orig, len_value; struct header *header = &request->headers[index]; - len_orig = strlenW( header->value ); - len_value = strlenW( value ); + len_orig = lstrlenW( header->value ); + len_value = lstrlenW( value ); len = len_orig + len_value + 2; - if (!(tmp = heap_realloc( header->value, (len + 1) * sizeof(WCHAR) ))) return FALSE; + if (!(tmp = realloc( header->value, (len + 1) * sizeof(WCHAR) ))) return ERROR_OUTOFMEMORY; header->value = tmp; header->value[len_orig++] = (flags & WINHTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA) ? ',' : ';'; header->value[len_orig++] = ' '; memcpy( &header->value[len_orig], value, len_value * sizeof(WCHAR) ); header->value[len] = 0; - return TRUE; + return ERROR_SUCCESS; } else { @@ -489,62 +479,51 @@ BOOL process_header( struct request *request, const WCHAR *field, const WCHAR *v } } - return TRUE; + return ERROR_SUCCESS; } -BOOL add_request_headers( struct request *request, const WCHAR *headers, DWORD len, DWORD flags ) +DWORD add_request_headers( struct request *request, const WCHAR *headers, DWORD len, DWORD flags ) { - BOOL ret = FALSE; - WCHAR *buffer, *p, *q; + DWORD ret = ERROR_WINHTTP_INVALID_HEADER; struct header *header; + const WCHAR *p, *q; - if (len == ~0u) len = strlenW( headers ); - if (!len) return TRUE; - if (!(buffer = heap_alloc( (len + 1) * sizeof(WCHAR) ))) return FALSE; - memcpy( buffer, headers, len * sizeof(WCHAR) ); - buffer[len] = 0; + if (len == ~0u) len = lstrlenW( headers ); + if (!len) return ERROR_SUCCESS; - p = buffer; + p = headers; do { - q = p; - while (*q) - { - if (q[0] == '\n' && q[1] == '\r') - { - q[0] = '\r'; - q[1] = '\n'; - } - if (q[0] == '\r' && q[1] == '\n') break; - q++; - } - if (!*p) break; - if (*q == '\r') - { - *q = 0; - q += 2; /* jump over \r\n */ - } - if ((header = parse_header( p ))) + const WCHAR *end; + + if (p >= headers + len) break; + + for (q = p; q < headers + len && *q != '\r' && *q != '\n'; ++q) + ; + end = q; + while (*q == '\r' || *q == '\n') + ++q; + + if ((header = parse_header( p, end - p, FALSE ))) { ret = process_header( request, header->field, header->value, flags, TRUE ); free_header( header ); } p = q; - } while (ret); + } while (!ret); - heap_free( buffer ); return ret; } /*********************************************************************** * WinHttpAddRequestHeaders (winhttp.@) */ -BOOL WINAPI WinHttpAddRequestHeaders( HINTERNET hrequest, LPCWSTR headers, DWORD len, DWORD flags ) +BOOL WINAPI WinHttpAddRequestHeaders( HINTERNET hrequest, const WCHAR *headers, DWORD len, DWORD flags ) { - BOOL ret; + DWORD ret; struct request *request; - TRACE("%p, %s, %u, 0x%08x\n", hrequest, debugstr_wn(headers, len), len, flags); + TRACE( "%p, %s, %lu, %#lx\n", hrequest, debugstr_wn(headers, len), len, flags ); if (!headers || !len) { @@ -566,35 +545,31 @@ BOOL WINAPI WinHttpAddRequestHeaders( HINTERNET hrequest, LPCWSTR headers, DWORD ret = add_request_headers( request, headers, len, flags ); release_object( &request->hdr ); - if (ret) SetLastError( ERROR_SUCCESS ); - return ret; + SetLastError( ret ); + return !ret; } static WCHAR *build_absolute_request_path( struct request *request, const WCHAR **path ) { - static const WCHAR http[] = {'h','t','t','p',0}; - static const WCHAR https[] = {'h','t','t','p','s',0}; - static const WCHAR fmt[] = {'%','s',':','/','/','%','s',0}; const WCHAR *scheme; WCHAR *ret; - int len; + int len, offset; - scheme = (request->netconn ? request->netconn->secure : (request->hdr.flags & WINHTTP_FLAG_SECURE)) ? https : http; + scheme = (request->netconn ? request->netconn->secure : (request->hdr.flags & WINHTTP_FLAG_SECURE)) ? L"https" : L"http"; - len = strlenW( scheme ) + strlenW( request->connect->hostname ) + 4; /* '://' + nul */ + len = lstrlenW( scheme ) + lstrlenW( request->connect->hostname ) + 4; /* '://' + nul */ if (request->connect->hostport) len += 6; /* ':' between host and port, up to 5 for port */ - len += strlenW( request->path ); - if ((ret = heap_alloc( len * sizeof(WCHAR) ))) + len += lstrlenW( request->path ); + if ((ret = malloc( len * sizeof(WCHAR) ))) { - len = sprintfW( ret, fmt, scheme, request->connect->hostname ); + offset = swprintf( ret, len, L"%s://%s", scheme, request->connect->hostname ); if (request->connect->hostport) { - static const WCHAR port_fmt[] = {':','%','u',0}; - len += sprintfW( ret + len, port_fmt, request->connect->hostport ); + offset += swprintf( ret + offset, len - offset, L":%u", request->connect->hostport ); } - strcpyW( ret + len, request->path ); - if (path) *path = ret + len; + lstrcpyW( ret + offset, request->path ); + if (path) *path = ret + offset; } return ret; @@ -602,59 +577,57 @@ static WCHAR *build_absolute_request_path( struct request *request, const WCHAR static WCHAR *build_request_string( struct request *request ) { - static const WCHAR spaceW[] = {' ',0}, crlfW[] = {'\r','\n',0}, colonW[] = {':',' ',0}; - static const WCHAR twocrlfW[] = {'\r','\n','\r','\n',0}; WCHAR *path, *ret; unsigned int i, len; - if (!strcmpiW( request->connect->hostname, request->connect->servername )) path = request->path; + if (!wcsicmp( request->connect->hostname, request->connect->servername )) path = request->path; else if (!(path = build_absolute_request_path( request, NULL ))) return NULL; - len = strlenW( request->verb ) + 1 /* ' ' */; - len += strlenW( path ) + 1 /* ' ' */; - len += strlenW( request->version ); + len = lstrlenW( request->verb ) + 1 /* ' ' */; + len += lstrlenW( path ) + 1 /* ' ' */; + len += lstrlenW( request->version ); for (i = 0; i < request->num_headers; i++) { if (request->headers[i].is_request) - len += strlenW( request->headers[i].field ) + strlenW( request->headers[i].value ) + 4; /* '\r\n: ' */ + len += lstrlenW( request->headers[i].field ) + lstrlenW( request->headers[i].value ) + 4; /* '\r\n: ' */ } len += 4; /* '\r\n\r\n' */ - if ((ret = heap_alloc( (len + 1) * sizeof(WCHAR) ))) + if ((ret = malloc( (len + 1) * sizeof(WCHAR) ))) { - strcpyW( ret, request->verb ); - strcatW( ret, spaceW ); - strcatW( ret, path ); - strcatW( ret, spaceW ); - strcatW( ret, request->version ); + lstrcpyW( ret, request->verb ); + lstrcatW( ret, L" " ); + lstrcatW( ret, path ); + lstrcatW( ret, L" " ); + lstrcatW( ret, request->version ); for (i = 0; i < request->num_headers; i++) { if (request->headers[i].is_request) { - strcatW( ret, crlfW ); - strcatW( ret, request->headers[i].field ); - strcatW( ret, colonW ); - strcatW( ret, request->headers[i].value ); + lstrcatW( ret, L"\r\n" ); + lstrcatW( ret, request->headers[i].field ); + lstrcatW( ret, L": " ); + lstrcatW( ret, request->headers[i].value ); } } - strcatW( ret, twocrlfW ); + lstrcatW( ret, L"\r\n\r\n" ); } - if (path != request->path) heap_free( path ); + if (path != request->path) free( path ); return ret; } #define QUERY_MODIFIER_MASK (WINHTTP_QUERY_FLAG_REQUEST_HEADERS | WINHTTP_QUERY_FLAG_SYSTEMTIME | WINHTTP_QUERY_FLAG_NUMBER) -static BOOL query_headers( struct request *request, DWORD level, const WCHAR *name, void *buffer, DWORD *buflen, - DWORD *index ) +static DWORD query_headers( struct request *request, DWORD level, const WCHAR *name, void *buffer, DWORD *buflen, + DWORD *index ) { struct header *header = NULL; - BOOL request_only, ret = FALSE; + BOOL request_only; int requested_index, header_index = -1; - DWORD attr, len; + DWORD attr, len, ret = ERROR_WINHTTP_HEADER_NOT_FOUND; request_only = level & WINHTTP_QUERY_FLAG_REQUEST_HEADERS; requested_index = index ? *index : 0; @@ -676,11 +649,10 @@ static BOOL query_headers( struct request *request, DWORD level, const WCHAR *na else headers = request->raw_headers; - if (!(p = headers)) return FALSE; + if (!(p = headers)) return ERROR_OUTOFMEMORY; for (len = 0; *p; p++) if (*p != '\r') len++; - if (!buffer || len * sizeof(WCHAR) > *buflen) - SetLastError( ERROR_INSUFFICIENT_BUFFER ); + if (!buffer || len * sizeof(WCHAR) > *buflen) ret = ERROR_INSUFFICIENT_BUFFER; else { for (p = headers, q = buffer; *p; p++, q++) @@ -694,10 +666,10 @@ static BOOL query_headers( struct request *request, DWORD level, const WCHAR *na } TRACE("returning data: %s\n", debugstr_wn(buffer, len)); if (len) len--; - ret = TRUE; + ret = ERROR_SUCCESS; } *buflen = len * sizeof(WCHAR); - if (request_only) heap_free( headers ); + if (request_only) free( headers ); return ret; } case WINHTTP_QUERY_RAW_HEADERS_CRLF: @@ -709,82 +681,77 @@ static BOOL query_headers( struct request *request, DWORD level, const WCHAR *na else headers = request->raw_headers; - if (!headers) return FALSE; - len = strlenW( headers ) * sizeof(WCHAR); + if (!headers) return ERROR_OUTOFMEMORY; + len = lstrlenW( headers ) * sizeof(WCHAR); if (!buffer || len + sizeof(WCHAR) > *buflen) { len += sizeof(WCHAR); - SetLastError( ERROR_INSUFFICIENT_BUFFER ); + ret = ERROR_INSUFFICIENT_BUFFER; } else { memcpy( buffer, headers, len + sizeof(WCHAR) ); TRACE("returning data: %s\n", debugstr_wn(buffer, len / sizeof(WCHAR))); - ret = TRUE; + ret = ERROR_SUCCESS; } *buflen = len; - if (request_only) heap_free( headers ); + if (request_only) free( headers ); return ret; } case WINHTTP_QUERY_VERSION: - len = strlenW( request->version ) * sizeof(WCHAR); + len = lstrlenW( request->version ) * sizeof(WCHAR); if (!buffer || len + sizeof(WCHAR) > *buflen) { len += sizeof(WCHAR); - SetLastError( ERROR_INSUFFICIENT_BUFFER ); + ret = ERROR_INSUFFICIENT_BUFFER; } else { - strcpyW( buffer, request->version ); + lstrcpyW( buffer, request->version ); TRACE("returning string: %s\n", debugstr_w(buffer)); - ret = TRUE; + ret = ERROR_SUCCESS; } *buflen = len; return ret; case WINHTTP_QUERY_STATUS_TEXT: - len = strlenW( request->status_text ) * sizeof(WCHAR); + len = lstrlenW( request->status_text ) * sizeof(WCHAR); if (!buffer || len + sizeof(WCHAR) > *buflen) { len += sizeof(WCHAR); - SetLastError( ERROR_INSUFFICIENT_BUFFER ); + ret = ERROR_INSUFFICIENT_BUFFER; } else { - strcpyW( buffer, request->status_text ); + lstrcpyW( buffer, request->status_text ); TRACE("returning string: %s\n", debugstr_w(buffer)); - ret = TRUE; + ret = ERROR_SUCCESS; } *buflen = len; return ret; case WINHTTP_QUERY_REQUEST_METHOD: - len = strlenW( request->verb ) * sizeof(WCHAR); + len = lstrlenW( request->verb ) * sizeof(WCHAR); if (!buffer || len + sizeof(WCHAR) > *buflen) { len += sizeof(WCHAR); - SetLastError( ERROR_INSUFFICIENT_BUFFER ); + ret = ERROR_INSUFFICIENT_BUFFER; } else { - strcpyW( buffer, request->verb ); + lstrcpyW( buffer, request->verb ); TRACE("returning string: %s\n", debugstr_w(buffer)); - ret = TRUE; + ret = ERROR_SUCCESS; } *buflen = len; return ret; default: - if (attr >= ARRAY_SIZE(attribute_table)) - { - SetLastError( ERROR_INVALID_PARAMETER ); - return FALSE; - } + if (attr >= ARRAY_SIZE(attribute_table)) return ERROR_INVALID_PARAMETER; if (!attribute_table[attr]) { - FIXME("attribute %u not implemented\n", attr); - SetLastError( ERROR_WINHTTP_HEADER_NOT_FOUND ); - return FALSE; + FIXME( "attribute %lu not implemented\n", attr ); + return ERROR_WINHTTP_HEADER_NOT_FOUND; } TRACE("attribute %s\n", debugstr_w(attribute_table[attr])); header_index = get_header_index( request, attribute_table[attr], requested_index, request_only ); @@ -795,70 +762,62 @@ static BOOL query_headers( struct request *request, DWORD level, const WCHAR *na { header = &request->headers[header_index]; } - if (!header || (request_only && !header->is_request)) - { - SetLastError( ERROR_WINHTTP_HEADER_NOT_FOUND ); - return FALSE; - } + if (!header || (request_only && !header->is_request)) return ERROR_WINHTTP_HEADER_NOT_FOUND; if (level & WINHTTP_QUERY_FLAG_NUMBER) { - if (!buffer || sizeof(int) > *buflen) - { - SetLastError( ERROR_INSUFFICIENT_BUFFER ); - } + if (!buffer || sizeof(DWORD) > *buflen) ret = ERROR_INSUFFICIENT_BUFFER; else { - int *number = buffer; - *number = atoiW( header->value ); - TRACE("returning number: %d\n", *number); - ret = TRUE; + DWORD *number = buffer; + *number = wcstoul( header->value, NULL, 10 ); + TRACE("returning number: %lu\n", *number); + ret = ERROR_SUCCESS; } - *buflen = sizeof(int); + *buflen = sizeof(DWORD); } else if (level & WINHTTP_QUERY_FLAG_SYSTEMTIME) { SYSTEMTIME *st = buffer; - if (!buffer || sizeof(SYSTEMTIME) > *buflen) - { - SetLastError( ERROR_INSUFFICIENT_BUFFER ); - } - else if ((ret = WinHttpTimeToSystemTime( header->value, st ))) + if (!buffer || sizeof(SYSTEMTIME) > *buflen) ret = ERROR_INSUFFICIENT_BUFFER; + else if (WinHttpTimeToSystemTime( header->value, st )) { TRACE("returning time: %04d/%02d/%02d - %d - %02d:%02d:%02d.%02d\n", st->wYear, st->wMonth, st->wDay, st->wDayOfWeek, st->wHour, st->wMinute, st->wSecond, st->wMilliseconds); + ret = ERROR_SUCCESS; } *buflen = sizeof(SYSTEMTIME); } else if (header->value) { - len = strlenW( header->value ) * sizeof(WCHAR); + len = lstrlenW( header->value ) * sizeof(WCHAR); if (!buffer || len + sizeof(WCHAR) > *buflen) { len += sizeof(WCHAR); - SetLastError( ERROR_INSUFFICIENT_BUFFER ); + ret = ERROR_INSUFFICIENT_BUFFER; } else { - strcpyW( buffer, header->value ); + lstrcpyW( buffer, header->value ); TRACE("returning string: %s\n", debugstr_w(buffer)); - ret = TRUE; + ret = ERROR_SUCCESS; } *buflen = len; } - if (ret && index) *index += 1; + if (!ret && index) *index += 1; return ret; } /*********************************************************************** * WinHttpQueryHeaders (winhttp.@) */ -BOOL WINAPI WinHttpQueryHeaders( HINTERNET hrequest, DWORD level, LPCWSTR name, LPVOID buffer, LPDWORD buflen, LPDWORD index ) +BOOL WINAPI WinHttpQueryHeaders( HINTERNET hrequest, DWORD level, const WCHAR *name, void *buffer, DWORD *buflen, + DWORD *index ) { - BOOL ret; + DWORD ret; struct request *request; - TRACE("%p, 0x%08x, %s, %p, %p, %p\n", hrequest, level, debugstr_w(name), buffer, buflen, index); + TRACE( "%p, %#lx, %s, %p, %p, %p\n", hrequest, level, debugstr_w(name), buffer, buflen, index ); if (!(request = (struct request *)grab_object( hrequest ))) { @@ -871,20 +830,21 @@ BOOL WINAPI WinHttpQueryHeaders( HINTERNET hrequest, DWORD level, LPCWSTR name, SetLastError( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE ); return FALSE; } + if (request->state < REQUEST_RESPONSE_STATE_RESPONSE_RECEIVED && !(level & WINHTTP_QUERY_FLAG_REQUEST_HEADERS) + && ((level & ~QUERY_MODIFIER_MASK) != WINHTTP_QUERY_REQUEST_METHOD)) + { + release_object( &request->hdr ); + SetLastError( ERROR_WINHTTP_INCORRECT_HANDLE_STATE ); + return FALSE; + } ret = query_headers( request, level, name, buffer, buflen, index ); release_object( &request->hdr ); - if (ret) SetLastError( ERROR_SUCCESS ); - return ret; + SetLastError( ret ); + return !ret; } -static const WCHAR basicW[] = {'B','a','s','i','c',0}; -static const WCHAR ntlmW[] = {'N','T','L','M',0}; -static const WCHAR passportW[] = {'P','a','s','s','p','o','r','t',0}; -static const WCHAR digestW[] = {'D','i','g','e','s','t',0}; -static const WCHAR negotiateW[] = {'N','e','g','o','t','i','a','t','e',0}; - static const struct { const WCHAR *str; @@ -893,11 +853,11 @@ static const struct } auth_schemes[] = { - { basicW, ARRAY_SIZE(basicW) - 1, WINHTTP_AUTH_SCHEME_BASIC }, - { ntlmW, ARRAY_SIZE(ntlmW) - 1, WINHTTP_AUTH_SCHEME_NTLM }, - { passportW, ARRAY_SIZE(passportW) - 1, WINHTTP_AUTH_SCHEME_PASSPORT }, - { digestW, ARRAY_SIZE(digestW) - 1, WINHTTP_AUTH_SCHEME_DIGEST }, - { negotiateW, ARRAY_SIZE(negotiateW) - 1, WINHTTP_AUTH_SCHEME_NEGOTIATE } + { L"Basic", ARRAY_SIZE(L"Basic") - 1, WINHTTP_AUTH_SCHEME_BASIC }, + { L"NTLM", ARRAY_SIZE(L"NTLM") - 1, WINHTTP_AUTH_SCHEME_NTLM }, + { L"Passport", ARRAY_SIZE(L"Passport") - 1, WINHTTP_AUTH_SCHEME_PASSPORT }, + { L"Digest", ARRAY_SIZE(L"Digest") - 1, WINHTTP_AUTH_SCHEME_DIGEST }, + { L"Negotiate", ARRAY_SIZE(L"Negotiate") - 1, WINHTTP_AUTH_SCHEME_NEGOTIATE } }; static enum auth_scheme scheme_from_flag( DWORD flag ) @@ -914,16 +874,15 @@ static DWORD auth_scheme_from_header( const WCHAR *header ) for (i = 0; i < ARRAY_SIZE( auth_schemes ); i++) { - if (!strncmpiW( header, auth_schemes[i].str, auth_schemes[i].len ) && + if (!wcsnicmp( header, auth_schemes[i].str, auth_schemes[i].len ) && (header[auth_schemes[i].len] == ' ' || !header[auth_schemes[i].len])) return auth_schemes[i].scheme; } return 0; } -static BOOL query_auth_schemes( struct request *request, DWORD level, DWORD *supported, DWORD *first ) +static DWORD query_auth_schemes( struct request *request, DWORD level, DWORD *supported, DWORD *first ) { - DWORD index = 0, supported_schemes = 0, first_scheme = 0; - BOOL ret = FALSE; + DWORD ret, index = 0, supported_schemes = 0, first_scheme = 0; for (;;) { @@ -931,26 +890,28 @@ static BOOL query_auth_schemes( struct request *request, DWORD level, DWORD *sup DWORD size, scheme; size = 0; - query_headers( request, level, NULL, NULL, &size, &index ); - if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) break; - - if (!(buffer = heap_alloc( size ))) return FALSE; - if (!query_headers( request, level, NULL, buffer, &size, &index )) + ret = query_headers( request, level, NULL, NULL, &size, &index ); + if (ret != ERROR_INSUFFICIENT_BUFFER) { - heap_free( buffer ); - return FALSE; + if (index) ret = ERROR_SUCCESS; + break; + } + + if (!(buffer = malloc( size ))) return ERROR_OUTOFMEMORY; + if ((ret = query_headers( request, level, NULL, buffer, &size, &index ))) + { + free( buffer ); + return ret; } scheme = auth_scheme_from_header( buffer ); - heap_free( buffer ); + free( buffer ); if (!scheme) continue; if (!first_scheme) first_scheme = scheme; supported_schemes |= scheme; - - ret = TRUE; } - if (ret) + if (!ret) { *supported = supported_schemes; *first = first_scheme; @@ -963,7 +924,7 @@ static BOOL query_auth_schemes( struct request *request, DWORD level, DWORD *sup */ BOOL WINAPI WinHttpQueryAuthSchemes( HINTERNET hrequest, LPDWORD supported, LPDWORD first, LPDWORD target ) { - BOOL ret = FALSE; + DWORD ret; struct request *request; TRACE("%p, %p, %p, %p\n", hrequest, supported, first, target); @@ -987,21 +948,19 @@ BOOL WINAPI WinHttpQueryAuthSchemes( HINTERNET hrequest, LPDWORD supported, LPDW } - if (query_auth_schemes( request, WINHTTP_QUERY_WWW_AUTHENTICATE, supported, first )) + if (!(ret = query_auth_schemes( request, WINHTTP_QUERY_WWW_AUTHENTICATE, supported, first ))) { *target = WINHTTP_AUTH_TARGET_SERVER; - ret = TRUE; } - else if (query_auth_schemes( request, WINHTTP_QUERY_PROXY_AUTHENTICATE, supported, first )) + else if (!(ret = query_auth_schemes( request, WINHTTP_QUERY_PROXY_AUTHENTICATE, supported, first ))) { *target = WINHTTP_AUTH_TARGET_PROXY; - ret = TRUE; } - else SetLastError( ERROR_INVALID_OPERATION ); + else ret = ERROR_INVALID_OPERATION; release_object( &request->hdr ); - if (ret) SetLastError( ERROR_SUCCESS ); - return ret; + SetLastError( ret ); + return !ret; } static UINT encode_base64( const char *bin, unsigned int len, WCHAR *base64 ) @@ -1121,7 +1080,7 @@ static struct authinfo *alloc_authinfo(void) { struct authinfo *ret; - if (!(ret = heap_alloc( sizeof(*ret) ))) return NULL; + if (!(ret = malloc( sizeof(*ret) ))) return NULL; SecInvalidateHandle( &ret->cred ); SecInvalidateHandle( &ret->ctx ); @@ -1144,8 +1103,8 @@ void destroy_authinfo( struct authinfo *authinfo ) if (SecIsValidHandle( &authinfo->cred )) FreeCredentialsHandle( &authinfo->cred ); - heap_free( authinfo->data ); - heap_free( authinfo ); + free( authinfo->data ); + free( authinfo ); } static BOOL get_authvalue( struct request *request, DWORD level, DWORD scheme, WCHAR *buffer, DWORD len ) @@ -1154,7 +1113,7 @@ static BOOL get_authvalue( struct request *request, DWORD level, DWORD scheme, W for (;;) { size = len; - if (!query_headers( request, level, NULL, buffer, &size, &index )) return FALSE; + if (query_headers( request, level, NULL, buffer, &size, &index )) return FALSE; if (auth_scheme_from_header( buffer ) == scheme) break; } return TRUE; @@ -1176,7 +1135,7 @@ static BOOL do_authorization( struct request *request, DWORD target, DWORD schem case WINHTTP_AUTH_TARGET_SERVER: has_auth_value = get_authvalue( request, WINHTTP_QUERY_WWW_AUTHENTICATE, scheme_flag, auth_value, len ); auth_ptr = &request->authinfo; - auth_target = attr_authorization; + auth_target = L"Authorization"; if (request->creds[TARGET_SERVER][scheme].username) { if (scheme != SCHEME_BASIC && !has_auth_value) return FALSE; @@ -1195,7 +1154,7 @@ static BOOL do_authorization( struct request *request, DWORD target, DWORD schem if (!get_authvalue( request, WINHTTP_QUERY_PROXY_AUTHENTICATE, scheme_flag, auth_value, len )) return FALSE; auth_ptr = &request->proxy_authinfo; - auth_target = attr_proxy_authorization; + auth_target = L"Proxy-Authorization"; if (request->creds[TARGET_PROXY][scheme].username) { username = request->creds[TARGET_PROXY][scheme].username; @@ -1209,7 +1168,7 @@ static BOOL do_authorization( struct request *request, DWORD target, DWORD schem break; default: - WARN("unknown target %x\n", target); + WARN( "unknown target %#lx\n", target ); return FALSE; } authinfo = *auth_ptr; @@ -1223,11 +1182,11 @@ static BOOL do_authorization( struct request *request, DWORD target, DWORD schem if (!username || !password) return FALSE; if ((!authinfo && !(authinfo = alloc_authinfo())) || authinfo->finished) return FALSE; - userlen = WideCharToMultiByte( CP_UTF8, 0, username, strlenW( username ), NULL, 0, NULL, NULL ); - passlen = WideCharToMultiByte( CP_UTF8, 0, password, strlenW( password ), NULL, 0, NULL, NULL ); + userlen = WideCharToMultiByte( CP_UTF8, 0, username, lstrlenW( username ), NULL, 0, NULL, NULL ); + passlen = WideCharToMultiByte( CP_UTF8, 0, password, lstrlenW( password ), NULL, 0, NULL, NULL ); authinfo->data_len = userlen + 1 + passlen; - if (!(authinfo->data = heap_alloc( authinfo->data_len ))) return FALSE; + if (!(authinfo->data = malloc( authinfo->data_len ))) return FALSE; WideCharToMultiByte( CP_UTF8, 0, username, -1, authinfo->data, userlen, NULL, NULL ); authinfo->data[userlen] = ':'; @@ -1257,7 +1216,7 @@ static BOOL do_authorization( struct request *request, DWORD target, DWORD schem first = TRUE; domain = (WCHAR *)username; - user = strchrW( username, '\\' ); + user = wcschr( username, '\\' ); if (user) user++; else @@ -1267,11 +1226,11 @@ static BOOL do_authorization( struct request *request, DWORD target, DWORD schem } id.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; id.User = user; - id.UserLength = strlenW( user ); + id.UserLength = lstrlenW( user ); id.Domain = domain; id.DomainLength = domain ? user - domain - 1 : 0; id.Password = (WCHAR *)password; - id.PasswordLength = strlenW( password ); + id.PasswordLength = lstrlenW( password ); status = AcquireCredentialsHandleW( NULL, (SEC_WCHAR *)auth_schemes[scheme].str, SECPKG_CRED_OUTBOUND, NULL, &id, NULL, NULL, @@ -1288,17 +1247,17 @@ static BOOL do_authorization( struct request *request, DWORD target, DWORD schem } if (status != SEC_E_OK) { - WARN("AcquireCredentialsHandleW for scheme %s failed with error 0x%08x\n", - debugstr_w(auth_schemes[scheme].str), status); - heap_free( authinfo ); + WARN( "AcquireCredentialsHandleW for scheme %s failed with error %#lx\n", + debugstr_w(auth_schemes[scheme].str), status ); + free( authinfo ); return FALSE; } authinfo->scheme = scheme; } else if (authinfo->finished) return FALSE; - if ((strlenW( auth_value ) < auth_schemes[authinfo->scheme].len || - strncmpiW( auth_value, auth_schemes[authinfo->scheme].str, auth_schemes[authinfo->scheme].len ))) + if ((lstrlenW( auth_value ) < auth_schemes[authinfo->scheme].len || + wcsnicmp( auth_value, auth_schemes[authinfo->scheme].str, auth_schemes[authinfo->scheme].len ))) { ERR("authentication scheme changed from %s to %s\n", debugstr_w(auth_schemes[authinfo->scheme].str), debugstr_w(auth_value)); @@ -1317,9 +1276,9 @@ static BOOL do_authorization( struct request *request, DWORD target, DWORD schem p = auth_value + auth_schemes[scheme].len; if (*p == ' ') { - int len = strlenW( ++p ); + int len = lstrlenW( ++p ); in.cbBuffer = decode_base64( p, len, NULL ); - if (!(in.pvBuffer = heap_alloc( in.cbBuffer ))) { + if (!(in.pvBuffer = malloc( in.cbBuffer ))) { destroy_authinfo( authinfo ); *auth_ptr = NULL; return FALSE; @@ -1328,9 +1287,9 @@ static BOOL do_authorization( struct request *request, DWORD target, DWORD schem } out.BufferType = SECBUFFER_TOKEN; out.cbBuffer = authinfo->max_token; - if (!(out.pvBuffer = heap_alloc( authinfo->max_token ))) + if (!(out.pvBuffer = malloc( authinfo->max_token ))) { - heap_free( in.pvBuffer ); + free( in.pvBuffer ); destroy_authinfo( authinfo ); *auth_ptr = NULL; return FALSE; @@ -1343,10 +1302,10 @@ static BOOL do_authorization( struct request *request, DWORD target, DWORD schem first ? request->connect->servername : NULL, flags, 0, SECURITY_NETWORK_DREP, in.pvBuffer ? &in_desc : NULL, 0, &authinfo->ctx, &out_desc, &authinfo->attr, &authinfo->exp ); - heap_free( in.pvBuffer ); + free( in.pvBuffer ); if (status == SEC_E_OK) { - heap_free( authinfo->data ); + free( authinfo->data ); authinfo->data = out.pvBuffer; authinfo->data_len = out.cbBuffer; authinfo->finished = TRUE; @@ -1354,15 +1313,15 @@ static BOOL do_authorization( struct request *request, DWORD target, DWORD schem } else if (status == SEC_I_CONTINUE_NEEDED) { - heap_free( authinfo->data ); + free( authinfo->data ); authinfo->data = out.pvBuffer; authinfo->data_len = out.cbBuffer; TRACE("sending next auth packet\n"); } else { - ERR("InitializeSecurityContextW failed with error 0x%08x\n", status); - heap_free( out.pvBuffer ); + ERR( "InitializeSecurityContextW failed with error %#lx\n", status ); + free( out.pvBuffer ); destroy_authinfo( authinfo ); *auth_ptr = NULL; return FALSE; @@ -1377,84 +1336,80 @@ static BOOL do_authorization( struct request *request, DWORD target, DWORD schem len_scheme = auth_schemes[authinfo->scheme].len; len = len_scheme + 1 + ((authinfo->data_len + 2) * 4) / 3; - if (!(auth_reply = heap_alloc( (len + 1) * sizeof(WCHAR) ))) return FALSE; + if (!(auth_reply = malloc( (len + 1) * sizeof(WCHAR) ))) return FALSE; memcpy( auth_reply, auth_schemes[authinfo->scheme].str, len_scheme * sizeof(WCHAR) ); auth_reply[len_scheme] = ' '; encode_base64( authinfo->data, authinfo->data_len, auth_reply + len_scheme + 1 ); flags = WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE; - ret = process_header( request, auth_target, auth_reply, flags, TRUE ); - heap_free( auth_reply ); + ret = !process_header( request, auth_target, auth_reply, flags, TRUE ); + free( auth_reply ); return ret; } static WCHAR *build_proxy_connect_string( struct request *request ) { - static const WCHAR fmtW[] = {'%','s',':','%','u',0}; - static const WCHAR connectW[] = {'C','O','N','N','E','C','T', 0}; - static const WCHAR spaceW[] = {' ',0}, crlfW[] = {'\r','\n',0}, colonW[] = {':',' ',0}; - static const WCHAR twocrlfW[] = {'\r','\n','\r','\n',0}; WCHAR *ret, *host; unsigned int i; - int len; + int len = lstrlenW( request->connect->hostname ) + 7; - if (!(host = heap_alloc( (strlenW( request->connect->hostname ) + 7) * sizeof(WCHAR) ))) return NULL; - len = sprintfW( host, fmtW, request->connect->hostname, request->connect->hostport ); + if (!(host = malloc( len * sizeof(WCHAR) ))) return NULL; + len = swprintf( host, len, L"%s:%u", request->connect->hostname, request->connect->hostport ); - len += ARRAY_SIZE(connectW); - len += ARRAY_SIZE(http1_1); + len += ARRAY_SIZE(L"CONNECT"); + len += ARRAY_SIZE(L"HTTP/1.1"); for (i = 0; i < request->num_headers; i++) { if (request->headers[i].is_request) - len += strlenW( request->headers[i].field ) + strlenW( request->headers[i].value ) + 4; /* '\r\n: ' */ + len += lstrlenW( request->headers[i].field ) + lstrlenW( request->headers[i].value ) + 4; /* '\r\n: ' */ } len += 4; /* '\r\n\r\n' */ - if ((ret = heap_alloc( (len + 1) * sizeof(WCHAR) ))) + if ((ret = malloc( (len + 1) * sizeof(WCHAR) ))) { - strcpyW( ret, connectW ); - strcatW( ret, spaceW ); - strcatW( ret, host ); - strcatW( ret, spaceW ); - strcatW( ret, http1_1 ); + lstrcpyW( ret, L"CONNECT" ); + lstrcatW( ret, L" " ); + lstrcatW( ret, host ); + lstrcatW( ret, L" " ); + lstrcatW( ret, L"HTTP/1.1" ); for (i = 0; i < request->num_headers; i++) { if (request->headers[i].is_request) { - strcatW( ret, crlfW ); - strcatW( ret, request->headers[i].field ); - strcatW( ret, colonW ); - strcatW( ret, request->headers[i].value ); + lstrcatW( ret, L"\r\n" ); + lstrcatW( ret, request->headers[i].field ); + lstrcatW( ret, L": " ); + lstrcatW( ret, request->headers[i].value ); } } - strcatW( ret, twocrlfW ); + lstrcatW( ret, L"\r\n\r\n" ); } - heap_free( host ); + free( host ); return ret; } -static BOOL read_reply( struct request *request ); +static DWORD read_reply( struct request *request ); -static BOOL secure_proxy_connect( struct request *request ) +static DWORD secure_proxy_connect( struct request *request ) { WCHAR *str; char *strA; int len, bytes_sent; - BOOL ret; + DWORD ret; - if (!(str = build_proxy_connect_string( request ))) return FALSE; + if (!(str = build_proxy_connect_string( request ))) return ERROR_OUTOFMEMORY; strA = strdupWA( str ); - heap_free( str ); - if (!strA) return FALSE; + free( str ); + if (!strA) return ERROR_OUTOFMEMORY; len = strlen( strA ); - ret = netconn_send( request->netconn, strA, len, &bytes_sent ); - heap_free( strA ); - if (ret) ret = read_reply( request ); + ret = netconn_send( request->netconn, strA, len, &bytes_sent, NULL ); + free( strA ); + if (!ret) ret = read_reply( request ); return ret; } @@ -1501,17 +1456,13 @@ void release_host( struct hostdata *host ) if (ref) return; assert( list_empty( &host->connections ) ); - heap_free( host->hostname ); - heap_free( host ); + free( host->hostname ); + free( host ); } static BOOL connection_collector_running; -#ifdef __REACTOS__ -static DWORD WINAPI connection_collector(void *arg) -#else static void CALLBACK connection_collector( TP_CALLBACK_INSTANCE *instance, void *ctx ) -#endif { unsigned int remaining_connections; struct netconn *netconn, *next_netconn; @@ -1535,7 +1486,7 @@ static void CALLBACK connection_collector( TP_CALLBACK_INSTANCE *instance, void { TRACE("freeing %p\n", netconn); list_remove(&netconn->entry); - netconn_close(netconn); + netconn_release(netconn); } else remaining_connections++; } @@ -1546,11 +1497,7 @@ static void CALLBACK connection_collector( TP_CALLBACK_INSTANCE *instance, void LeaveCriticalSection(&connection_pool_cs); } while(remaining_connections); -#ifdef __REACTOS__ - FreeLibraryAndExitThread( winhttp_instance, 0 ); -#else FreeLibraryWhenCallbackReturns( instance, winhttp_instance ); -#endif } static void cache_connection( struct netconn *netconn ) @@ -1565,27 +1512,11 @@ static void cache_connection( struct netconn *netconn ) if (!connection_collector_running) { HMODULE module; -#ifdef __REACTOS__ - HANDLE thread; -#endif GetModuleHandleExW( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const WCHAR *)winhttp_instance, &module ); -#ifdef __REACTOS__ - thread = CreateThread(NULL, 0, connection_collector, NULL, 0, NULL); - if (thread) - { - CloseHandle( thread ); - connection_collector_running = TRUE; - } - else - { - FreeLibrary( winhttp_instance ); - } -#else if (TrySubmitThreadpoolCallback( connection_collector, NULL, NULL )) connection_collector_running = TRUE; else FreeLibrary( winhttp_instance ); -#endif } LeaveCriticalSection( &connection_pool_cs ); @@ -1602,11 +1533,11 @@ static DWORD map_secure_protocols( DWORD mask ) return ret; } -static BOOL ensure_cred_handle( struct request *request ) +static DWORD ensure_cred_handle( struct request *request ) { SECURITY_STATUS status = SEC_E_OK; - if (request->cred_handle_initialized) return TRUE; + if (request->cred_handle_initialized) return ERROR_SUCCESS; if (!request->cred_handle_initialized) { @@ -1627,13 +1558,13 @@ static BOOL ensure_cred_handle( struct request *request ) if (status != SEC_E_OK) { - WARN( "AcquireCredentialsHandleW failed: 0x%08x\n", status ); - return FALSE; + WARN( "AcquireCredentialsHandleW failed: %#lx\n", status ); + return status; } - return TRUE; + return ERROR_SUCCESS; } -static BOOL open_connection( struct request *request ) +static DWORD open_connection( struct request *request ) { BOOL is_secure = request->hdr.flags & WINHTTP_FLAG_SECURE; struct hostdata *host = NULL, *iter; @@ -1641,7 +1572,7 @@ static BOOL open_connection( struct request *request ) struct connect *connect; WCHAR *addressW = NULL; INTERNET_PORT port; - DWORD len; + DWORD ret, len; if (request->netconn) goto done; @@ -1652,7 +1583,7 @@ static BOOL open_connection( struct request *request ) LIST_FOR_EACH_ENTRY( iter, &connection_pool, struct hostdata, entry ) { - if (iter->port == port && !strcmpW( connect->servername, iter->hostname ) && !is_secure == !iter->secure) + if (iter->port == port && !wcscmp( connect->servername, iter->hostname ) && !is_secure == !iter->secure) { host = iter; host->ref++; @@ -1662,19 +1593,19 @@ static BOOL open_connection( struct request *request ) if (!host) { - if ((host = heap_alloc( sizeof(*host) ))) + if ((host = malloc( sizeof(*host) ))) { host->ref = 1; host->secure = is_secure; host->port = port; list_init( &host->connections ); - if ((host->hostname = strdupW( connect->servername ))) + if ((host->hostname = wcsdup( connect->servername ))) { list_add_head( &connection_pool, &host->entry ); } else { - heap_free( host ); + free( host ); host = NULL; } } @@ -1682,7 +1613,7 @@ static BOOL open_connection( struct request *request ) LeaveCriticalSection( &connection_pool_cs ); - if (!host) return FALSE; + if (!host) return ERROR_OUTOFMEMORY; for (;;) { @@ -1697,7 +1628,7 @@ static BOOL open_connection( struct request *request ) if (netconn_is_alive( netconn )) break; TRACE("connection %p no longer alive, closing\n", netconn); - netconn_close( netconn ); + netconn_release( netconn ); netconn = NULL; } @@ -1709,22 +1640,22 @@ static BOOL open_connection( struct request *request ) if (!connect->resolved) { - len = strlenW( host->hostname ) + 1; + len = lstrlenW( host->hostname ) + 1; send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME, host->hostname, len ); - if (!netconn_resolve( host->hostname, port, &connect->sockaddr, request->resolve_timeout )) + if ((ret = netconn_resolve( host->hostname, port, &connect->sockaddr, request->resolve_timeout ))) { release_host( host ); - return FALSE; + return ret; } connect->resolved = TRUE; if (!(addressW = addr_to_str( &connect->sockaddr ))) { release_host( host ); - return FALSE; + return ERROR_OUTOFMEMORY; } - len = strlenW( addressW ) + 1; + len = lstrlenW( addressW ) + 1; send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED, addressW, len ); } @@ -1733,68 +1664,68 @@ static BOOL open_connection( struct request *request ) if (!addressW && !(addressW = addr_to_str( &connect->sockaddr ))) { release_host( host ); - return FALSE; + return ERROR_OUTOFMEMORY; } TRACE("connecting to %s:%u\n", debugstr_w(addressW), port); - send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, addressW, 0 ); + len = lstrlenW( addressW ) + 1; + send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, addressW, len ); - if (!(netconn = netconn_create( host, &connect->sockaddr, request->connect_timeout ))) + if ((ret = netconn_create( host, &connect->sockaddr, request->connect_timeout, &netconn ))) { - heap_free( addressW ); + free( addressW ); release_host( host ); - return FALSE; + return ret; } netconn_set_timeout( netconn, TRUE, request->send_timeout ); - netconn_set_timeout( netconn, FALSE, request->receive_response_timeout ); + netconn_set_timeout( netconn, FALSE, request_receive_response_timeout( request )); request->netconn = netconn; if (is_secure) { - if (connect->session->proxy_server && - strcmpiW( connect->hostname, connect->servername )) + if (connect->session->proxy_server && wcsicmp( connect->hostname, connect->servername )) { - if (!secure_proxy_connect( request )) + if ((ret = secure_proxy_connect( request ))) { request->netconn = NULL; - heap_free( addressW ); - netconn_close( netconn ); - return FALSE; + free( addressW ); + netconn_release( netconn ); + return ret; } } CertFreeCertificateContext( request->server_cert ); request->server_cert = NULL; - if (!ensure_cred_handle( request ) || - !netconn_secure_connect( netconn, connect->hostname, request->security_flags, - &request->cred_handle, request->check_revocation )) + if ((ret = ensure_cred_handle( request )) || + (ret = netconn_secure_connect( netconn, connect->hostname, request->security_flags, + &request->cred_handle, request->check_revocation ))) { request->netconn = NULL; - heap_free( addressW ); - netconn_close( netconn ); - return FALSE; + free( addressW ); + netconn_release( netconn ); + return ret; } } - send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, addressW, strlenW(addressW) + 1 ); + send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, addressW, lstrlenW(addressW) + 1 ); } else { TRACE("using connection %p\n", netconn); netconn_set_timeout( netconn, TRUE, request->send_timeout ); - netconn_set_timeout( netconn, FALSE, request->receive_response_timeout ); + netconn_set_timeout( netconn, FALSE, request_receive_response_timeout( request )); request->netconn = netconn; } if (netconn->secure && !(request->server_cert = netconn_get_certificate( netconn ))) { - heap_free( addressW ); - netconn_close( netconn ); - return FALSE; + free( addressW ); + netconn_release( netconn ); + return ERROR_WINHTTP_SECURE_FAILURE; } done: @@ -1802,26 +1733,22 @@ done: request->read_chunked = FALSE; request->read_chunked_size = ~0u; request->read_chunked_eof = FALSE; - heap_free( addressW ); - return TRUE; + free( addressW ); + return ERROR_SUCCESS; } void close_connection( struct request *request ) { if (!request->netconn) return; - send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION, 0, 0 ); - netconn_close( request->netconn ); + netconn_release( request->netconn ); request->netconn = NULL; - send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED, 0, 0 ); } -static BOOL add_host_header( struct request *request, DWORD modifier ) +static DWORD add_host_header( struct request *request, DWORD modifier ) { - BOOL ret; - DWORD len; + DWORD ret, len; WCHAR *host; - static const WCHAR fmt[] = {'%','s',':','%','u',0}; struct connect *connect = request->connect; INTERNET_PORT port; @@ -1829,13 +1756,13 @@ static BOOL add_host_header( struct request *request, DWORD modifier ) if (port == INTERNET_DEFAULT_HTTP_PORT || port == INTERNET_DEFAULT_HTTPS_PORT) { - return process_header( request, attr_host, connect->hostname, modifier, TRUE ); + return process_header( request, L"Host", connect->hostname, modifier, TRUE ); } - len = strlenW( connect->hostname ) + 7; /* sizeof(":65335") */ - if (!(host = heap_alloc( len * sizeof(WCHAR) ))) return FALSE; - sprintfW( host, fmt, connect->hostname, port ); - ret = process_header( request, attr_host, host, modifier, TRUE ); - heap_free( host ); + len = lstrlenW( connect->hostname ) + 7; /* sizeof(":65335") */ + if (!(host = malloc( len * sizeof(WCHAR) ))) return ERROR_OUTOFMEMORY; + swprintf( host, len, L"%s:%u", connect->hostname, port ); + ret = process_header( request, L"Host", host, modifier, TRUE ); + free( host ); return ret; } @@ -1861,12 +1788,12 @@ static void remove_data( struct request *request, int count ) } /* read some more data into the read buffer */ -static BOOL read_more_data( struct request *request, int maxlen, BOOL notify ) +static DWORD read_more_data( struct request *request, int maxlen, BOOL notify ) { int len; - BOOL ret; + DWORD ret; - if (request->read_chunked_eof) return FALSE; + if (request->read_chunked_eof) return ERROR_INSUFFICIENT_BUFFER; if (request->read_size && request->read_pos) { @@ -1882,14 +1809,16 @@ static BOOL read_more_data( struct request *request, int maxlen, BOOL notify ) maxlen - request->read_size, 0, &len ); if (notify) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, &len, sizeof(len) ); + request->read_reply_len += len; request->read_size += len; return ret; } /* discard data contents until we reach end of line */ -static BOOL discard_eol( struct request *request, BOOL notify ) +static DWORD discard_eol( struct request *request, BOOL notify ) { + DWORD ret; do { char *eol = memchr( request->read_buf + request->read_pos, '\n', request->read_size ); @@ -1899,34 +1828,64 @@ static BOOL discard_eol( struct request *request, BOOL notify ) break; } request->read_pos = request->read_size = 0; /* discard everything */ - if (!read_more_data( request, -1, notify )) return FALSE; + if ((ret = read_more_data( request, -1, notify ))) return ret; } while (request->read_size); + return ERROR_SUCCESS; +} + +static void update_value_from_digit( DWORD *value, char ch ) +{ + if (ch >= '0' && ch <= '9') *value = *value * 16 + ch - '0'; + else if (ch >= 'a' && ch <= 'f') *value = *value * 16 + ch - 'a' + 10; + else if (ch >= 'A' && ch <= 'F') *value = *value * 16 + ch - 'A' + 10; +} + +/* read chunk size if already in the read buffer */ +static BOOL get_chunk_size( struct request *request ) +{ + DWORD chunk_size; + char *p, *eol; + + if (request->read_chunked_size != ~0ul) return TRUE; + + eol = memchr( request->read_buf + request->read_pos, '\n', request->read_size ); + if (!eol) return FALSE; + + chunk_size = 0; + for (p = request->read_buf + request->read_pos; p != eol; ++p) + { + if (*p == ';' || *p == '\r') break; + update_value_from_digit( &chunk_size, *p ); + } + + request->read_chunked_size = chunk_size; + if (!chunk_size) request->read_chunked_eof = TRUE; + + remove_data( request, (eol + 1) - (request->read_buf + request->read_pos) ); return TRUE; } /* read the size of the next chunk */ -static BOOL start_next_chunk( struct request *request, BOOL notify ) +static DWORD start_next_chunk( struct request *request, BOOL notify ) { - DWORD chunk_size = 0; + DWORD ret, chunk_size = 0; assert(!request->read_chunked_size || request->read_chunked_size == ~0u); - if (request->read_chunked_eof) return FALSE; + if (request->read_chunked_eof) return ERROR_INSUFFICIENT_BUFFER; /* read terminator for the previous chunk */ - if (!request->read_chunked_size && !discard_eol( request, notify )) return FALSE; + if (!request->read_chunked_size && (ret = discard_eol( request, notify ))) return ret; for (;;) { while (request->read_size) { char ch = request->read_buf[request->read_pos]; - if (ch >= '0' && ch <= '9') chunk_size = chunk_size * 16 + ch - '0'; - else if (ch >= 'a' && ch <= 'f') chunk_size = chunk_size * 16 + ch - 'a' + 10; - else if (ch >= 'A' && ch <= 'F') chunk_size = chunk_size * 16 + ch - 'A' + 10; - else if (ch == ';' || ch == '\r' || ch == '\n') + + if (ch == ';' || ch == '\r' || ch == '\n') { - TRACE("reading %u byte chunk\n", chunk_size); + TRACE( "reading %lu byte chunk\n", chunk_size ); if (request->content_length == ~0u) request->content_length = chunk_size; else request->content_length += chunk_size; @@ -1936,28 +1895,30 @@ static BOOL start_next_chunk( struct request *request, BOOL notify ) return discard_eol( request, notify ); } + update_value_from_digit( &chunk_size, ch ); remove_data( request, 1 ); } - if (!read_more_data( request, -1, notify )) return FALSE; + if ((ret = read_more_data( request, -1, notify ))) return ret; if (!request->read_size) { request->content_length = request->content_read = 0; request->read_chunked_size = 0; - return TRUE; + return ERROR_SUCCESS; } } } -static BOOL refill_buffer( struct request *request, BOOL notify ) +static DWORD refill_buffer( struct request *request, BOOL notify ) { int len = sizeof(request->read_buf); + DWORD ret; if (request->read_chunked) { - if (request->read_chunked_eof) return FALSE; + if (request->read_chunked_eof) return ERROR_INSUFFICIENT_BUFFER; if (request->read_chunked_size == ~0u || !request->read_chunked_size) { - if (!start_next_chunk( request, notify )) return FALSE; + if ((ret = start_next_chunk( request, notify ))) return ret; } len = min( len, request->read_chunked_size ); } @@ -1966,43 +1927,53 @@ static BOOL refill_buffer( struct request *request, BOOL notify ) len = min( len, request->content_length - request->content_read ); } - if (len <= request->read_size) return TRUE; - if (!read_more_data( request, len, notify )) return FALSE; + if (len <= request->read_size) return ERROR_SUCCESS; + if ((ret = read_more_data( request, len, notify ))) return ret; if (!request->read_size) request->content_length = request->content_read = 0; - return TRUE; + return ERROR_SUCCESS; } static void finished_reading( struct request *request ) { - static const WCHAR closeW[] = {'c','l','o','s','e',0}; - - BOOL close = FALSE; + BOOL close = FALSE, close_request_headers; WCHAR connection[20]; DWORD size = sizeof(connection); if (!request->netconn) return; - if (request->hdr.disable_flags & WINHTTP_DISABLE_KEEP_ALIVE) close = TRUE; - else if (query_headers( request, WINHTTP_QUERY_CONNECTION, NULL, connection, &size, NULL ) || - query_headers( request, WINHTTP_QUERY_PROXY_CONNECTION, NULL, connection, &size, NULL )) + if (request->netconn->socket == -1) close = TRUE; + else if (request->hdr.disable_flags & WINHTTP_DISABLE_KEEP_ALIVE) close = TRUE; + else if (!query_headers( request, WINHTTP_QUERY_CONNECTION, NULL, connection, &size, NULL ) || + !query_headers( request, WINHTTP_QUERY_PROXY_CONNECTION, NULL, connection, &size, NULL )) { - if (!strcmpiW( connection, closeW )) close = TRUE; - } - else if (!strcmpW( request->version, http1_0 )) close = TRUE; - if (close) - { - close_connection( request ); - return; + if (!wcsicmp( connection, L"close" )) close = TRUE; } + else if (!wcscmp( request->version, L"HTTP/1.0" )) close = TRUE; - cache_connection( request->netconn ); + size = sizeof(connection); + close_request_headers = + (!query_headers( request, WINHTTP_QUERY_CONNECTION | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, NULL, connection, &size, NULL ) + || !query_headers( request, WINHTTP_QUERY_PROXY_CONNECTION | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, NULL, connection, &size, NULL )) + && !wcsicmp( connection, L"close" ); + if (close || close_request_headers) + { + if (close_request_headers) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION, 0, 0 ); + netconn_release( request->netconn ); + if (close_request_headers) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED, 0, 0 ); + } + else + cache_connection( request->netconn ); request->netconn = NULL; } /* return the size of data available to be read immediately */ static DWORD get_available_data( struct request *request ) { - if (request->read_chunked) return min( request->read_chunked_size, request->read_size ); + if (request->read_chunked) + { + if (!get_chunk_size( request )) return 0; + return min( request->read_chunked_size, request->read_size ); + } return request->read_size; } @@ -2015,10 +1986,13 @@ static BOOL end_of_read_data( struct request *request ) return (request->content_length == request->content_read); } -static BOOL read_data( struct request *request, void *buffer, DWORD size, DWORD *read, BOOL async ) +static DWORD read_data( struct request *request, void *buffer, DWORD size, DWORD *read, BOOL async ) { int count, bytes_read = 0; - BOOL ret = TRUE; + DWORD ret = ERROR_SUCCESS; + + if (request->read_chunked && request->read_chunked_size == ~0u + && (ret = start_next_chunk( request, async ))) goto done; if (end_of_read_data( request )) goto done; @@ -2026,7 +2000,7 @@ static BOOL read_data( struct request *request, void *buffer, DWORD size, DWORD { if (!(count = get_available_data( request ))) { - if (!(ret = refill_buffer( request, async ))) goto done; + if ((ret = refill_buffer( request, async ))) goto done; if (!(count = get_available_data( request ))) goto done; } count = min( count, size ); @@ -2041,21 +2015,21 @@ static BOOL read_data( struct request *request, void *buffer, DWORD size, DWORD if (request->read_chunked && !request->read_chunked_size) ret = refill_buffer( request, async ); done: - TRACE( "retrieved %u bytes (%u/%u)\n", bytes_read, request->content_read, request->content_length ); + TRACE( "retrieved %u bytes (%lu/%lu)\n", bytes_read, request->content_read, request->content_length ); + if (end_of_read_data( request )) finished_reading( request ); if (async) { - if (ret) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, buffer, bytes_read ); + if (!ret) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, buffer, bytes_read ); else { WINHTTP_ASYNC_RESULT result; result.dwResult = API_READ_DATA; - result.dwError = GetLastError(); + result.dwError = ret; send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &result, sizeof(result) ); } } - if (ret && read) *read = bytes_read; - if (end_of_read_data( request )) finished_reading( request ); + if (!ret && read) *read = bytes_read; return ret; } @@ -2069,12 +2043,9 @@ static void drain_content( struct request *request ) for (;;) { if (request->read_chunked) size = sizeof(buffer); - else - { - if (bytes_total >= bytes_left) return; - size = min( sizeof(buffer), bytes_left - bytes_total ); - } - if (!read_data( request, buffer, size, &bytes_read, FALSE ) || !bytes_read) return; + else size = min( sizeof(buffer), bytes_left - bytes_total ); + + if (read_data( request, buffer, size, &bytes_read, FALSE ) || !bytes_read) return; bytes_total += bytes_read; } } @@ -2145,13 +2116,13 @@ static DWORD str_to_wire( const WCHAR *src, int src_len, char *dst, enum escape_ DWORD len; char *utf8; - if (src_len < 0) src_len = strlenW( src ); + if (src_len < 0) src_len = lstrlenW( src ); len = WideCharToMultiByte( CP_UTF8, 0, src, src_len, NULL, 0, NULL, NULL ); - if (!(utf8 = heap_alloc( len ))) return 0; + if (!(utf8 = malloc( len ))) return 0; WideCharToMultiByte( CP_UTF8, 0, src, -1, utf8, len, NULL, NULL ); len = escape_string( utf8, len, dst, flags ); - heap_free( utf8 ); + free( utf8 ); return len; } @@ -2164,16 +2135,16 @@ static char *build_wire_path( struct request *request, DWORD *ret_len ) enum escape_flags path_flags, query_flags; char *ret; - if (!strcmpiW( request->connect->hostname, request->connect->servername )) start = full_path = request->path; + if (!wcsicmp( request->connect->hostname, request->connect->servername )) start = full_path = request->path; else if (!(full_path = build_absolute_request_path( request, &start ))) return NULL; - len = strlenW( full_path ); - if ((path = strchrW( start, '/' ))) + len = lstrlenW( full_path ); + if ((path = wcschr( start, '/' ))) { - len_path = strlenW( path ); - if ((query = strchrW( path, '?' ))) + len_path = lstrlenW( path ); + if ((query = wcschr( path, '?' ))) { - len_query = strlenW( query ); + len_query = lstrlenW( query ); len_path -= len_query; } } @@ -2189,14 +2160,14 @@ static char *build_wire_path( struct request *request, DWORD *ret_len ) if (path) *ret_len += str_to_wire( path, len_path, NULL, path_flags ); if (query) *ret_len += str_to_wire( query, len_query, NULL, query_flags ); - if ((ret = heap_alloc( *ret_len + 1 ))) + if ((ret = malloc( *ret_len + 1 ))) { len = str_to_wire( full_path, len - len_path - len_query, ret, 0 ); if (path) len += str_to_wire( path, len_path, ret + len, path_flags ); if (query) str_to_wire( query, len_query, ret + len, query_flags ); } - if (full_path != request->path) heap_free( full_path ); + if (full_path != request->path) free( full_path ); return ret; } @@ -2221,7 +2192,7 @@ static char *build_wire_request( struct request *request, DWORD *len ) } *len += 4; /* '\r\n\r\n' */ - if ((ret = ptr = heap_alloc( *len + 1 ))) + if ((ret = ptr = malloc( *len + 1 ))) { ptr += str_to_wire( request->verb, -1, ptr, 0 ); *ptr++ = ' '; @@ -2245,29 +2216,59 @@ static char *build_wire_request( struct request *request, DWORD *len ) memcpy( ptr, "\r\n\r\n", sizeof("\r\n\r\n") ); } - heap_free( path ); + free( path ); return ret; } -static BOOL send_request( struct request *request, const WCHAR *headers, DWORD headers_len, void *optional, - DWORD optional_len, DWORD total_len, DWORD_PTR context, BOOL async ) +static WCHAR *create_websocket_key(void) { - static const WCHAR keep_alive[] = {'K','e','e','p','-','A','l','i','v','e',0}; - static const WCHAR no_cache[] = {'n','o','-','c','a','c','h','e',0}; - static const WCHAR length_fmt[] = {'%','l','d',0}; + WCHAR *ret; + char buf[16]; + DWORD base64_len = ((sizeof(buf) + 2) * 4) / 3; + if (!RtlGenRandom( buf, sizeof(buf) )) return NULL; + if ((ret = malloc( (base64_len + 1) * sizeof(WCHAR) ))) encode_base64( buf, sizeof(buf), ret ); + return ret; +} - BOOL ret = FALSE; +static DWORD add_websocket_key_header( struct request *request ) +{ + WCHAR *key = create_websocket_key(); + if (!key) return ERROR_OUTOFMEMORY; + process_header( request, L"Sec-WebSocket-Key", key, WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE, TRUE ); + free( key ); + return ERROR_SUCCESS; +} + +static DWORD send_request( struct request *request, const WCHAR *headers, DWORD headers_len, void *optional, + DWORD optional_len, DWORD total_len, DWORD_PTR context, BOOL async ) +{ struct connect *connect = request->connect; struct session *session = connect->session; + DWORD ret, len, buflen, content_length; + WCHAR encoding[20]; char *wire_req; int bytes_sent; - DWORD len; + BOOL chunked; + + TRACE( "request state %d.\n", request->state ); + + request->read_reply_status = ERROR_WINHTTP_INCORRECT_HANDLE_STATE; + request->read_reply_len = 0; + request->state = REQUEST_RESPONSE_STATE_NONE; + + if (request->flags & REQUEST_FLAG_WEBSOCKET_UPGRADE + && request->websocket_set_send_buffer_size < MIN_WEBSOCKET_SEND_BUFFER_SIZE) + { + WARN( "Invalid send buffer size %u.\n", request->websocket_set_send_buffer_size ); + ret = ERROR_NOT_ENOUGH_MEMORY; + goto end; + } - clear_response_headers( request ); drain_content( request ); + clear_response_headers( request ); if (session->agent) - process_header( request, attr_user_agent, session->agent, WINHTTP_ADDREQ_FLAG_ADD_IF_NEW, TRUE ); + process_header( request, L"User-Agent", session->agent, WINHTTP_ADDREQ_FLAG_ADD_IF_NEW, TRUE ); if (connect->hostname) add_host_header( request, WINHTTP_ADDREQ_FLAG_ADD_IF_NEW ); @@ -2275,86 +2276,132 @@ static BOOL send_request( struct request *request, const WCHAR *headers, DWORD h if (request->creds[TARGET_SERVER][SCHEME_BASIC].username) do_authorization( request, WINHTTP_AUTH_TARGET_SERVER, WINHTTP_AUTH_SCHEME_BASIC ); - if (total_len || (request->verb && !strcmpW( request->verb, postW ))) + buflen = sizeof(encoding); + chunked = !query_headers( request, WINHTTP_QUERY_FLAG_REQUEST_HEADERS | WINHTTP_QUERY_TRANSFER_ENCODING, + NULL, encoding, &buflen, NULL ) && !wcsicmp( encoding, L"chunked" ); + if (!chunked && (total_len || (request->verb && (!wcscmp( request->verb, L"POST" ) + || !wcscmp( request->verb, L"PUT" ))))) { WCHAR length[21]; /* decimal long int + null */ - sprintfW( length, length_fmt, total_len ); - process_header( request, attr_content_length, length, WINHTTP_ADDREQ_FLAG_ADD_IF_NEW, TRUE ); + swprintf( length, ARRAY_SIZE(length), L"%ld", total_len ); + process_header( request, L"Content-Length", length, WINHTTP_ADDREQ_FLAG_ADD_IF_NEW, TRUE ); } - if (!(request->hdr.disable_flags & WINHTTP_DISABLE_KEEP_ALIVE)) + if (request->flags & REQUEST_FLAG_WEBSOCKET_UPGRADE) { - process_header( request, attr_connection, keep_alive, WINHTTP_ADDREQ_FLAG_ADD_IF_NEW, TRUE ); + request->websocket_send_buffer_size = request->websocket_set_send_buffer_size; + process_header( request, L"Upgrade", L"websocket", WINHTTP_ADDREQ_FLAG_ADD_IF_NEW, TRUE ); + process_header( request, L"Connection", L"Upgrade", WINHTTP_ADDREQ_FLAG_ADD_IF_NEW, TRUE ); + process_header( request, L"Sec-WebSocket-Version", L"13", WINHTTP_ADDREQ_FLAG_ADD_IF_NEW, TRUE ); + if ((ret = add_websocket_key_header( request ))) return ret; + } + else if (!(request->hdr.disable_flags & WINHTTP_DISABLE_KEEP_ALIVE)) + { + process_header( request, L"Connection", L"Keep-Alive", WINHTTP_ADDREQ_FLAG_ADD_IF_NEW, TRUE ); } if (request->hdr.flags & WINHTTP_FLAG_REFRESH) { - process_header( request, attr_pragma, no_cache, WINHTTP_ADDREQ_FLAG_ADD_IF_NEW, TRUE ); - process_header( request, attr_cache_control, no_cache, WINHTTP_ADDREQ_FLAG_ADD_IF_NEW, TRUE ); + process_header( request, L"Pragma", L"no-cache", WINHTTP_ADDREQ_FLAG_ADD_IF_NEW, TRUE ); + process_header( request, L"Cache-Control", L"no-cache", WINHTTP_ADDREQ_FLAG_ADD_IF_NEW, TRUE ); } - if (headers && !add_request_headers( request, headers, headers_len, WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE )) + if (headers && (ret = add_request_headers( request, headers, headers_len, + WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE ))) { - TRACE("failed to add request headers\n"); - return FALSE; + TRACE( "failed to add request headers: %lu\n", ret ); + return ret; } - if (!(request->hdr.disable_flags & WINHTTP_DISABLE_COOKIES) && !add_cookie_headers( request )) + if (!(request->hdr.disable_flags & WINHTTP_DISABLE_COOKIES) && (ret = add_cookie_headers( request ))) { - WARN("failed to add cookie headers\n"); - return FALSE; + WARN( "failed to add cookie headers: %lu\n", ret ); + return ret; } if (context) request->hdr.context = context; - if (!(ret = open_connection( request ))) goto end; - if (!(wire_req = build_wire_request( request, &len ))) goto end; + if ((ret = open_connection( request ))) goto end; + if (!(wire_req = build_wire_request( request, &len ))) + { + ret = ERROR_OUTOFMEMORY; + goto end; + } TRACE("full request: %s\n", debugstr_a(wire_req)); + request->state = REQUEST_RESPONSE_STATE_SENDING_REQUEST; send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST, NULL, 0 ); - ret = netconn_send( request->netconn, wire_req, len, &bytes_sent ); - heap_free( wire_req ); - if (!ret) goto end; + ret = netconn_send( request->netconn, wire_req, len, &bytes_sent, NULL ); + free( wire_req ); + if (ret) goto end; if (optional_len) { - if (!netconn_send( request->netconn, optional, optional_len, &bytes_sent )) goto end; + if ((ret = netconn_send( request->netconn, optional, optional_len, &bytes_sent, NULL ))) goto end; request->optional = optional; request->optional_len = optional_len; len += optional_len; } send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_SENT, &len, sizeof(len) ); + buflen = sizeof(content_length); + if (query_headers( request, WINHTTP_QUERY_FLAG_REQUEST_HEADERS | WINHTTP_QUERY_CONTENT_LENGTH + | WINHTTP_QUERY_FLAG_NUMBER, NULL, &content_length, &buflen, NULL )) + content_length = total_len; + + if (!chunked && content_length <= optional_len) + { + netconn_set_timeout( request->netconn, FALSE, request_receive_response_timeout( request )); + request->read_reply_status = read_reply( request ); + if (request->state == REQUEST_RESPONSE_STATE_READ_RESPONSE_QUEUED) + request->state = REQUEST_RESPONSE_STATE_READ_RESPONSE_QUEUED_REPLY_RECEIVED; + else + request->state = REQUEST_RESPONSE_STATE_REPLY_RECEIVED; + } + else + { + if (request->state == REQUEST_RESPONSE_STATE_READ_RESPONSE_QUEUED) + request->state = REQUEST_RESPONSE_STATE_READ_RESPONSE_QUEUED_REQUEST_SENT; + else + request->state = REQUEST_RESPONSE_STATE_REQUEST_SENT; + } + end: if (async) { - if (ret) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE, NULL, 0 ); + if (!ret) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE, NULL, 0 ); else { WINHTTP_ASYNC_RESULT result; result.dwResult = API_SEND_REQUEST; - result.dwError = GetLastError(); + result.dwError = ret; send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &result, sizeof(result) ); } } return ret; } -static void task_send_request( struct task_header *task ) +static void task_send_request( void *ctx, BOOL abort ) { - struct send_request *s = (struct send_request *)task; - send_request( s->hdr.request, s->headers, s->headers_len, s->optional, s->optional_len, s->total_len, s->context, TRUE ); - heap_free( s->headers ); + struct send_request *s = ctx; + struct request *request = (struct request *)s->task_hdr.obj; + + if (abort) return; + + TRACE( "running %p\n", ctx ); + send_request( request, s->headers, s->headers_len, s->optional, s->optional_len, s->total_len, s->context, TRUE ); + + free( s->headers ); } /*********************************************************************** * WinHttpSendRequest (winhttp.@) */ -BOOL WINAPI WinHttpSendRequest( HINTERNET hrequest, LPCWSTR headers, DWORD headers_len, - LPVOID optional, DWORD optional_len, DWORD total_len, DWORD_PTR context ) +BOOL WINAPI WinHttpSendRequest( HINTERNET hrequest, const WCHAR *headers, DWORD headers_len, + void *optional, DWORD optional_len, DWORD total_len, DWORD_PTR context ) { - BOOL ret; + DWORD ret; struct request *request; - TRACE("%p, %s, %u, %p, %u, %u, %lx\n", hrequest, debugstr_wn(headers, headers_len), headers_len, optional, - optional_len, total_len, context); + TRACE( "%p, %s, %lu, %p, %lu, %lu, %Ix\n", hrequest, debugstr_wn(headers, headers_len), headers_len, optional, + optional_len, total_len, context ); if (!(request = (struct request *)grab_object( hrequest ))) { @@ -2368,84 +2415,88 @@ BOOL WINAPI WinHttpSendRequest( HINTERNET hrequest, LPCWSTR headers, DWORD heade return FALSE; } - if (headers && !headers_len) headers_len = strlenW( headers ); + if (headers && !headers_len) headers_len = lstrlenW( headers ); if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC) { struct send_request *s; - if (!(s = heap_alloc( sizeof(struct send_request) ))) return FALSE; - s->hdr.request = request; - s->hdr.proc = task_send_request; - s->headers = strdupW( headers ); + if (!(s = malloc( sizeof(*s) ))) + { + release_object( &request->hdr ); + SetLastError( ERROR_OUTOFMEMORY ); + return FALSE; + } + s->headers = wcsdup( headers ); s->headers_len = headers_len; s->optional = optional; s->optional_len = optional_len; s->total_len = total_len; s->context = context; - addref_object( &request->hdr ); - ret = queue_task( (struct task_header *)s ); + if ((ret = queue_task( &request->queue, task_send_request, &s->task_hdr, &request->hdr ))) + { + free( s->headers ); + free( s ); + } } - else - ret = send_request( request, headers, headers_len, optional, optional_len, total_len, context, FALSE ); + else ret = send_request( request, headers, headers_len, optional, optional_len, total_len, context, FALSE ); release_object( &request->hdr ); - if (ret) SetLastError( ERROR_SUCCESS ); - return ret; + SetLastError( ret ); + return !ret; } -static BOOL set_credentials( struct request *request, DWORD target, DWORD scheme_flag, const WCHAR *username, - const WCHAR *password ) +static DWORD set_credentials( struct request *request, DWORD target, DWORD scheme_flag, const WCHAR *username, + const WCHAR *password ) { enum auth_scheme scheme = scheme_from_flag( scheme_flag ); if (scheme == SCHEME_INVALID || ((scheme == SCHEME_BASIC || scheme == SCHEME_DIGEST) && (!username || !password))) { - SetLastError( ERROR_INVALID_PARAMETER ); - return FALSE; + return ERROR_INVALID_PARAMETER; } switch (target) { case WINHTTP_AUTH_TARGET_SERVER: { - heap_free( request->creds[TARGET_SERVER][scheme].username ); + free( request->creds[TARGET_SERVER][scheme].username ); if (!username) request->creds[TARGET_SERVER][scheme].username = NULL; - else if (!(request->creds[TARGET_SERVER][scheme].username = strdupW( username ))) return FALSE; + else if (!(request->creds[TARGET_SERVER][scheme].username = wcsdup( username ))) return ERROR_OUTOFMEMORY; - heap_free( request->creds[TARGET_SERVER][scheme].password ); + free( request->creds[TARGET_SERVER][scheme].password ); if (!password) request->creds[TARGET_SERVER][scheme].password = NULL; - else if (!(request->creds[TARGET_SERVER][scheme].password = strdupW( password ))) return FALSE; + else if (!(request->creds[TARGET_SERVER][scheme].password = wcsdup( password ))) return ERROR_OUTOFMEMORY; break; } case WINHTTP_AUTH_TARGET_PROXY: { - heap_free( request->creds[TARGET_PROXY][scheme].username ); + free( request->creds[TARGET_PROXY][scheme].username ); if (!username) request->creds[TARGET_PROXY][scheme].username = NULL; - else if (!(request->creds[TARGET_PROXY][scheme].username = strdupW( username ))) return FALSE; + else if (!(request->creds[TARGET_PROXY][scheme].username = wcsdup( username ))) return ERROR_OUTOFMEMORY; - heap_free( request->creds[TARGET_PROXY][scheme].password ); + free( request->creds[TARGET_PROXY][scheme].password ); if (!password) request->creds[TARGET_PROXY][scheme].password = NULL; - else if (!(request->creds[TARGET_PROXY][scheme].password = strdupW( password ))) return FALSE; + else if (!(request->creds[TARGET_PROXY][scheme].password = wcsdup( password ))) return ERROR_OUTOFMEMORY; break; } default: - WARN("unknown target %u\n", target); - return FALSE; + WARN( "unknown target %lu\n", target ); + return ERROR_INVALID_PARAMETER; } - return TRUE; + return ERROR_SUCCESS; } /*********************************************************************** * WinHttpSetCredentials (winhttp.@) */ -BOOL WINAPI WinHttpSetCredentials( HINTERNET hrequest, DWORD target, DWORD scheme, LPCWSTR username, - LPCWSTR password, LPVOID params ) +BOOL WINAPI WinHttpSetCredentials( HINTERNET hrequest, DWORD target, DWORD scheme, const WCHAR *username, + const WCHAR *password, void *params ) { - BOOL ret; + DWORD ret; struct request *request; - TRACE("%p, %x, 0x%08x, %s, %p, %p\n", hrequest, target, scheme, debugstr_w(username), password, params); + TRACE( "%p, %lu, %#lx, %s, %p, %p\n", hrequest, target, scheme, debugstr_w(username), password, params ); if (!(request = (struct request *)grab_object( hrequest ))) { @@ -2462,13 +2513,13 @@ BOOL WINAPI WinHttpSetCredentials( HINTERNET hrequest, DWORD target, DWORD schem ret = set_credentials( request, target, scheme, username, password ); release_object( &request->hdr ); - if (ret) SetLastError( ERROR_SUCCESS ); - return ret; + SetLastError( ret ); + return !ret; } -static BOOL handle_authorization( struct request *request, DWORD status ) +static DWORD handle_authorization( struct request *request, DWORD status ) { - DWORD i, schemes, first, level, target; + DWORD ret, i, schemes, first, level, target; switch (status) { @@ -2483,39 +2534,42 @@ static BOOL handle_authorization( struct request *request, DWORD status ) break; default: - WARN("unhandled status %u\n", status); - return FALSE; + ERR( "unhandled status %lu\n", status ); + return ERROR_WINHTTP_INTERNAL_ERROR; } - if (!query_auth_schemes( request, level, &schemes, &first )) return FALSE; - if (do_authorization( request, target, first )) return TRUE; + if ((ret = query_auth_schemes( request, level, &schemes, &first ))) return ret; + if (do_authorization( request, target, first )) return ERROR_SUCCESS; schemes &= ~first; for (i = 0; i < ARRAY_SIZE( auth_schemes ); i++) { if (!(schemes & auth_schemes[i].scheme)) continue; - if (do_authorization( request, target, auth_schemes[i].scheme )) return TRUE; + if (do_authorization( request, target, auth_schemes[i].scheme )) return ERROR_SUCCESS; } - return FALSE; + return ERROR_WINHTTP_LOGIN_FAILURE; } /* set the request content length based on the headers */ -static DWORD set_content_length( struct request *request, DWORD status ) +static void set_content_length( struct request *request, DWORD status ) { WCHAR encoding[20]; DWORD buflen = sizeof(request->content_length); - if (status == HTTP_STATUS_NO_CONTENT || status == HTTP_STATUS_NOT_MODIFIED || !strcmpW( request->verb, headW )) + if (status == HTTP_STATUS_NO_CONTENT || status == HTTP_STATUS_NOT_MODIFIED || + status == HTTP_STATUS_SWITCH_PROTOCOLS || !wcscmp( request->verb, L"HEAD" )) + { request->content_length = 0; + } else { - if (!query_headers( request, WINHTTP_QUERY_CONTENT_LENGTH|WINHTTP_QUERY_FLAG_NUMBER, - NULL, &request->content_length, &buflen, NULL )) + if (query_headers( request, WINHTTP_QUERY_CONTENT_LENGTH|WINHTTP_QUERY_FLAG_NUMBER, + NULL, &request->content_length, &buflen, NULL )) request->content_length = ~0u; buflen = sizeof(encoding); - if (query_headers( request, WINHTTP_QUERY_TRANSFER_ENCODING, NULL, encoding, &buflen, NULL ) && - !strcmpiW( encoding, chunkedW )) + if (!query_headers( request, WINHTTP_QUERY_TRANSFER_ENCODING, NULL, encoding, &buflen, NULL ) && + !wcsicmp( encoding, L"chunked" )) { request->content_length = ~0u; request->read_chunked = TRUE; @@ -2524,12 +2578,12 @@ static DWORD set_content_length( struct request *request, DWORD status ) } } request->content_read = 0; - return request->content_length; } -static BOOL read_line( struct request *request, char *buffer, DWORD *len ) +static DWORD read_line( struct request *request, char *buffer, DWORD *len ) { int count, bytes_read, pos = 0; + DWORD ret; for (;;) { @@ -2547,12 +2601,12 @@ static BOOL read_line( struct request *request, char *buffer, DWORD *len ) remove_data( request, bytes_read ); if (eol) break; - if (!read_more_data( request, -1, TRUE )) return FALSE; + if ((ret = read_more_data( request, -1, FALSE ))) return ret; if (!request->read_size) { *len = 0; TRACE("returning empty string\n"); - return FALSE; + return ERROR_WINHTTP_INVALID_SERVER_RESPONSE; } } if (pos < *len) @@ -2562,34 +2616,32 @@ static BOOL read_line( struct request *request, char *buffer, DWORD *len ) } buffer[*len - 1] = 0; TRACE("returning %s\n", debugstr_a(buffer)); - return TRUE; + return ERROR_SUCCESS; } #define MAX_REPLY_LEN 1460 #define INITIAL_HEADER_BUFFER_LEN 512 -static BOOL read_reply( struct request *request ) +static DWORD read_reply( struct request *request ) { - static const WCHAR crlf[] = {'\r','\n',0}; - char buffer[MAX_REPLY_LEN]; - DWORD buflen, len, offset, crlf_len = 2; /* strlenW(crlf) */ + DWORD ret, buflen, len, offset, crlf_len = 2; /* lstrlenW(crlf) */ char *status_code, *status_text; WCHAR *versionW, *status_textW, *raw_headers; WCHAR status_codeW[4]; /* sizeof("nnn") */ - if (!request->netconn) return FALSE; + if (!request->netconn) return ERROR_WINHTTP_INCORRECT_HANDLE_STATE; do { buflen = MAX_REPLY_LEN; - if (!read_line( request, buffer, &buflen )) return FALSE; + if ((ret = read_line( request, buffer, &buflen ))) return ret; /* first line should look like 'HTTP/1.x nnn OK' where nnn is the status code */ - if (!(status_code = strchr( buffer, ' ' ))) return FALSE; + if (!(status_code = strchr( buffer, ' ' ))) return ERROR_WINHTTP_INVALID_SERVER_RESPONSE; status_code++; - if (!(status_text = strchr( status_code, ' ' ))) return FALSE; - if ((len = status_text - status_code) != sizeof("nnn") - 1) return FALSE; + if (!(status_text = strchr( status_code, ' ' ))) return ERROR_WINHTTP_INVALID_SERVER_RESPONSE; + if ((len = status_text - status_code) != sizeof("nnn") - 1) return ERROR_WINHTTP_INVALID_SERVER_RESPONSE; status_text++; TRACE("version [%s] status code [%s] status text [%s]\n", @@ -2602,69 +2654,89 @@ static BOOL read_reply( struct request *request ) /* we rely on the fact that the protocol is ascii */ MultiByteToWideChar( CP_ACP, 0, status_code, len, status_codeW, len ); status_codeW[len] = 0; - if (!(process_header( request, attr_status, status_codeW, - WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE, FALSE ))) - return FALSE; + if ((ret = process_header( request, L"Status", status_codeW, + WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE, FALSE ))) return ret; len = status_code - buffer; - if (!(versionW = heap_alloc( len * sizeof(WCHAR) ))) return FALSE; + if (!(versionW = malloc( len * sizeof(WCHAR) ))) return ERROR_OUTOFMEMORY; MultiByteToWideChar( CP_ACP, 0, buffer, len - 1, versionW, len -1 ); versionW[len - 1] = 0; - heap_free( request->version ); + free( request->version ); request->version = versionW; len = buflen - (status_text - buffer); - if (!(status_textW = heap_alloc( len * sizeof(WCHAR) ))) return FALSE; + if (!(status_textW = malloc( len * sizeof(WCHAR) ))) return ERROR_OUTOFMEMORY; MultiByteToWideChar( CP_ACP, 0, status_text, len, status_textW, len ); - heap_free( request->status_text ); + free( request->status_text ); request->status_text = status_textW; len = max( buflen + crlf_len, INITIAL_HEADER_BUFFER_LEN ); - if (!(raw_headers = heap_alloc( len * sizeof(WCHAR) ))) return FALSE; + if (!(raw_headers = malloc( len * sizeof(WCHAR) ))) return ERROR_OUTOFMEMORY; MultiByteToWideChar( CP_ACP, 0, buffer, buflen, raw_headers, buflen ); - memcpy( raw_headers + buflen - 1, crlf, sizeof(crlf) ); + memcpy( raw_headers + buflen - 1, L"\r\n", sizeof(L"\r\n") ); - heap_free( request->raw_headers ); + free( request->raw_headers ); request->raw_headers = raw_headers; offset = buflen + crlf_len - 1; for (;;) { struct header *header; + int lenW; buflen = MAX_REPLY_LEN; - if (!read_line( request, buffer, &buflen )) return TRUE; + if (read_line( request, buffer, &buflen )) return ERROR_SUCCESS; if (!*buffer) buflen = 1; while (len - offset < buflen + crlf_len) { WCHAR *tmp; len *= 2; - if (!(tmp = heap_realloc( raw_headers, len * sizeof(WCHAR) ))) return FALSE; + if (!(tmp = realloc( raw_headers, len * sizeof(WCHAR) ))) return ERROR_OUTOFMEMORY; request->raw_headers = raw_headers = tmp; } if (!*buffer) { - memcpy( raw_headers + offset, crlf, sizeof(crlf) ); + memcpy( raw_headers + offset, L"\r\n", sizeof(L"\r\n") ); break; } - MultiByteToWideChar( CP_ACP, 0, buffer, buflen, raw_headers + offset, buflen ); + lenW = MultiByteToWideChar( CP_ACP, 0, buffer, buflen, raw_headers + offset, buflen ); - if (!(header = parse_header( raw_headers + offset ))) break; - if (!(process_header( request, header->field, header->value, WINHTTP_ADDREQ_FLAG_ADD, FALSE ))) + if (!(header = parse_header( raw_headers + offset, lenW - 1, TRUE ))) break; + if ((ret = process_header( request, header->field, header->value, WINHTTP_ADDREQ_FLAG_ADD, FALSE ))) { free_header( header ); break; } + + lenW = wcslen( header->field ); + assert( len - offset >= lenW + 1 ); + memcpy( raw_headers + offset, header->field, lenW * sizeof(WCHAR) ); + offset += lenW; + + lenW = 2; + assert( len - offset >= lenW + 1 ); + memcpy( raw_headers + offset, L": ", lenW * sizeof(WCHAR) ); + offset += lenW; + + lenW = wcslen( header->value ); + assert( len - offset >= lenW + 1 ); + memcpy( raw_headers + offset, header->value, lenW * sizeof(WCHAR) ); + offset += lenW; + + lenW = crlf_len; + assert( len - offset >= lenW + 1 ); + memcpy( raw_headers + offset, L"\r\n", lenW * sizeof(WCHAR) ); + offset += lenW; + + raw_headers[offset] = 0; free_header( header ); - memcpy( raw_headers + offset + buflen - 1, crlf, sizeof(crlf) ); - offset += buflen + crlf_len - 1; } TRACE("raw headers: %s\n", debugstr_w(raw_headers)); - return TRUE; + return ret; } static void record_cookies( struct request *request ) @@ -2674,38 +2746,40 @@ static void record_cookies( struct request *request ) for (i = 0; i < request->num_headers; i++) { struct header *set_cookie = &request->headers[i]; - if (!strcmpiW( set_cookie->field, attr_set_cookie ) && !set_cookie->is_request) + if (!wcsicmp( set_cookie->field, L"Set-Cookie" ) && !set_cookie->is_request) { set_cookies( request, set_cookie->value ); } } } -static WCHAR *get_redirect_url( struct request *request, DWORD *len ) +static DWORD get_redirect_url( struct request *request, WCHAR **ret_url, DWORD *ret_len ) { - DWORD size; - WCHAR *ret; + DWORD size, ret; + WCHAR *url; - query_headers( request, WINHTTP_QUERY_LOCATION, NULL, NULL, &size, NULL ); - if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return NULL; - if (!(ret = heap_alloc( size ))) return NULL; - *len = size / sizeof(WCHAR) - 1; - if (query_headers( request, WINHTTP_QUERY_LOCATION, NULL, ret, &size, NULL )) return ret; - heap_free( ret ); - return NULL; + ret = query_headers( request, WINHTTP_QUERY_LOCATION, NULL, NULL, &size, NULL ); + if (ret != ERROR_INSUFFICIENT_BUFFER) return ret; + if (!(url = malloc( size ))) return ERROR_OUTOFMEMORY; + if ((ret = query_headers( request, WINHTTP_QUERY_LOCATION, NULL, url, &size, NULL ))) + { + free( url ); + return ret; + } + *ret_url = url; + *ret_len = size / sizeof(WCHAR); + return ERROR_SUCCESS; } -static BOOL handle_redirect( struct request *request, DWORD status ) +static DWORD handle_redirect( struct request *request, DWORD status ) { - BOOL ret = FALSE; - DWORD len, len_loc; + DWORD ret, len, len_loc = 0; URL_COMPONENTS uc; struct connect *connect = request->connect; INTERNET_PORT port; - WCHAR *hostname = NULL, *location; - int index; + WCHAR *hostname = NULL, *location = NULL; - if (!(location = get_redirect_url( request, &len_loc ))) return FALSE; + if ((ret = get_redirect_url( request, &location, &len_loc ))) return ret; memset( &uc, 0, sizeof(uc) ); uc.dwStructSize = sizeof(uc); @@ -2715,24 +2789,26 @@ static BOOL handle_redirect( struct request *request, DWORD status ) { WCHAR *path, *p; + ret = ERROR_OUTOFMEMORY; if (location[0] == '/') { - if (!(path = heap_alloc( (len_loc + 1) * sizeof(WCHAR) ))) goto end; + if (!(path = malloc( (len_loc + 1) * sizeof(WCHAR) ))) goto end; memcpy( path, location, len_loc * sizeof(WCHAR) ); path[len_loc] = 0; } else { - if ((p = strrchrW( request->path, '/' ))) *p = 0; - len = strlenW( request->path ) + 1 + len_loc; - if (!(path = heap_alloc( (len + 1) * sizeof(WCHAR) ))) goto end; - strcpyW( path, request->path ); - strcatW( path, slashW ); - memcpy( path + strlenW(path), location, len_loc * sizeof(WCHAR) ); + if ((p = wcsrchr( request->path, '/' ))) *p = 0; + len = lstrlenW( request->path ) + 1 + len_loc; + if (!(path = malloc( (len + 1) * sizeof(WCHAR) ))) goto end; + lstrcpyW( path, request->path ); + lstrcatW( path, L"/" ); + memcpy( path + lstrlenW(path), location, len_loc * sizeof(WCHAR) ); path[len_loc] = 0; } - heap_free( request->path ); + free( request->path ); request->path = path; + ret = ERROR_SUCCESS; send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REDIRECT, location, len_loc + 1 ); } @@ -2740,7 +2816,11 @@ static BOOL handle_redirect( struct request *request, DWORD status ) { if (uc.nScheme == INTERNET_SCHEME_HTTP && request->hdr.flags & WINHTTP_FLAG_SECURE) { - if (request->hdr.redirect_policy == WINHTTP_OPTION_REDIRECT_POLICY_DISALLOW_HTTPS_TO_HTTP) goto end; + if (request->hdr.redirect_policy == WINHTTP_OPTION_REDIRECT_POLICY_DISALLOW_HTTPS_TO_HTTP) + { + ret = ERROR_WINHTTP_REDIRECT_FAILED; + goto end; + } TRACE("redirect from secure page to non-secure page\n"); request->hdr.flags &= ~WINHTTP_FLAG_SECURE; } @@ -2753,56 +2833,58 @@ static BOOL handle_redirect( struct request *request, DWORD status ) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REDIRECT, location, len_loc + 1 ); len = uc.dwHostNameLength; - if (!(hostname = heap_alloc( (len + 1) * sizeof(WCHAR) ))) goto end; + if (!(hostname = malloc( (len + 1) * sizeof(WCHAR) ))) + { + ret = ERROR_OUTOFMEMORY; + goto end; + } memcpy( hostname, uc.lpszHostName, len * sizeof(WCHAR) ); hostname[len] = 0; port = uc.nPort ? uc.nPort : (uc.nScheme == INTERNET_SCHEME_HTTPS ? 443 : 80); - if (strcmpiW( connect->hostname, hostname ) || connect->serverport != port) + if (wcsicmp( connect->hostname, hostname ) || connect->serverport != port) { - heap_free( connect->hostname ); + free( connect->hostname ); connect->hostname = hostname; connect->hostport = port; - if (!(ret = set_server_for_hostname( connect, hostname, port ))) goto end; + if (!set_server_for_hostname( connect, hostname, port )) + { + ret = ERROR_OUTOFMEMORY; + goto end; + } - netconn_close( request->netconn ); + netconn_release( request->netconn ); request->netconn = NULL; request->content_length = request->content_read = 0; request->read_pos = request->read_size = 0; request->read_chunked = request->read_chunked_eof = FALSE; } - else heap_free( hostname ); + else free( hostname ); - if (!(ret = add_host_header( request, WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE ))) goto end; - if (!(ret = open_connection( request ))) goto end; + if ((ret = add_host_header( request, WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE ))) goto end; - heap_free( request->path ); + free( request->path ); request->path = NULL; if (uc.dwUrlPathLength) { len = uc.dwUrlPathLength + uc.dwExtraInfoLength; - if (!(request->path = heap_alloc( (len + 1) * sizeof(WCHAR) ))) goto end; + if (!(request->path = malloc( (len + 1) * sizeof(WCHAR) ))) goto end; memcpy( request->path, uc.lpszUrlPath, (len + 1) * sizeof(WCHAR) ); request->path[len] = 0; } - else request->path = strdupW( slashW ); + else request->path = wcsdup( L"/" ); } - /* remove content-type/length headers */ - if ((index = get_header_index( request, attr_content_type, 0, TRUE )) >= 0) delete_header( request, index ); - if ((index = get_header_index( request, attr_content_length, 0, TRUE )) >= 0 ) delete_header( request, index ); - - if (status != HTTP_STATUS_REDIRECT_KEEP_VERB && !strcmpW( request->verb, postW )) + if (status != HTTP_STATUS_REDIRECT_KEEP_VERB && !wcscmp( request->verb, L"POST" )) { - heap_free( request->verb ); - request->verb = strdupW( getW ); + free( request->verb ); + request->verb = wcsdup( L"GET" ); request->optional = NULL; request->optional_len = 0; } - ret = TRUE; end: - heap_free( location ); + free( location ); return ret; } @@ -2813,22 +2895,21 @@ static BOOL is_passport_request( struct request *request ) DWORD len = ARRAY_SIZE(buf); if (!(request->connect->session->passport_flags & WINHTTP_ENABLE_PASSPORT_AUTH) || - !query_headers( request, WINHTTP_QUERY_WWW_AUTHENTICATE, NULL, buf, &len, NULL )) return FALSE; + query_headers( request, WINHTTP_QUERY_WWW_AUTHENTICATE, NULL, buf, &len, NULL )) return FALSE; - if (!strncmpiW( buf, passportW, ARRAY_SIZE(passportW) ) && + if (!wcsnicmp( buf, passportW, ARRAY_SIZE(passportW) ) && (buf[ARRAY_SIZE(passportW)] == ' ' || !buf[ARRAY_SIZE(passportW)])) return TRUE; return FALSE; } -static BOOL handle_passport_redirect( struct request *request ) +static DWORD handle_passport_redirect( struct request *request ) { - static const WCHAR status401W[] = {'4','0','1',0}; - DWORD flags = WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE; - int i, len = strlenW( request->raw_headers ); + DWORD ret, flags = WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE; + int i, len = lstrlenW( request->raw_headers ); WCHAR *p = request->raw_headers; - if (!process_header( request, attr_status, status401W, flags, FALSE )) return FALSE; + if ((ret = process_header( request, L"Status", L"401", flags, FALSE ))) return ret; for (i = 0; i < len; i++) { @@ -2839,83 +2920,146 @@ static BOOL handle_passport_redirect( struct request *request ) break; } } - return TRUE; + return ERROR_SUCCESS; } -static BOOL receive_response( struct request *request, BOOL async ) +static void task_receive_response( void *ctx, BOOL abort ); + +static DWORD queue_receive_response( struct request *request ) { - BOOL ret; - DWORD size, query, status; + struct receive_response *r; + DWORD ret; - if (!request->netconn) + if (!(r = malloc( sizeof(*r) ))) return ERROR_OUTOFMEMORY; + if ((ret = queue_task( &request->queue, task_receive_response, &r->task_hdr, &request->hdr ))) + free( r ); + return ret; +} + +static DWORD receive_response( struct request *request ) +{ + BOOL async_mode = request->connect->hdr.flags & WINHTTP_FLAG_ASYNC; + DWORD ret, size, query, status; + + TRACE( "request state %d.\n", request->state ); + + switch (request->state) { - SetLastError( ERROR_WINHTTP_INCORRECT_HANDLE_STATE ); - return FALSE; - } - - netconn_set_timeout( request->netconn, FALSE, request->receive_response_timeout ); - for (;;) - { - if (!(ret = read_reply( request ))) - { - SetLastError( ERROR_WINHTTP_INVALID_SERVER_RESPONSE ); - break; - } - size = sizeof(DWORD); - query = WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER; - if (!(ret = query_headers( request, query, NULL, &status, &size, NULL ))) break; - - set_content_length( request, status ); - - if (!(request->hdr.disable_flags & WINHTTP_DISABLE_COOKIES)) record_cookies( request ); - - if (status == HTTP_STATUS_REDIRECT && is_passport_request( request )) - { - ret = handle_passport_redirect( request ); - } - else if (status == HTTP_STATUS_MOVED || status == HTTP_STATUS_REDIRECT || status == HTTP_STATUS_REDIRECT_KEEP_VERB) - { - if (request->hdr.disable_flags & WINHTTP_DISABLE_REDIRECTS || - request->hdr.redirect_policy == WINHTTP_OPTION_REDIRECT_POLICY_NEVER) break; - - if (!(ret = handle_redirect( request, status ))) break; - - /* recurse synchronously */ - if ((ret = send_request( request, NULL, 0, request->optional, request->optional_len, 0, 0, FALSE ))) continue; - } - else if (status == HTTP_STATUS_DENIED || status == HTTP_STATUS_PROXY_AUTH_REQ) - { - if (request->hdr.disable_flags & WINHTTP_DISABLE_AUTHENTICATION) break; - - if (!handle_authorization( request, status )) break; - - /* recurse synchronously */ - if ((ret = send_request( request, NULL, 0, request->optional, request->optional_len, 0, 0, FALSE ))) continue; - } + case REQUEST_RESPONSE_RECURSIVE_REQUEST: + TRACE( "Sending request.\n" ); + if ((ret = send_request( request, NULL, 0, request->optional, request->optional_len, 0, 0, FALSE ))) goto done; + send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NULL, 0 ); break; + + case REQUEST_RESPONSE_STATE_SENDING_REQUEST: + if (!async_mode) + { + ret = ERROR_WINHTTP_INCORRECT_HANDLE_STATE; + goto done; + } + send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NULL, 0 ); + request->state = REQUEST_RESPONSE_STATE_READ_RESPONSE_QUEUED; + return queue_receive_response( request ); + + + case REQUEST_RESPONSE_STATE_REQUEST_SENT: + send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NULL, 0 ); + if (async_mode) + { + request->state = REQUEST_RESPONSE_STATE_READ_RESPONSE_QUEUED_REQUEST_SENT; + return queue_receive_response( request ); + } + /* fallthrough */ + case REQUEST_RESPONSE_STATE_READ_RESPONSE_QUEUED_REQUEST_SENT: + netconn_set_timeout( request->netconn, FALSE, request_receive_response_timeout( request )); + request->read_reply_status = read_reply( request ); + request->state = REQUEST_RESPONSE_STATE_REPLY_RECEIVED; + break; + + case REQUEST_RESPONSE_STATE_REPLY_RECEIVED: + send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NULL, 0 ); + break; + + case REQUEST_RESPONSE_STATE_READ_RESPONSE_QUEUED_REPLY_RECEIVED: + request->state = REQUEST_RESPONSE_STATE_REPLY_RECEIVED; + break; + + default: + ret = ERROR_WINHTTP_INCORRECT_HANDLE_STATE; + goto done; } - netconn_set_timeout( request->netconn, FALSE, request->receive_timeout ); - if (request->content_length) ret = refill_buffer( request, FALSE ); + send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, + &request->read_reply_len, sizeof(request->read_reply_len) ); + if ((ret = request->read_reply_status)) goto done; - if (async) + size = sizeof(DWORD); + query = WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER; + if ((ret = query_headers( request, query, NULL, &status, &size, NULL ))) goto done; + + set_content_length( request, status ); + + if (!(request->hdr.disable_flags & WINHTTP_DISABLE_COOKIES)) record_cookies( request ); + + if (status == HTTP_STATUS_REDIRECT && is_passport_request( request )) { - if (ret) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NULL, 0 ); + ret = handle_passport_redirect( request ); + goto done; + } + if (status == HTTP_STATUS_MOVED || status == HTTP_STATUS_REDIRECT || status == HTTP_STATUS_REDIRECT_KEEP_VERB) + { + if (request->hdr.disable_flags & WINHTTP_DISABLE_REDIRECTS || + request->hdr.redirect_policy == WINHTTP_OPTION_REDIRECT_POLICY_NEVER) goto done; + + if (++request->redirect_count > request->max_redirects) + { + ret = ERROR_WINHTTP_REDIRECT_FAILED; + goto done; + } + + if ((ret = handle_redirect( request, status ))) goto done; + } + else if (status == HTTP_STATUS_DENIED || status == HTTP_STATUS_PROXY_AUTH_REQ) + { + if (request->hdr.disable_flags & WINHTTP_DISABLE_AUTHENTICATION) goto done; + + if (handle_authorization( request, status )) goto done; + } + else goto done; + + request->state = REQUEST_RESPONSE_RECURSIVE_REQUEST; + return async_mode ? queue_receive_response( request ) : receive_response( request ); + +done: + if (!ret) + { + request->state = REQUEST_RESPONSE_STATE_RESPONSE_RECEIVED; + if (request->netconn) netconn_set_timeout( request->netconn, FALSE, request->receive_timeout ); + } + if (async_mode) + { + if (!ret) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NULL, 0 ); else { WINHTTP_ASYNC_RESULT result; result.dwResult = API_RECEIVE_RESPONSE; - result.dwError = GetLastError(); + result.dwError = ret; send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &result, sizeof(result) ); } + return ERROR_SUCCESS; } return ret; } -static void task_receive_response( struct task_header *task ) +static void task_receive_response( void *ctx, BOOL abort ) { - struct receive_response *r = (struct receive_response *)task; - receive_response( r->hdr.request, TRUE ); + struct receive_response *r = ctx; + struct request *request = (struct request *)r->task_hdr.obj; + + if (abort) return; + + TRACE("running %p\n", ctx); + receive_response( request ); } /*********************************************************************** @@ -2923,7 +3067,7 @@ static void task_receive_response( struct task_header *task ) */ BOOL WINAPI WinHttpReceiveResponse( HINTERNET hrequest, LPVOID reserved ) { - BOOL ret; + DWORD ret; struct request *request; TRACE("%p, %p\n", hrequest, reserved); @@ -2940,63 +3084,70 @@ BOOL WINAPI WinHttpReceiveResponse( HINTERNET hrequest, LPVOID reserved ) return FALSE; } - if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC) - { - struct receive_response *r; - - if (!(r = heap_alloc( sizeof(struct receive_response) ))) return FALSE; - r->hdr.request = request; - r->hdr.proc = task_receive_response; - - addref_object( &request->hdr ); - ret = queue_task( (struct task_header *)r ); - } - else - ret = receive_response( request, FALSE ); + ret = receive_response( request ); release_object( &request->hdr ); - if (ret) SetLastError( ERROR_SUCCESS ); - return ret; + SetLastError( ret ); + return !ret; } -static BOOL query_data_available( struct request *request, DWORD *available, BOOL async ) +static DWORD query_data_ready( struct request *request ) { - DWORD count = 0; - BOOL ret = TRUE; - - if (end_of_read_data( request )) goto done; + DWORD count; count = get_available_data( request ); if (!request->read_chunked && request->netconn) count += netconn_query_data_available( request->netconn ); - if (!count) + + return count; +} + +static BOOL skip_async_queue( struct request *request, BOOL *wont_block, DWORD to_read ) +{ + if (!request->read_chunked) + to_read = min( to_read, request->content_length - request->content_read ); + *wont_block = end_of_read_data( request ) || query_data_ready( request ) >= to_read; + return request->hdr.recursion_count < 3 && *wont_block; +} + +static DWORD query_data_available( struct request *request, DWORD *available, BOOL async ) +{ + DWORD ret = ERROR_SUCCESS, count = 0; + + if (end_of_read_data( request )) goto done; + + if (!(count = query_data_ready( request ))) { - if (!(ret = refill_buffer( request, async ))) goto done; - count = get_available_data( request ); - if (!request->read_chunked && request->netconn) count += netconn_query_data_available( request->netconn ); + if ((ret = refill_buffer( request, async ))) goto done; + count = query_data_ready( request ); } done: - TRACE("%u bytes available\n", count); + TRACE( "%lu bytes available\n", count ); if (async) { - if (ret) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE, &count, sizeof(count) ); + if (!ret) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE, &count, sizeof(count) ); else { WINHTTP_ASYNC_RESULT result; result.dwResult = API_QUERY_DATA_AVAILABLE; - result.dwError = GetLastError(); + result.dwError = ret; send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &result, sizeof(result) ); } } - if (ret && available) *available = count; + if (!ret && available) *available = count; return ret; } -static void task_query_data_available( struct task_header *task ) +static void task_query_data_available( void *ctx, BOOL abort ) { - struct query_data *q = (struct query_data *)task; - query_data_available( q->hdr.request, q->available, TRUE ); + struct query_data *q = ctx; + struct request *request = (struct request *)q->task_hdr.obj; + + if (abort) return; + + TRACE("running %p\n", ctx); + query_data_available( request, q->available, TRUE ); } /*********************************************************************** @@ -3004,8 +3155,10 @@ static void task_query_data_available( struct task_header *task ) */ BOOL WINAPI WinHttpQueryDataAvailable( HINTERNET hrequest, LPDWORD available ) { - BOOL ret; + DWORD ret; struct request *request; + BOOL async; + BOOL wont_block = FALSE; TRACE("%p, %p\n", hrequest, available); @@ -3021,41 +3174,89 @@ BOOL WINAPI WinHttpQueryDataAvailable( HINTERNET hrequest, LPDWORD available ) return FALSE; } - if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC) + if (!(async = request->connect->hdr.flags & WINHTTP_FLAG_ASYNC) || skip_async_queue( request, &wont_block, 1 )) + { + ret = query_data_available( request, available, async ); + } + else if (wont_block) + { + /* Data available but recursion limit reached, only queue callback. */ + struct send_callback *s; + + if (!(s = malloc( sizeof(*s) ))) + { + release_object( &request->hdr ); + SetLastError( ERROR_OUTOFMEMORY ); + return FALSE; + } + + if (!(ret = query_data_available( request, &s->count, FALSE ))) + { + if (available) *available = s->count; + s->status = WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE; + s->info = &s->count; + s->buflen = sizeof(s->count); + } + else + { + s->result.dwResult = API_QUERY_DATA_AVAILABLE; + s->result.dwError = ret; + s->status = WINHTTP_CALLBACK_STATUS_REQUEST_ERROR; + s->info = &s->result; + s->buflen = sizeof(s->result); + } + + if ((ret = queue_task( &request->queue, task_send_callback, &s->task_hdr, &request->hdr ))) + free( s ); + else + ret = ERROR_IO_PENDING; + } + else { struct query_data *q; - if (!(q = heap_alloc( sizeof(struct query_data) ))) return FALSE; - q->hdr.request = request; - q->hdr.proc = task_query_data_available; - q->available = available; + if (!(q = malloc( sizeof(*q) ))) + { + release_object( &request->hdr ); + SetLastError( ERROR_OUTOFMEMORY ); + return FALSE; + } - addref_object( &request->hdr ); - ret = queue_task( (struct task_header *)q ); + q->available = available; + + if ((ret = queue_task( &request->queue, task_query_data_available, &q->task_hdr, &request->hdr ))) + free( q ); + else + ret = ERROR_IO_PENDING; } - else - ret = query_data_available( request, available, FALSE ); release_object( &request->hdr ); - if (ret) SetLastError( ERROR_SUCCESS ); - return ret; + SetLastError( ret ); + return !ret || ret == ERROR_IO_PENDING; } -static void task_read_data( struct task_header *task ) +static void task_read_data( void *ctx, BOOL abort ) { - struct read_data *r = (struct read_data *)task; - read_data( r->hdr.request, r->buffer, r->to_read, r->read, TRUE ); + struct read_data *r = ctx; + struct request *request = (struct request *)r->task_hdr.obj; + + if (abort) return; + + TRACE("running %p\n", ctx); + read_data( request, r->buffer, r->to_read, r->read, TRUE ); } /*********************************************************************** * WinHttpReadData (winhttp.@) */ -BOOL WINAPI WinHttpReadData( HINTERNET hrequest, LPVOID buffer, DWORD to_read, LPDWORD read ) +BOOL WINAPI WinHttpReadData( HINTERNET hrequest, void *buffer, DWORD to_read, DWORD *read ) { - BOOL ret; + DWORD ret; struct request *request; + BOOL async; + BOOL wont_block = FALSE; - TRACE("%p, %p, %d, %p\n", hrequest, buffer, to_read, read); + TRACE( "%p, %p, %lu, %p\n", hrequest, buffer, to_read, read ); if (!(request = (struct request *)grab_object( hrequest ))) { @@ -3069,65 +3270,110 @@ BOOL WINAPI WinHttpReadData( HINTERNET hrequest, LPVOID buffer, DWORD to_read, L return FALSE; } - if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC) + if (!(async = request->connect->hdr.flags & WINHTTP_FLAG_ASYNC) || skip_async_queue( request, &wont_block, to_read )) + { + ret = read_data( request, buffer, to_read, read, async ); + } + else if (wont_block) + { + /* Data available but recursion limit reached, only queue callback. */ + struct send_callback *s; + + if (!(s = malloc( sizeof(*s) ))) + { + release_object( &request->hdr ); + SetLastError( ERROR_OUTOFMEMORY ); + return FALSE; + } + + if (!(ret = read_data( request, buffer, to_read, &s->count, FALSE ))) + { + if (read) *read = s->count; + s->status = WINHTTP_CALLBACK_STATUS_READ_COMPLETE; + s->info = buffer; + s->buflen = s->count; + } + else + { + s->result.dwResult = API_READ_DATA; + s->result.dwError = ret; + s->status = WINHTTP_CALLBACK_STATUS_REQUEST_ERROR; + s->info = &s->result; + s->buflen = sizeof(s->result); + } + + if ((ret = queue_task( &request->queue, task_send_callback, &s->task_hdr, &request->hdr ))) + free( s ); + else + ret = ERROR_IO_PENDING; + } + else { struct read_data *r; - if (!(r = heap_alloc( sizeof(struct read_data) ))) return FALSE; - r->hdr.request = request; - r->hdr.proc = task_read_data; - r->buffer = buffer; - r->to_read = to_read; - r->read = read; + if (!(r = malloc( sizeof(*r) ))) + { + release_object( &request->hdr ); + SetLastError( ERROR_OUTOFMEMORY ); + return FALSE; + } + r->buffer = buffer; + r->to_read = to_read; + r->read = read; - addref_object( &request->hdr ); - ret = queue_task( (struct task_header *)r ); + if ((ret = queue_task( &request->queue, task_read_data, &r->task_hdr, &request->hdr ))) + free( r ); + else + ret = ERROR_IO_PENDING; } - else - ret = read_data( request, buffer, to_read, read, FALSE ); release_object( &request->hdr ); - if (ret) SetLastError( ERROR_SUCCESS ); - return ret; + SetLastError( ret ); + return !ret || ret == ERROR_IO_PENDING; } -static BOOL write_data( struct request *request, const void *buffer, DWORD to_write, DWORD *written, BOOL async ) +static DWORD write_data( struct request *request, const void *buffer, DWORD to_write, DWORD *written, BOOL async ) { - BOOL ret; + DWORD ret; int num_bytes; - ret = netconn_send( request->netconn, buffer, to_write, &num_bytes ); + ret = netconn_send( request->netconn, buffer, to_write, &num_bytes, NULL ); if (async) { - if (ret) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE, &num_bytes, sizeof(num_bytes) ); + if (!ret) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE, &num_bytes, sizeof(num_bytes) ); else { WINHTTP_ASYNC_RESULT result; result.dwResult = API_WRITE_DATA; - result.dwError = GetLastError(); + result.dwError = ret; send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &result, sizeof(result) ); } } - if (ret && written) *written = num_bytes; + if (!ret && written) *written = num_bytes; return ret; } -static void task_write_data( struct task_header *task ) +static void task_write_data( void *ctx, BOOL abort ) { - struct write_data *w = (struct write_data *)task; - write_data( w->hdr.request, w->buffer, w->to_write, w->written, TRUE ); + struct write_data *w = ctx; + struct request *request = (struct request *)w->task_hdr.obj; + + if (abort) return; + + TRACE("running %p\n", ctx); + write_data( request, w->buffer, w->to_write, w->written, TRUE ); } /*********************************************************************** * WinHttpWriteData (winhttp.@) */ -BOOL WINAPI WinHttpWriteData( HINTERNET hrequest, LPCVOID buffer, DWORD to_write, LPDWORD written ) +BOOL WINAPI WinHttpWriteData( HINTERNET hrequest, const void *buffer, DWORD to_write, DWORD *written ) { - BOOL ret; + DWORD ret; struct request *request; - TRACE("%p, %p, %d, %p\n", hrequest, buffer, to_write, written); + TRACE( "%p, %p, %lu, %p\n", hrequest, buffer, to_write, written ); if (!(request = (struct request *)grab_object( hrequest ))) { @@ -3145,21 +3391,1206 @@ BOOL WINAPI WinHttpWriteData( HINTERNET hrequest, LPCVOID buffer, DWORD to_write { struct write_data *w; - if (!(w = heap_alloc( sizeof(struct write_data) ))) return FALSE; - w->hdr.request = request; - w->hdr.proc = task_write_data; - w->buffer = buffer; - w->to_write = to_write; - w->written = written; + if (!(w = malloc( sizeof(*w) ))) + { + release_object( &request->hdr ); + SetLastError( ERROR_OUTOFMEMORY ); + return FALSE; + } + w->buffer = buffer; + w->to_write = to_write; + w->written = written; - addref_object( &request->hdr ); - ret = queue_task( (struct task_header *)w ); + if ((ret = queue_task( &request->queue, task_write_data, &w->task_hdr, &request->hdr ))) + free( w ); } - else - ret = write_data( request, buffer, to_write, written, FALSE ); + else ret = write_data( request, buffer, to_write, written, FALSE ); release_object( &request->hdr ); - if (ret) SetLastError( ERROR_SUCCESS ); + SetLastError( ret ); + return !ret; +} + +static void socket_handle_closing( struct object_header *hdr ) +{ + struct socket *socket = (struct socket *)hdr; + BOOL pending_tasks; + + pending_tasks = cancel_queue( &socket->send_q ); + pending_tasks = cancel_queue( &socket->recv_q ) || pending_tasks; + + if (pending_tasks) + netconn_cancel_io( socket->netconn ); +} + +static BOOL socket_query_option( struct object_header *hdr, DWORD option, void *buffer, DWORD *buflen ) +{ + switch (option) + { + case WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL: + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + FIXME( "unimplemented option %lu\n", option ); + SetLastError( ERROR_WINHTTP_INVALID_OPTION ); + return FALSE; +} + +static void socket_destroy( struct object_header *hdr ) +{ + struct socket *socket = (struct socket *)hdr; + + TRACE("%p\n", socket); + + stop_queue( &socket->send_q ); + stop_queue( &socket->recv_q ); + + netconn_release( socket->netconn ); + free( socket->read_buffer ); + free( socket->send_frame_buffer ); + free( socket ); +} + +static BOOL socket_set_option( struct object_header *hdr, DWORD option, void *buffer, DWORD buflen ) +{ + struct socket *socket = (struct socket *)hdr; + + switch (option) + { + case WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL: + { + DWORD interval; + + if (buflen != sizeof(DWORD) || (interval = *(DWORD *)buffer) < 15000) + { + WARN( "Invalid parameters for WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL.\n" ); + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + socket->keepalive_interval = interval; + netconn_set_timeout( socket->netconn, FALSE, socket->keepalive_interval ); + SetLastError( ERROR_SUCCESS ); + TRACE( "WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL %lu.\n", interval); + return TRUE; + } + } + + FIXME( "unimplemented option %lu\n", option ); + SetLastError( ERROR_WINHTTP_INVALID_OPTION ); + return FALSE; +} + +static const struct object_vtbl socket_vtbl = +{ + socket_handle_closing, + socket_destroy, + socket_query_option, + socket_set_option, +}; + +HINTERNET WINAPI WinHttpWebSocketCompleteUpgrade( HINTERNET hrequest, DWORD_PTR context ) +{ + struct socket *socket; + struct request *request; + HINTERNET hsocket = NULL; + + TRACE( "%p, %Ix\n", hrequest, context ); + + if (!(request = (struct request *)grab_object( hrequest ))) + { + SetLastError( ERROR_INVALID_HANDLE ); + return NULL; + } + if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST) + { + release_object( &request->hdr ); + SetLastError( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE ); + return NULL; + } + if (!(socket = calloc( 1, sizeof(*socket) ))) + { + release_object( &request->hdr ); + return NULL; + } + socket->hdr.type = WINHTTP_HANDLE_TYPE_SOCKET; + socket->hdr.vtbl = &socket_vtbl; + socket->hdr.refs = 1; + socket->hdr.callback = request->hdr.callback; + socket->hdr.notify_mask = request->hdr.notify_mask; + socket->hdr.context = context; + socket->hdr.flags = request->connect->hdr.flags & WINHTTP_FLAG_ASYNC; + socket->keepalive_interval = 30000; + socket->send_buffer_size = request->websocket_send_buffer_size; + if (request->read_size) + { + if (!(socket->read_buffer = malloc( request->read_size ))) + { + ERR( "No memory.\n" ); + free( socket ); + release_object( &request->hdr ); + return NULL; + } + socket->bytes_in_read_buffer = request->read_size; + memcpy( socket->read_buffer, request->read_buf + request->read_pos, request->read_size ); + request->read_pos = request->read_size = 0; + } + InitializeSRWLock( &socket->send_lock ); + init_queue( &socket->send_q ); + init_queue( &socket->recv_q ); + netconn_addref( request->netconn ); + socket->netconn = request->netconn; + + netconn_set_timeout( socket->netconn, FALSE, socket->keepalive_interval ); + + if ((hsocket = alloc_handle( &socket->hdr ))) + { + send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, &hsocket, sizeof(hsocket) ); + } + + release_object( &socket->hdr ); + release_object( &request->hdr ); + TRACE("returning %p\n", hsocket); + if (hsocket) SetLastError( ERROR_SUCCESS ); + return hsocket; +} + +static DWORD send_bytes( struct socket *socket, char *bytes, int len, int *sent, WSAOVERLAPPED *ovr ) +{ + int count; + DWORD err; + err = netconn_send( socket->netconn, bytes, len, &count, ovr ); + if (sent) *sent = count; + if (err) return err; + return (count == len || (ovr && count)) ? ERROR_SUCCESS : ERROR_INTERNAL_ERROR; +} + +#define FIN_BIT (1 << 7) +#define MASK_BIT (1 << 7) +#define RESERVED_BIT (7 << 4) +#define CONTROL_BIT (1 << 3) + +static DWORD send_frame( struct socket *socket, enum socket_opcode opcode, USHORT status, const char *buf, + DWORD buflen, BOOL final, WSAOVERLAPPED *ovr ) +{ + DWORD i, offset = 2, len = buflen, buffer_size, ret = 0; + int sent_size; + char hdr[14]; + char *ptr; + + TRACE( "sending %02x frame, len %lu\n", opcode, len ); + + if (opcode == SOCKET_OPCODE_CLOSE) len += sizeof(status); + + hdr[0] = final ? (char)FIN_BIT : 0; + hdr[0] |= opcode; + hdr[1] = (char)MASK_BIT; + if (len < 126) hdr[1] |= len; + else if (len < 65536) + { + hdr[1] |= 126; + hdr[2] = len >> 8; + hdr[3] = len & 0xff; + offset += 2; + } + else + { + hdr[1] |= 127; + hdr[2] = hdr[3] = hdr[4] = hdr[5] = 0; + hdr[6] = len >> 24; + hdr[7] = (len >> 16) & 0xff; + hdr[8] = (len >> 8) & 0xff; + hdr[9] = len & 0xff; + offset += 8; + } + + buffer_size = len + offset + 4; + assert( buffer_size - len < socket->send_buffer_size ); + if (buffer_size > socket->send_frame_buffer_size && socket->send_frame_buffer_size < socket->send_buffer_size) + { + DWORD new_size; + void *new; + + new_size = min( buffer_size, socket->send_buffer_size ); + if (!(new = realloc( socket->send_frame_buffer, new_size ))) + { + ERR( "out of memory, buffer_size %lu\n", buffer_size); + return ERROR_OUTOFMEMORY; + } + socket->send_frame_buffer = new; + socket->send_frame_buffer_size = new_size; + } + ptr = socket->send_frame_buffer; + + memcpy(ptr, hdr, offset); + ptr += offset; + + RtlGenRandom( socket->mask, 4 ); + memcpy( ptr, socket->mask, 4 ); + ptr += 4; + socket->mask_index = 0; + + if (opcode == SOCKET_OPCODE_CLOSE) /* prepend status code */ + { + *ptr++ = (status >> 8) ^ socket->mask[socket->mask_index++ % 4]; + *ptr++ = (status & 0xff) ^ socket->mask[socket->mask_index++ % 4]; + } + + offset = ptr - socket->send_frame_buffer; + socket->send_remaining_size = offset + buflen; + socket->client_buffer_offset = 0; + while (socket->send_remaining_size) + { + len = min( buflen, socket->send_buffer_size - offset ); + for (i = 0; i < len; ++i) + { + socket->send_frame_buffer[offset++] = buf[socket->client_buffer_offset++] + ^ socket->mask[socket->mask_index++ % 4]; + } + + sent_size = 0; + ret = send_bytes( socket, socket->send_frame_buffer, offset, &sent_size, ovr ); + socket->send_remaining_size -= sent_size; + if (ret) + { + if (ovr && ret == WSA_IO_PENDING) + { + memmove( socket->send_frame_buffer, socket->send_frame_buffer + sent_size, offset - sent_size ); + socket->bytes_in_send_frame_buffer = offset - sent_size; + } + return ret; + } + assert( sent_size == offset ); + offset = 0; + buflen -= len; + } + return ERROR_SUCCESS; +} + +static DWORD complete_send_frame( struct socket *socket, WSAOVERLAPPED *ovr, const char *buf ) +{ + DWORD ret, len, i; + + if (!netconn_wait_overlapped_result( socket->netconn, ovr, &len )) + return WSAGetLastError(); + + if (socket->bytes_in_send_frame_buffer) + { + ret = send_bytes( socket, socket->send_frame_buffer, socket->bytes_in_send_frame_buffer, NULL, NULL ); + if (ret) return ret; + } + + assert( socket->bytes_in_send_frame_buffer <= socket->send_remaining_size ); + socket->send_remaining_size -= socket->bytes_in_send_frame_buffer; + + while (socket->send_remaining_size) + { + len = min( socket->send_remaining_size, socket->send_buffer_size ); + for (i = 0; i < len; ++i) + { + socket->send_frame_buffer[i] = buf[socket->client_buffer_offset++] + ^ socket->mask[socket->mask_index++ % 4]; + } + ret = send_bytes( socket, socket->send_frame_buffer, len, NULL, NULL ); + if (ret) return ret; + socket->send_remaining_size -= len; + } + return ERROR_SUCCESS; +} + +static void send_io_complete( struct object_header *hdr ) +{ + LONG count = InterlockedDecrement( &hdr->pending_sends ); + assert( count >= 0 ); +} + +/* returns FALSE if sending callback should be omitted. */ +static void receive_io_complete( struct socket *socket ) +{ + LONG count = InterlockedDecrement( &socket->hdr.pending_receives ); + assert( count >= 0 ); +} + +static BOOL socket_can_send( struct socket *socket ) +{ + return socket->state == SOCKET_STATE_OPEN && !socket->close_frame_received; +} + +static BOOL socket_can_receive( struct socket *socket ) +{ + return socket->state <= SOCKET_STATE_SHUTDOWN && !socket->close_frame_received; +} + +static BOOL validate_buffer_type( WINHTTP_WEB_SOCKET_BUFFER_TYPE type, enum fragment_type current_fragment ) +{ + switch (current_fragment) + { + case SOCKET_FRAGMENT_NONE: + return type == WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE + || type == WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE + || type == WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE + || type == WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE; + case SOCKET_FRAGMENT_BINARY: + return type == WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE + || type == WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE; + case SOCKET_FRAGMENT_UTF8: + return type == WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE + || type == WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE; + } + assert( 0 ); + return FALSE; +} + +static enum socket_opcode map_buffer_type( struct socket *socket, WINHTTP_WEB_SOCKET_BUFFER_TYPE type ) +{ + switch (type) + { + case WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE: + if (socket->sending_fragment_type) + { + socket->sending_fragment_type = SOCKET_FRAGMENT_NONE; + return SOCKET_OPCODE_CONTINUE; + } + return SOCKET_OPCODE_TEXT; + + case WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE: + if (socket->sending_fragment_type) + { + socket->sending_fragment_type = SOCKET_FRAGMENT_NONE; + return SOCKET_OPCODE_CONTINUE; + } + return SOCKET_OPCODE_BINARY; + + case WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE: + if (!socket->sending_fragment_type) + { + socket->sending_fragment_type = SOCKET_FRAGMENT_UTF8; + return SOCKET_OPCODE_TEXT; + } + return SOCKET_OPCODE_CONTINUE; + + case WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE: + if (!socket->sending_fragment_type) + { + socket->sending_fragment_type = SOCKET_FRAGMENT_BINARY; + return SOCKET_OPCODE_BINARY; + } + return SOCKET_OPCODE_CONTINUE; + + case WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE: + return SOCKET_OPCODE_CLOSE; + + default: + FIXME("buffer type %u not supported\n", type); + return SOCKET_OPCODE_INVALID; + } +} + +static void socket_send_complete( struct socket *socket, DWORD ret, WINHTTP_WEB_SOCKET_BUFFER_TYPE type, DWORD len ) +{ + if (!ret) + { + WINHTTP_WEB_SOCKET_STATUS status; + status.dwBytesTransferred = len; + status.eBufferType = type; + send_callback( &socket->hdr, WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE, &status, sizeof(status) ); + } + else + { + WINHTTP_WEB_SOCKET_ASYNC_RESULT result; + result.AsyncResult.dwResult = API_WRITE_DATA; + result.AsyncResult.dwError = ret; + result.Operation = WINHTTP_WEB_SOCKET_SEND_OPERATION; + send_callback( &socket->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &result, sizeof(result) ); + } +} + +static DWORD socket_send( struct socket *socket, WINHTTP_WEB_SOCKET_BUFFER_TYPE type, const void *buf, DWORD len, + WSAOVERLAPPED *ovr ) +{ + enum socket_opcode opcode = map_buffer_type( socket, type ); + BOOL final = (type != WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE && + type != WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE); + + return send_frame( socket, opcode, 0, buf, len, final, ovr ); +} + +static void task_socket_send( void *ctx, BOOL abort ) +{ + struct socket_send *s = ctx; + struct socket *socket = (struct socket *)s->task_hdr.obj; + DWORD ret; + + if (abort) return; + + TRACE("running %p\n", ctx); + + if (s->complete_async) ret = complete_send_frame( socket, &s->ovr, s->buf ); + else ret = socket_send( socket, s->type, s->buf, s->len, NULL ); + + send_io_complete( &socket->hdr ); + InterlockedExchange( &socket->pending_noncontrol_send, 0 ); + socket_send_complete( socket, ret, s->type, s->len ); +} + +DWORD WINAPI WinHttpWebSocketSend( HINTERNET hsocket, WINHTTP_WEB_SOCKET_BUFFER_TYPE type, void *buf, DWORD len ) +{ + struct socket *socket; + DWORD ret = 0; + + TRACE( "%p, %u, %p, %lu\n", hsocket, type, buf, len ); + + if (len && !buf) return ERROR_INVALID_PARAMETER; + + if (!(socket = (struct socket *)grab_object( hsocket ))) return ERROR_INVALID_HANDLE; + if (socket->hdr.type != WINHTTP_HANDLE_TYPE_SOCKET) + { + release_object( &socket->hdr ); + return ERROR_WINHTTP_INCORRECT_HANDLE_TYPE; + } + if (!socket_can_send( socket )) + { + release_object( &socket->hdr ); + return ERROR_INVALID_OPERATION; + } + + if (socket->hdr.flags & WINHTTP_FLAG_ASYNC) + { + BOOL async_send, complete_async = FALSE; + struct socket_send *s; + + if (InterlockedCompareExchange( &socket->pending_noncontrol_send, 1, 0 )) + { + WARN( "Previous send is still queued.\n" ); + release_object( &socket->hdr ); + return ERROR_INVALID_OPERATION; + } + if (!validate_buffer_type( type, socket->sending_fragment_type )) + { + WARN( "Invalid buffer type %u, sending_fragment_type %u.\n", type, socket->sending_fragment_type ); + InterlockedExchange( &socket->pending_noncontrol_send, 0 ); + release_object( &socket->hdr ); + return ERROR_INVALID_PARAMETER; + } + + if (!(s = malloc( sizeof(*s) ))) + { + InterlockedExchange( &socket->pending_noncontrol_send, 0 ); + release_object( &socket->hdr ); + return ERROR_OUTOFMEMORY; + } + + AcquireSRWLockExclusive( &socket->send_lock ); + async_send = InterlockedIncrement( &socket->hdr.pending_sends ) > 1 || socket->hdr.recursion_count >= 3; + if (!async_send) + { + memset( &s->ovr, 0, sizeof(s->ovr) ); + if ((ret = socket_send( socket, type, buf, len, &s->ovr )) == WSA_IO_PENDING) + { + async_send = TRUE; + complete_async = TRUE; + } + } + + if (async_send) + { + s->complete_async = complete_async; + TRACE("queueing, complete_async %#x.\n", complete_async); + s->type = type; + s->buf = buf; + s->len = len; + + if ((ret = queue_task( &socket->send_q, task_socket_send, &s->task_hdr, &socket->hdr ))) + free( s ); + } + if (!async_send || ret) + { + InterlockedDecrement( &socket->hdr.pending_sends ); + InterlockedExchange( &socket->pending_noncontrol_send, 0 ); + } + ReleaseSRWLockExclusive( &socket->send_lock ); + if (!async_send) + { + TRACE("sent sync.\n"); + free( s ); + socket_send_complete( socket, ret, type, len ); + ret = ERROR_SUCCESS; + } + } + else + { + if (validate_buffer_type( type, socket->sending_fragment_type )) + { + ret = socket_send( socket, type, buf, len, NULL ); + } + else + { + WARN( "Invalid buffer type %u, sending_fragment_type %u.\n", type, socket->sending_fragment_type ); + ret = ERROR_INVALID_PARAMETER; + } + } + + release_object( &socket->hdr ); + return ret; +} + +static DWORD receive_bytes( struct socket *socket, char *buf, DWORD len, DWORD *ret_len, BOOL read_full_buffer ) +{ + DWORD err, size = 0, needed = len; + char *ptr = buf; + int received; + + if (socket->bytes_in_read_buffer) + { + size = min( needed, socket->bytes_in_read_buffer ); + memcpy( ptr, socket->read_buffer, size ); + memmove( socket->read_buffer, socket->read_buffer + size, socket->bytes_in_read_buffer - size ); + socket->bytes_in_read_buffer -= size; + needed -= size; + ptr += size; + } + while (size != len) + { + if ((err = netconn_recv( socket->netconn, ptr, needed, 0, &received ))) return err; + if (!received) break; + size += received; + if (!read_full_buffer) break; + needed -= received; + ptr += received; + } + *ret_len = size; + if (size != len && (read_full_buffer || !size)) return ERROR_WINHTTP_INVALID_SERVER_RESPONSE; + return ERROR_SUCCESS; +} + +static BOOL is_supported_opcode( enum socket_opcode opcode ) +{ + switch (opcode) + { + case SOCKET_OPCODE_CONTINUE: + case SOCKET_OPCODE_TEXT: + case SOCKET_OPCODE_BINARY: + case SOCKET_OPCODE_CLOSE: + case SOCKET_OPCODE_PING: + case SOCKET_OPCODE_PONG: + return TRUE; + default: + FIXME( "opcode %02x not handled\n", opcode ); + return FALSE; + } +} + +static DWORD receive_frame( struct socket *socket, DWORD *ret_len, enum socket_opcode *opcode, BOOL *final ) +{ + DWORD ret, len, count; + char hdr[2]; + + if ((ret = receive_bytes( socket, hdr, sizeof(hdr), &count, TRUE ))) return ret; + if ((hdr[0] & RESERVED_BIT) || (hdr[1] & MASK_BIT) || !is_supported_opcode( hdr[0] & 0xf )) + { + return ERROR_WINHTTP_INVALID_SERVER_RESPONSE; + } + *opcode = hdr[0] & 0xf; + *final = hdr[0] & FIN_BIT; + TRACE("received %02x frame, final %#x\n", *opcode, *final); + + len = hdr[1] & ~MASK_BIT; + if (len == 126) + { + USHORT len16; + if ((ret = receive_bytes( socket, (char *)&len16, sizeof(len16), &count, TRUE ))) return ret; + len = RtlUshortByteSwap( len16 ); + } + else if (len == 127) + { + ULONGLONG len64; + if ((ret = receive_bytes( socket, (char *)&len64, sizeof(len64), &count, TRUE ))) return ret; + if ((len64 = RtlUlonglongByteSwap( len64 )) > ~0u) return ERROR_NOT_SUPPORTED; + len = len64; + } + + *ret_len = len; + return ERROR_SUCCESS; +} + +static void task_socket_send_pong( void *ctx, BOOL abort ) +{ + struct socket_send *s = ctx; + struct socket *socket = (struct socket *)s->task_hdr.obj; + + if (abort) return; + + TRACE("running %p\n", ctx); + + if (s->complete_async) complete_send_frame( socket, &s->ovr, NULL ); + else send_frame( socket, SOCKET_OPCODE_PONG, 0, NULL, 0, TRUE, NULL ); + + send_io_complete( &socket->hdr ); +} + +static DWORD socket_send_pong( struct socket *socket ) +{ + if (socket->hdr.flags & WINHTTP_FLAG_ASYNC) + { + BOOL async_send, complete_async = FALSE; + struct socket_send *s; + DWORD ret = 0; + + if (!(s = malloc( sizeof(*s) ))) return ERROR_OUTOFMEMORY; + + AcquireSRWLockExclusive( &socket->send_lock ); + async_send = InterlockedIncrement( &socket->hdr.pending_sends ) > 1; + if (!async_send) + { + memset( &s->ovr, 0, sizeof(s->ovr) ); + if ((ret = send_frame( socket, SOCKET_OPCODE_PONG, 0, NULL, 0, TRUE, &s->ovr )) == WSA_IO_PENDING) + { + async_send = TRUE; + complete_async = TRUE; + } + } + + if (async_send) + { + s->complete_async = complete_async; + if ((ret = queue_task( &socket->send_q, task_socket_send_pong, &s->task_hdr, &socket->hdr ))) + { + InterlockedDecrement( &socket->hdr.pending_sends ); + free( s ); + } + } + else + { + InterlockedDecrement( &socket->hdr.pending_sends ); + free( s ); + } + ReleaseSRWLockExclusive( &socket->send_lock ); + return ret; + } + return send_frame( socket, SOCKET_OPCODE_PONG, 0, NULL, 0, TRUE, NULL ); +} + +static DWORD socket_drain( struct socket *socket ) +{ + DWORD ret, count; + + while (socket->read_size) + { + char buf[1024]; + if ((ret = receive_bytes( socket, buf, min(socket->read_size, sizeof(buf)), &count, TRUE ))) return ret; + socket->read_size -= count; + } + return ERROR_SUCCESS; +} + +static DWORD receive_close_status( struct socket *socket, DWORD len ) +{ + DWORD reason_len, ret; + + socket->close_frame_received = TRUE; + if ((len && (len < sizeof(socket->status) || len > sizeof(socket->status) + sizeof(socket->reason)))) + return (socket->close_frame_receive_err = ERROR_WINHTTP_INVALID_SERVER_RESPONSE); + + if (!len) return (socket->close_frame_receive_err = ERROR_SUCCESS); + + reason_len = len - sizeof(socket->status); + if ((ret = receive_bytes( socket, (char *)&socket->status, sizeof(socket->status), &len, TRUE ))) + return (socket->close_frame_receive_err = ret); + socket->status = RtlUshortByteSwap( socket->status ); + return (socket->close_frame_receive_err + = receive_bytes( socket, socket->reason, reason_len, &socket->reason_len, TRUE )); +} + +static DWORD handle_control_frame( struct socket *socket ) +{ + DWORD ret; + + TRACE( "opcode %u.\n", socket->opcode ); + + switch (socket->opcode) + { + case SOCKET_OPCODE_PING: + return socket_send_pong( socket ); + + case SOCKET_OPCODE_PONG: + return socket_drain( socket ); + + case SOCKET_OPCODE_CLOSE: + if (socket->state < SOCKET_STATE_SHUTDOWN) + WARN( "SOCKET_OPCODE_CLOSE received, socket->state %u.\n", socket->state ); + if (socket->close_frame_received) + { + FIXME( "Close frame already received.\n" ); + return ERROR_WINHTTP_INVALID_SERVER_RESPONSE; + } + + ret = receive_close_status( socket, socket->read_size ); + socket->read_size = 0; + return ret; + + default: + ERR("unhandled control opcode %02x\n", socket->opcode); + return ERROR_WINHTTP_INVALID_SERVER_RESPONSE; + } + + return ERROR_SUCCESS; +} + +static WINHTTP_WEB_SOCKET_BUFFER_TYPE map_opcode( struct socket *socket, enum socket_opcode opcode, BOOL fragment ) +{ + enum fragment_type frag_type = socket->receiving_fragment_type; + + switch (opcode) + { + case SOCKET_OPCODE_TEXT: + if (frag_type && frag_type != SOCKET_FRAGMENT_UTF8) + FIXME( "Received SOCKET_OPCODE_TEXT with prev fragment %u.\n", frag_type ); + if (fragment) + { + socket->receiving_fragment_type = SOCKET_FRAGMENT_UTF8; + return WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE; + } + socket->receiving_fragment_type = SOCKET_FRAGMENT_NONE; + return WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE; + + case SOCKET_OPCODE_BINARY: + if (frag_type && frag_type != SOCKET_FRAGMENT_BINARY) + FIXME( "Received SOCKET_OPCODE_BINARY with prev fragment %u.\n", frag_type ); + if (fragment) + { + socket->receiving_fragment_type = SOCKET_FRAGMENT_BINARY; + return WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE; + } + socket->receiving_fragment_type = SOCKET_FRAGMENT_NONE; + return WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE; + + case SOCKET_OPCODE_CONTINUE: + if (!frag_type) + { + FIXME( "Received SOCKET_OPCODE_CONTINUE without starting fragment.\n" ); + return ~0u; + } + if (fragment) + { + return frag_type == SOCKET_FRAGMENT_BINARY ? WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE + : WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE; + } + socket->receiving_fragment_type = SOCKET_FRAGMENT_NONE; + return frag_type == SOCKET_FRAGMENT_BINARY ? WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE + : WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE; + + case SOCKET_OPCODE_CLOSE: + return WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE; + + default: + FIXME("opcode %02x not handled\n", opcode); + return ~0u; + } +} + +static DWORD socket_receive( struct socket *socket, void *buf, DWORD len, DWORD *ret_len, + WINHTTP_WEB_SOCKET_BUFFER_TYPE *ret_type ) +{ + BOOL final = socket->last_receive_final; + DWORD count, ret = ERROR_SUCCESS; + + if (!socket->read_size) + { + for (;;) + { + if (!(ret = receive_frame( socket, &socket->read_size, &socket->opcode, &final ))) + { + if (!(socket->opcode & CONTROL_BIT) || (ret = handle_control_frame( socket )) + || socket->opcode == SOCKET_OPCODE_CLOSE) break; + } + else if (ret == WSAETIMEDOUT) ret = socket_send_pong( socket ); + if (ret) break; + } + } + if (!ret) + { + socket->last_receive_final = final; + ret = receive_bytes( socket, buf, min(len, socket->read_size), &count, FALSE ); + } + if (!ret) + { + if (count < socket->read_size) + WARN("Short read.\n"); + + socket->read_size -= count; + *ret_len = count; + *ret_type = map_opcode( socket, socket->opcode, !final || socket->read_size != 0 ); + TRACE( "len %lu, *ret_len %lu, *ret_type %u.\n", len, *ret_len, *ret_type ); + if (*ret_type == ~0u) + { + FIXME( "Unexpected opcode %u.\n", socket->opcode ); + socket->read_size = 0; + return ERROR_WINHTTP_INVALID_SERVER_RESPONSE; + } + } + return ret; +} + +static void socket_receive_complete( struct socket *socket, DWORD ret, WINHTTP_WEB_SOCKET_BUFFER_TYPE type, DWORD len ) +{ + if (!ret) + { + WINHTTP_WEB_SOCKET_STATUS status; + status.dwBytesTransferred = len; + status.eBufferType = type; + send_callback( &socket->hdr, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, &status, sizeof(status) ); + } + else + { + WINHTTP_WEB_SOCKET_ASYNC_RESULT result; + result.AsyncResult.dwResult = 0; + result.AsyncResult.dwError = ret; + result.Operation = WINHTTP_WEB_SOCKET_RECEIVE_OPERATION; + send_callback( &socket->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &result, sizeof(result) ); + } +} + +static void task_socket_receive( void *ctx, BOOL abort ) +{ + struct socket_receive *r = ctx; + struct socket *socket = (struct socket *)r->task_hdr.obj; + DWORD ret, count; + WINHTTP_WEB_SOCKET_BUFFER_TYPE type; + + if (abort) + { + socket_receive_complete( socket, ERROR_WINHTTP_OPERATION_CANCELLED, 0, 0 ); + return; + } + + TRACE("running %p\n", ctx); + ret = socket_receive( socket, r->buf, r->len, &count, &type ); + receive_io_complete( socket ); + if (task_needs_completion( &r->task_hdr )) + socket_receive_complete( socket, ret, type, count ); +} + +DWORD WINAPI WinHttpWebSocketReceive( HINTERNET hsocket, void *buf, DWORD len, DWORD *ret_len, + WINHTTP_WEB_SOCKET_BUFFER_TYPE *ret_type ) +{ + struct socket *socket; + DWORD ret; + + TRACE( "%p, %p, %lu, %p, %p\n", hsocket, buf, len, ret_len, ret_type ); + + if (!buf || !len) return ERROR_INVALID_PARAMETER; + + if (!(socket = (struct socket *)grab_object( hsocket ))) return ERROR_INVALID_HANDLE; + if (socket->hdr.type != WINHTTP_HANDLE_TYPE_SOCKET) + { + release_object( &socket->hdr ); + return ERROR_WINHTTP_INCORRECT_HANDLE_TYPE; + } + if (!socket_can_receive( socket )) + { + release_object( &socket->hdr ); + return ERROR_INVALID_OPERATION; + } + + if (socket->hdr.flags & WINHTTP_FLAG_ASYNC) + { + struct socket_receive *r; + + if (InterlockedIncrement( &socket->hdr.pending_receives ) > 1) + { + InterlockedDecrement( &socket->hdr.pending_receives ); + WARN( "Attempt to queue receive while another is pending.\n" ); + release_object( &socket->hdr ); + return ERROR_INVALID_OPERATION; + } + + if (!(r = malloc( sizeof(*r) ))) + { + InterlockedDecrement( &socket->hdr.pending_receives ); + release_object( &socket->hdr ); + return ERROR_OUTOFMEMORY; + } + r->buf = buf; + r->len = len; + + if ((ret = queue_task( &socket->recv_q, task_socket_receive, &r->task_hdr, &socket->hdr ))) + { + InterlockedDecrement( &socket->hdr.pending_receives ); + free( r ); + } + } + else ret = socket_receive( socket, buf, len, ret_len, ret_type ); + + release_object( &socket->hdr ); + return ret; +} + +static void socket_shutdown_complete( struct socket *socket, DWORD ret ) +{ + if (!ret) send_callback( &socket->hdr, WINHTTP_CALLBACK_STATUS_SHUTDOWN_COMPLETE, NULL, 0 ); + else + { + WINHTTP_WEB_SOCKET_ASYNC_RESULT result; + result.AsyncResult.dwResult = API_WRITE_DATA; + result.AsyncResult.dwError = ret; + result.Operation = WINHTTP_WEB_SOCKET_SHUTDOWN_OPERATION; + send_callback( &socket->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &result, sizeof(result) ); + } +} + +static void task_socket_shutdown( void *ctx, BOOL abort ) +{ + struct socket_shutdown *s = ctx; + struct socket *socket = (struct socket *)s->task_hdr.obj; + DWORD ret; + + if (abort) return; + + TRACE("running %p\n", ctx); + + if (s->complete_async) ret = complete_send_frame( socket, &s->ovr, s->reason ); + else ret = send_frame( socket, SOCKET_OPCODE_CLOSE, s->status, s->reason, s->len, TRUE, NULL ); + + send_io_complete( &socket->hdr ); + if (s->send_callback) socket_shutdown_complete( socket, ret ); +} + +static DWORD send_socket_shutdown( struct socket *socket, USHORT status, const void *reason, DWORD len, + BOOL send_callback) +{ + DWORD ret; + + if (socket->state < SOCKET_STATE_SHUTDOWN) socket->state = SOCKET_STATE_SHUTDOWN; + + if (socket->hdr.flags & WINHTTP_FLAG_ASYNC) + { + BOOL async_send, complete_async = FALSE; + struct socket_shutdown *s; + + if (!(s = malloc( sizeof(*s) ))) return FALSE; + + AcquireSRWLockExclusive( &socket->send_lock ); + async_send = InterlockedIncrement( &socket->hdr.pending_sends ) > 1 || socket->hdr.recursion_count >= 3; + if (!async_send) + { + memset( &s->ovr, 0, sizeof(s->ovr) ); + if ((ret = send_frame( socket, SOCKET_OPCODE_CLOSE, status, reason, len, TRUE, &s->ovr )) == WSA_IO_PENDING) + { + async_send = TRUE; + complete_async = TRUE; + } + } + + if (async_send) + { + s->complete_async = complete_async; + s->status = status; + memcpy( s->reason, reason, len ); + s->len = len; + s->send_callback = send_callback; + + if ((ret = queue_task( &socket->send_q, task_socket_shutdown, &s->task_hdr, &socket->hdr ))) + { + InterlockedDecrement( &socket->hdr.pending_sends ); + free( s ); + } + } + else InterlockedDecrement( &socket->hdr.pending_sends ); + ReleaseSRWLockExclusive( &socket->send_lock ); + if (!async_send) + { + free( s ); + if (send_callback) + { + socket_shutdown_complete( socket, ret ); + ret = ERROR_SUCCESS; + } + } + } + else ret = send_frame( socket, SOCKET_OPCODE_CLOSE, status, reason, len, TRUE, NULL ); + + return ret; +} + +DWORD WINAPI WinHttpWebSocketShutdown( HINTERNET hsocket, USHORT status, void *reason, DWORD len ) +{ + struct socket *socket; + DWORD ret; + + TRACE( "%p, %u, %p, %lu\n", hsocket, status, reason, len ); + + if ((len && !reason) || len > sizeof(socket->reason)) return ERROR_INVALID_PARAMETER; + + if (!(socket = (struct socket *)grab_object( hsocket ))) return ERROR_INVALID_HANDLE; + if (socket->hdr.type != WINHTTP_HANDLE_TYPE_SOCKET) + { + release_object( &socket->hdr ); + return ERROR_WINHTTP_INCORRECT_HANDLE_TYPE; + } + if (socket->state >= SOCKET_STATE_SHUTDOWN) + { + release_object( &socket->hdr ); + return ERROR_INVALID_OPERATION; + } + + ret = send_socket_shutdown( socket, status, reason, len, TRUE ); + release_object( &socket->hdr ); + return ret; +} + +static DWORD socket_close( struct socket *socket ) +{ + BOOL final = FALSE; + DWORD ret, count; + + if (socket->close_frame_received) return socket->close_frame_receive_err; + + if ((ret = socket_drain( socket ))) return ret; + + while (1) + { + if ((ret = receive_frame( socket, &count, &socket->opcode, &final ))) return ret; + if (socket->opcode == SOCKET_OPCODE_CLOSE) break; + + socket->read_size = count; + if ((ret = socket_drain( socket ))) return ret; + } + if (!final) + FIXME( "Received close opcode without FIN bit.\n" ); + + return receive_close_status( socket, count ); +} + +static void socket_close_complete( struct socket *socket, DWORD ret ) +{ + if (!ret) send_callback( &socket->hdr, WINHTTP_CALLBACK_STATUS_CLOSE_COMPLETE, NULL, 0 ); + else + { + WINHTTP_WEB_SOCKET_ASYNC_RESULT result; + result.AsyncResult.dwResult = API_READ_DATA; /* FIXME */ + result.AsyncResult.dwError = ret; + result.Operation = WINHTTP_WEB_SOCKET_CLOSE_OPERATION; + send_callback( &socket->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &result, sizeof(result) ); + } +} + +static void task_socket_close( void *ctx, BOOL abort ) +{ + struct socket_shutdown *s = ctx; + struct socket *socket = (struct socket *)s->task_hdr.obj; + DWORD ret; + + if (abort) + { + socket_close_complete( socket, ERROR_WINHTTP_OPERATION_CANCELLED ); + return; + } + + TRACE("running %p\n", ctx); + + ret = socket_close( socket ); + receive_io_complete( socket ); + if (task_needs_completion( &s->task_hdr )) + socket_close_complete( socket, ret ); +} + +DWORD WINAPI WinHttpWebSocketClose( HINTERNET hsocket, USHORT status, void *reason, DWORD len ) +{ + enum socket_state prev_state; + LONG pending_receives = 0; + struct socket *socket; + DWORD ret; + + TRACE( "%p, %u, %p, %lu\n", hsocket, status, reason, len ); + + if ((len && !reason) || len > sizeof(socket->reason)) return ERROR_INVALID_PARAMETER; + + if (!(socket = (struct socket *)grab_object( hsocket ))) return ERROR_INVALID_HANDLE; + if (socket->hdr.type != WINHTTP_HANDLE_TYPE_SOCKET) + { + release_object( &socket->hdr ); + return ERROR_WINHTTP_INCORRECT_HANDLE_TYPE; + } + if (socket->state >= SOCKET_STATE_CLOSED) + { + release_object( &socket->hdr ); + return ERROR_INVALID_OPERATION; + } + + prev_state = socket->state; + socket->state = SOCKET_STATE_CLOSED; + + if (socket->hdr.flags & WINHTTP_FLAG_ASYNC) + { + pending_receives = InterlockedIncrement( &socket->hdr.pending_receives ); + cancel_queue( &socket->recv_q ); + } + + if (prev_state < SOCKET_STATE_SHUTDOWN && (ret = send_socket_shutdown( socket, status, reason, len, FALSE ))) + goto done; + + if (pending_receives == 1 && socket->close_frame_received) + { + if (socket->hdr.flags & WINHTTP_FLAG_ASYNC) + socket_close_complete( socket, socket->close_frame_receive_err ); + goto done; + } + + if (socket->hdr.flags & WINHTTP_FLAG_ASYNC) + { + struct socket_shutdown *s; + + if (!(s = calloc( 1, sizeof(*s) ))) + { + ret = ERROR_OUTOFMEMORY; + goto done; + } + if ((ret = queue_task( &socket->recv_q, task_socket_close, &s->task_hdr, &socket->hdr ))) + { + InterlockedDecrement( &socket->hdr.pending_receives ); + free( s ); + } + } + else ret = socket_close( socket ); + +done: + release_object( &socket->hdr ); + return ret; +} + +DWORD WINAPI WinHttpWebSocketQueryCloseStatus( HINTERNET hsocket, USHORT *status, void *reason, DWORD len, + DWORD *ret_len ) +{ + struct socket *socket; + DWORD ret; + + TRACE( "%p, %p, %p, %lu, %p\n", hsocket, status, reason, len, ret_len ); + + if (!status || (len && !reason) || !ret_len) return ERROR_INVALID_PARAMETER; + + if (!(socket = (struct socket *)grab_object( hsocket ))) return ERROR_INVALID_HANDLE; + if (socket->hdr.type != WINHTTP_HANDLE_TYPE_SOCKET) + { + release_object( &socket->hdr ); + return ERROR_WINHTTP_INCORRECT_HANDLE_TYPE; + } + + if (!socket->close_frame_received || socket->close_frame_receive_err) + { + ret = socket->close_frame_received ? socket->close_frame_receive_err : ERROR_INVALID_OPERATION; + release_object( &socket->hdr ); + return ret; + } + *status = socket->status; + *ret_len = socket->reason_len; + if (socket->reason_len > len) ret = ERROR_INSUFFICIENT_BUFFER; + else + { + memcpy( reason, socket->reason, socket->reason_len ); + ret = ERROR_SUCCESS; + } + + release_object( &socket->hdr ); return ret; } @@ -3183,16 +4614,10 @@ struct winhttp_request HINTERNET hrequest; VARIANT data; WCHAR *verb; -#ifdef __REACTOS__ - HANDLE thread; -#else HANDLE done; -#endif HANDLE wait; HANDLE cancel; -#ifndef __REACTOS__ BOOL proc_running; -#endif char *buffer; DWORD offset; DWORD bytes_available; @@ -3207,6 +4632,7 @@ struct winhttp_request WINHTTP_PROXY_INFO proxy; BOOL async; UINT url_codepage; + DWORD security_flags; }; static inline struct winhttp_request *impl_from_IWinHttpRequest( IWinHttpRequest *iface ) @@ -3226,17 +4652,6 @@ static void cancel_request( struct winhttp_request *request ) { if (request->state <= REQUEST_STATE_CANCELLED) return; -#ifdef __REACTOS__ - SetEvent( request->cancel ); - LeaveCriticalSection( &request->cs ); - WaitForSingleObject( request->thread, INFINITE ); - EnterCriticalSection( &request->cs ); - - request->state = REQUEST_STATE_CANCELLED; - - CloseHandle( request->thread ); - request->thread = NULL; -#else if (request->proc_running) { SetEvent( request->cancel ); @@ -3247,7 +4662,6 @@ static void cancel_request( struct winhttp_request *request ) EnterCriticalSection( &request->cs ); } request->state = REQUEST_STATE_CANCELLED; -#endif } /* critical section must be held */ @@ -3257,17 +4671,13 @@ static void free_request( struct winhttp_request *request ) WinHttpCloseHandle( request->hrequest ); WinHttpCloseHandle( request->hconnect ); WinHttpCloseHandle( request->hsession ); -#ifdef __REACTOS__ - CloseHandle( request->thread ); -#else CloseHandle( request->done ); -#endif CloseHandle( request->wait ); CloseHandle( request->cancel ); - heap_free( (WCHAR *)request->proxy.lpszProxy ); - heap_free( (WCHAR *)request->proxy.lpszProxyBypass ); - heap_free( request->buffer ); - heap_free( request->verb ); + free( request->proxy.lpszProxy ); + free( request->proxy.lpszProxyBypass ); + free( request->buffer ); + free( request->verb ); VariantClear( &request->data ); } @@ -3286,7 +4696,7 @@ static ULONG WINAPI winhttp_request_Release( LeaveCriticalSection( &request->cs ); request->cs.DebugInfo->Spare[0] = 0; DeleteCriticalSection( &request->cs ); - heap_free( request ); + free( request ); } return refs; } @@ -3351,7 +4761,7 @@ static HRESULT get_typeinfo( enum type_id tid, ITypeInfo **ret ) hr = LoadRegTypeLib( &LIBID_WinHttp, 5, 1, LOCALE_SYSTEM_DEFAULT, &typelib ); if (FAILED(hr)) { - ERR("LoadRegTypeLib failed: %08x\n", hr); + ERR( "LoadRegTypeLib failed: %#lx\n", hr ); return hr; } if (InterlockedCompareExchangePointer( (void **)&winhttp_typelib, typelib, NULL )) @@ -3364,7 +4774,7 @@ static HRESULT get_typeinfo( enum type_id tid, ITypeInfo **ret ) hr = ITypeLib_GetTypeInfoOfGuid( winhttp_typelib, winhttp_tid_id[tid], &typeinfo ); if (FAILED(hr)) { - ERR("GetTypeInfoOfGuid(%s) failed: %08x\n", debugstr_guid(winhttp_tid_id[tid]), hr); + ERR( "GetTypeInfoOfGuid(%s) failed: %#lx\n", debugstr_guid(winhttp_tid_id[tid]), hr ); return hr; } if (InterlockedCompareExchangePointer( (void **)(winhttp_typeinfo + tid), typeinfo, NULL )) @@ -3394,7 +4804,7 @@ static HRESULT WINAPI winhttp_request_GetTypeInfo( ITypeInfo **info ) { struct winhttp_request *request = impl_from_IWinHttpRequest( iface ); - TRACE("%p, %u, %u, %p\n", request, index, lcid, info); + TRACE( "%p, %u, %lu, %p\n", request, index, lcid, info ); return get_typeinfo( IWinHttpRequest_tid, info ); } @@ -3411,7 +4821,7 @@ static HRESULT WINAPI winhttp_request_GetIDsOfNames( ITypeInfo *typeinfo; HRESULT hr; - TRACE("%p, %s, %p, %u, %u, %p\n", request, debugstr_guid(riid), names, count, lcid, dispid); + TRACE( "%p, %s, %p, %u, %lu, %p\n", request, debugstr_guid(riid), names, count, lcid, dispid ); if (!names || !count || !dispid) return E_INVALIDARG; @@ -3439,8 +4849,8 @@ static HRESULT WINAPI winhttp_request_Invoke( ITypeInfo *typeinfo; HRESULT hr; - TRACE("%p, %d, %s, %d, %d, %p, %p, %p, %p\n", request, member, debugstr_guid(riid), - lcid, flags, params, result, excep_info, arg_err); + TRACE( "%p, %ld, %s, %lu, %d, %p, %p, %p, %p\n", request, member, debugstr_guid(riid), + lcid, flags, params, result, excep_info, arg_err ); if (!IsEqualIID( riid, &IID_NULL )) return DISP_E_UNKNOWNINTERFACE; @@ -3464,7 +4874,7 @@ static HRESULT WINAPI winhttp_request_Invoke( hr = IWinHttpRequest_put_Option( &request->IWinHttpRequest_iface, V_I4( &option ), params->rgvarg[0] ); if (FAILED(hr)) - WARN("put_Option(%d) failed: %x\n", V_I4( &option ), hr); + WARN( "put_Option(%ld) failed: %#lx\n", V_I4( &option ), hr ); return hr; } else if (flags & (DISPATCH_PROPERTYGET | DISPATCH_METHOD)) @@ -3474,7 +4884,7 @@ static HRESULT WINAPI winhttp_request_Invoke( hr = IWinHttpRequest_get_Option( &request->IWinHttpRequest_iface, V_I4( &option ), result ); if (FAILED(hr)) - WARN("get_Option(%d) failed: %x\n", V_I4( &option ), hr); + WARN( "get_Option(%ld) failed: %#lx\n", V_I4( &option ), hr ); return hr; } @@ -3503,24 +4913,24 @@ static HRESULT WINAPI winhttp_request_SetProxy( struct winhttp_request *request = impl_from_IWinHttpRequest( iface ); DWORD err = ERROR_SUCCESS; - TRACE("%p, %u, %s, %s\n", request, proxy_setting, debugstr_variant(&proxy_server), - debugstr_variant(&bypass_list)); + TRACE( "%p, %lu, %s, %s\n", request, proxy_setting, debugstr_variant(&proxy_server), + debugstr_variant(&bypass_list) ); EnterCriticalSection( &request->cs ); switch (proxy_setting) { case HTTPREQUEST_PROXYSETTING_DEFAULT: request->proxy.dwAccessType = WINHTTP_ACCESS_TYPE_DEFAULT_PROXY; - heap_free( (WCHAR *)request->proxy.lpszProxy ); - heap_free( (WCHAR *)request->proxy.lpszProxyBypass ); + free( request->proxy.lpszProxy ); + free( request->proxy.lpszProxyBypass ); request->proxy.lpszProxy = NULL; request->proxy.lpszProxyBypass = NULL; break; case HTTPREQUEST_PROXYSETTING_DIRECT: request->proxy.dwAccessType = WINHTTP_ACCESS_TYPE_NO_PROXY; - heap_free( (WCHAR *)request->proxy.lpszProxy ); - heap_free( (WCHAR *)request->proxy.lpszProxyBypass ); + free( request->proxy.lpszProxy ); + free( request->proxy.lpszProxyBypass ); request->proxy.lpszProxy = NULL; request->proxy.lpszProxyBypass = NULL; break; @@ -3529,13 +4939,13 @@ static HRESULT WINAPI winhttp_request_SetProxy( request->proxy.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY; if (V_VT( &proxy_server ) == VT_BSTR) { - heap_free( (WCHAR *)request->proxy.lpszProxy ); - request->proxy.lpszProxy = strdupW( V_BSTR( &proxy_server ) ); + free( request->proxy.lpszProxy ); + request->proxy.lpszProxy = wcsdup( V_BSTR( &proxy_server ) ); } if (V_VT( &bypass_list ) == VT_BSTR) { - heap_free( (WCHAR *)request->proxy.lpszProxyBypass ); - request->proxy.lpszProxyBypass = strdupW( V_BSTR( &bypass_list ) ); + free( request->proxy.lpszProxyBypass ); + request->proxy.lpszProxyBypass = wcsdup( V_BSTR( &bypass_list ) ); } break; @@ -3557,7 +4967,7 @@ static HRESULT WINAPI winhttp_request_SetCredentials( DWORD target, scheme = WINHTTP_AUTH_SCHEME_BASIC; /* FIXME: query supported schemes */ DWORD err = ERROR_SUCCESS; - TRACE("%p, %s, %p, 0x%08x\n", request, debugstr_w(username), password, flags); + TRACE( "%p, %s, %p, %#lx\n", request, debugstr_w(username), password, flags ); EnterCriticalSection( &request->cs ); if (request->state < REQUEST_STATE_OPEN) @@ -3590,9 +5000,7 @@ static void initialize_request( struct winhttp_request *request ) { request->wait = CreateEventW( NULL, FALSE, FALSE, NULL ); request->cancel = CreateEventW( NULL, FALSE, FALSE, NULL ); -#ifndef __REACTOS__ request->done = CreateEventW( NULL, FALSE, FALSE, NULL ); -#endif request->connect_timeout = 60000; request->send_timeout = 30000; request->receive_timeout = 30000; @@ -3608,9 +5016,9 @@ static void reset_request( struct winhttp_request *request ) request->hrequest = NULL; WinHttpCloseHandle( request->hconnect ); request->hconnect = NULL; - heap_free( request->buffer ); + free( request->buffer ); request->buffer = NULL; - heap_free( request->verb ); + free( request->verb ); request->verb = NULL; request->offset = 0; request->bytes_available = 0; @@ -3623,9 +5031,9 @@ static void reset_request( struct winhttp_request *request ) request->send_timeout = 30000; request->receive_timeout = 30000; request->url_codepage = CP_UTF8; - heap_free( request->proxy.lpszProxy ); + free( request->proxy.lpszProxy ); request->proxy.lpszProxy = NULL; - heap_free( request->proxy.lpszProxyBypass ); + free( request->proxy.lpszProxyBypass ); request->proxy.lpszProxyBypass = NULL; VariantClear( &request->data ); request->state = REQUEST_STATE_INITIALIZED; @@ -3637,13 +5045,9 @@ static HRESULT WINAPI winhttp_request_Open( BSTR url, VARIANT async ) { - static const WCHAR typeW[] = {'*','/','*',0}; - static const WCHAR *acceptW[] = {typeW, NULL}; static const WCHAR httpsW[] = {'h','t','t','p','s'}; - static const WCHAR user_agentW[] = { - 'M','o','z','i','l','l','a','/','4','.','0',' ','(','c','o','m','p','a','t','i','b','l','e',';',' ', - 'W','i','n','3','2',';',' ','W','i','n','H','t','t','p','.','W','i','n','H','t','t','p', - 'R','e','q','u','e','s','t','.','5',')',0}; + static const WCHAR *acceptW[] = {L"*/*", NULL}; + static const WCHAR user_agentW[] = L"Mozilla/4.0 (compatible; Win32; WinHttp.WinHttpRequest.5)"; struct winhttp_request *request = impl_from_IWinHttpRequest( iface ); URL_COMPONENTS uc; WCHAR *hostname, *path = NULL, *verb = NULL; @@ -3665,15 +5069,15 @@ static HRESULT WINAPI winhttp_request_Open( EnterCriticalSection( &request->cs ); reset_request( request ); - if (!(hostname = heap_alloc( (uc.dwHostNameLength + 1) * sizeof(WCHAR) ))) goto error; + if (!(hostname = malloc( (uc.dwHostNameLength + 1) * sizeof(WCHAR) ))) goto error; memcpy( hostname, uc.lpszHostName, uc.dwHostNameLength * sizeof(WCHAR) ); hostname[uc.dwHostNameLength] = 0; - if (!(path = heap_alloc( (uc.dwUrlPathLength + uc.dwExtraInfoLength + 1) * sizeof(WCHAR) ))) goto error; + if (!(path = malloc( (uc.dwUrlPathLength + uc.dwExtraInfoLength + 1) * sizeof(WCHAR) ))) goto error; memcpy( path, uc.lpszUrlPath, (uc.dwUrlPathLength + uc.dwExtraInfoLength) * sizeof(WCHAR) ); path[uc.dwUrlPathLength + uc.dwExtraInfoLength] = 0; - if (!(verb = strdupW( method ))) goto error; + if (!(verb = wcsdup( method ))) goto error; if (SUCCEEDED( VariantChangeType( &async, &async, 0, VT_BOOL )) && V_BOOL( &async )) request->async = TRUE; else request->async = FALSE; @@ -3713,17 +5117,17 @@ static HRESULT WINAPI winhttp_request_Open( request->state = REQUEST_STATE_OPEN; request->verb = verb; - heap_free( hostname ); - heap_free( path ); + free( hostname ); + free( path ); LeaveCriticalSection( &request->cs ); return S_OK; error: WinHttpCloseHandle( request->hconnect ); request->hconnect = NULL; - heap_free( hostname ); - heap_free( path ); - heap_free( verb ); + free( hostname ); + free( path ); + free( verb ); LeaveCriticalSection( &request->cs ); return HRESULT_FROM_WIN32( err ); } @@ -3733,8 +5137,6 @@ static HRESULT WINAPI winhttp_request_SetRequestHeader( BSTR header, BSTR value ) { - static const WCHAR fmtW[] = {'%','s',':',' ','%','s','\r','\n',0}; - static const WCHAR emptyW[] = {0}; struct winhttp_request *request = impl_from_IWinHttpRequest( iface ); DWORD len, err = ERROR_SUCCESS; WCHAR *str; @@ -3754,20 +5156,20 @@ static HRESULT WINAPI winhttp_request_SetRequestHeader( err = ERROR_WINHTTP_CANNOT_CALL_AFTER_SEND; goto done; } - len = strlenW( header ) + 4; - if (value) len += strlenW( value ); - if (!(str = heap_alloc( (len + 1) * sizeof(WCHAR) ))) + len = lstrlenW( header ) + 4; + if (value) len += lstrlenW( value ); + if (!(str = malloc( (len + 1) * sizeof(WCHAR) ))) { err = ERROR_OUTOFMEMORY; goto done; } - sprintfW( str, fmtW, header, value ? value : emptyW ); + swprintf( str, len + 1, L"%s: %s\r\n", header, value ? value : L"" ); if (!WinHttpAddRequestHeaders( request->hrequest, str, len, WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE )) { err = GetLastError(); } - heap_free( str ); + free( str ); done: LeaveCriticalSection( &request->cs ); @@ -3892,38 +5294,22 @@ static void wait_set_status_callback( struct winhttp_request *request, DWORD sta static DWORD wait_for_completion( struct winhttp_request *request ) { HANDLE handles[2] = { request->wait, request->cancel }; -#ifndef __REACTOS__ DWORD ret; -#endif switch (WaitForMultipleObjects( 2, handles, FALSE, INFINITE )) { case WAIT_OBJECT_0: -#ifndef __REACTOS__ ret = request->error; -#endif break; case WAIT_OBJECT_0 + 1: -#ifdef __REACTOS__ - request->error = ERROR_CANCELLED; -#else ret = request->error = ERROR_CANCELLED; SetEvent( request->done ); -#endif break; default: -#ifdef __REACTOS__ - request->error = GetLastError(); -#else ret = request->error = GetLastError(); -#endif break; } -#ifdef __REACTOS__ - return request->error; -#else return ret; -#endif } static HRESULT request_receive( struct winhttp_request *request ) @@ -3936,12 +5322,12 @@ static HRESULT request_receive( struct winhttp_request *request ) return HRESULT_FROM_WIN32( GetLastError() ); } if ((err = wait_for_completion( request ))) return HRESULT_FROM_WIN32( err ); - if (!strcmpW( request->verb, headW )) + if (!wcscmp( request->verb, L"HEAD" )) { request->state = REQUEST_STATE_RESPONSE_RECEIVED; return S_OK; } - if (!(request->buffer = heap_alloc( buflen ))) return E_OUTOFMEMORY; + if (!(request->buffer = malloc( buflen ))) return E_OUTOFMEMORY; request->buffer[0] = 0; size = 0; do @@ -3959,7 +5345,7 @@ static HRESULT request_receive( struct winhttp_request *request ) { char *tmp; while (buflen < size) buflen *= 2; - if (!(tmp = heap_realloc( request->buffer, buflen ))) + if (!(tmp = realloc( request->buffer, buflen ))) { err = ERROR_OUTOFMEMORY; goto error; @@ -3981,7 +5367,7 @@ static HRESULT request_receive( struct winhttp_request *request ) return S_OK; error: - heap_free( request->buffer ); + free( request->buffer ); request->buffer = NULL; return HRESULT_FROM_WIN32( err ); } @@ -3997,6 +5383,9 @@ static DWORD request_set_parameters( struct winhttp_request *request ) if (!WinHttpSetOption( request->hrequest, WINHTTP_OPTION_DISABLE_FEATURE, &request->disable_feature, sizeof(request->disable_feature) )) return GetLastError(); + if (!WinHttpSetOption( request->hrequest, WINHTTP_OPTION_SECURITY_FLAGS, &request->security_flags, + sizeof(request->security_flags) )) return GetLastError(); + if (!WinHttpSetTimeouts( request->hrequest, request->resolve_timeout, request->connect_timeout, @@ -4007,15 +5396,13 @@ static DWORD request_set_parameters( struct winhttp_request *request ) static void request_set_utf8_content_type( struct winhttp_request *request ) { - static const WCHAR fmtW[] = {'%','s',':',' ','%','s',0}; - static const WCHAR text_plainW[] = {'t','e','x','t','/','p','l','a','i','n',0}; - static const WCHAR charset_utf8W[] = {'c','h','a','r','s','e','t','=','u','t','f','-','8',0}; WCHAR headerW[64]; int len; - len = sprintfW( headerW, fmtW, attr_content_type, text_plainW ); + len = swprintf( headerW, ARRAY_SIZE(headerW), L"%s: %s", L"Content-Type", L"text/plain" ); WinHttpAddRequestHeaders( request->hrequest, headerW, len, WINHTTP_ADDREQ_FLAG_ADD_IF_NEW ); - len = sprintfW( headerW, fmtW, attr_content_type, charset_utf8W ); + + len = swprintf( headerW, ARRAY_SIZE(headerW), L"%s: %s", L"Content-Type", L"charset=utf-8" ); WinHttpAddRequestHeaders( request->hrequest, headerW, len, WINHTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON ); } @@ -4029,14 +5416,14 @@ static HRESULT request_send( struct winhttp_request *request ) DWORD err; if ((err = request_set_parameters( request ))) return HRESULT_FROM_WIN32( err ); - if (strcmpW( request->verb, getW )) + if (wcscmp( request->verb, L"GET" )) { VariantInit( &data ); if (V_VT( &request->data ) == VT_BSTR) { UINT cp = CP_ACP; const WCHAR *str = V_BSTR( &request->data ); - int i, len = strlenW( str ); + int i, len = lstrlenW( str ); for (i = 0; i < len; i++) { @@ -4047,7 +5434,7 @@ static HRESULT request_send( struct winhttp_request *request ) } } size = WideCharToMultiByte( cp, 0, str, len, NULL, 0, NULL, NULL ); - if (!(ptr = heap_alloc( size ))) return E_OUTOFMEMORY; + if (!(ptr = malloc( size ))) return E_OUTOFMEMORY; WideCharToMultiByte( cp, 0, str, len, ptr, size, NULL, NULL ); if (cp == CP_UTF8) request_set_utf8_content_type( request ); } @@ -4063,7 +5450,7 @@ static HRESULT request_send( struct winhttp_request *request ) size++; } } - wait_set_status_callback( request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT ); + wait_set_status_callback( request, WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE ); if (!WinHttpSendRequest( request->hrequest, NULL, 0, ptr, size, size, 0 )) { err = GetLastError(); @@ -4071,54 +5458,31 @@ static HRESULT request_send( struct winhttp_request *request ) } if ((err = wait_for_completion( request ))) goto error; if (sa) SafeArrayUnaccessData( sa ); - else heap_free( ptr ); + else free( ptr ); request->state = REQUEST_STATE_SENT; return S_OK; error: if (sa) SafeArrayUnaccessData( sa ); - else heap_free( ptr ); + else free( ptr ); return HRESULT_FROM_WIN32( err ); } -#ifdef __REACTOS__ -static HRESULT request_send_and_receive( struct winhttp_request *request ) -{ - HRESULT hr = request_send( request ); - if (hr == S_OK) hr = request_receive( request ); - return hr; -} - -static DWORD CALLBACK send_and_receive_proc( void *arg ) -{ - struct winhttp_request *request = (struct winhttp_request *)arg; - return request_send_and_receive( request ); -} -#else static void CALLBACK send_and_receive_proc( TP_CALLBACK_INSTANCE *instance, void *ctx ) { struct winhttp_request *request = (struct winhttp_request *)ctx; if (request_send( request ) == S_OK) request_receive( request ); SetEvent( request->done ); } -#endif /* critical section must be held */ static DWORD request_wait( struct winhttp_request *request, DWORD timeout ) { -#ifdef __REACTOS__ - HANDLE thread = request->thread; -#else HANDLE done = request->done; -#endif DWORD err, ret; LeaveCriticalSection( &request->cs ); -#ifdef __REACTOS__ - while ((err = MsgWaitForMultipleObjects( 1, &thread, FALSE, timeout, QS_ALLINPUT )) == WAIT_OBJECT_0 + 1) -#else while ((err = MsgWaitForMultipleObjects( 1, &done, FALSE, timeout, QS_ALLINPUT )) == WAIT_OBJECT_0 + 1) -#endif { MSG msg; while (PeekMessageW( &msg, NULL, 0, 0, PM_REMOVE )) @@ -4140,9 +5504,7 @@ static DWORD request_wait( struct winhttp_request *request, DWORD timeout ) break; } EnterCriticalSection( &request->cs ); -#ifndef __REACTOS__ if (err == WAIT_OBJECT_0) request->proc_running = FALSE; -#endif return ret; } @@ -4172,18 +5534,12 @@ static HRESULT WINAPI winhttp_request_Send( LeaveCriticalSection( &request->cs ); return hr; } -#ifdef __REACTOS__ - if (!(request->thread = CreateThread( NULL, 0, send_and_receive_proc, request, 0, NULL ))) -#else if (!TrySubmitThreadpoolCallback( send_and_receive_proc, request, NULL )) -#endif { LeaveCriticalSection( &request->cs ); return HRESULT_FROM_WIN32( GetLastError() ); } -#ifndef __REACTOS__ request->proc_running = TRUE; -#endif if (!request->async) { hr = HRESULT_FROM_WIN32( request_wait( request, INFINITE ) ); @@ -4263,8 +5619,6 @@ done: static DWORD request_get_codepage( struct winhttp_request *request, UINT *codepage ) { - static const WCHAR utf8W[] = {'u','t','f','-','8',0}; - static const WCHAR charsetW[] = {'c','h','a','r','s','e','t',0}; WCHAR *buffer, *p; DWORD size; @@ -4272,22 +5626,23 @@ static DWORD request_get_codepage( struct winhttp_request *request, UINT *codepa if (!WinHttpQueryHeaders( request->hrequest, WINHTTP_QUERY_CONTENT_TYPE, NULL, NULL, &size, NULL ) && GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - if (!(buffer = heap_alloc( size ))) return ERROR_OUTOFMEMORY; + if (!(buffer = malloc( size ))) return ERROR_OUTOFMEMORY; if (!WinHttpQueryHeaders( request->hrequest, WINHTTP_QUERY_CONTENT_TYPE, NULL, buffer, &size, NULL )) { + free( buffer ); return GetLastError(); } - if ((p = strstrW( buffer, charsetW ))) + if ((p = wcsstr( buffer, L"charset" ))) { - p += strlenW( charsetW ); + p += lstrlenW( L"charset" ); while (*p == ' ') p++; if (*p++ == '=') { while (*p == ' ') p++; - if (!strcmpiW( p, utf8W )) *codepage = CP_UTF8; + if (!wcsicmp( p, L"utf-8" )) *codepage = CP_UTF8; } } - heap_free( buffer ); + free( buffer ); } return ERROR_SUCCESS; } @@ -4416,8 +5771,8 @@ static ULONG WINAPI stream_Release( IStream *iface ) LONG refs = InterlockedDecrement( &stream->refs ); if (!refs) { - heap_free( stream->data ); - heap_free( stream ); + free( stream->data ); + free( stream ); } return refs; } @@ -4547,16 +5902,16 @@ static HRESULT WINAPI winhttp_request_get_ResponseStream( err = ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND; goto done; } - if (!(stream = heap_alloc( sizeof(*stream) ))) + if (!(stream = malloc( sizeof(*stream) ))) { err = ERROR_OUTOFMEMORY; goto done; } stream->IStream_iface.lpVtbl = &stream_vtbl; stream->refs = 1; - if (!(stream->data = heap_alloc( request->offset ))) + if (!(stream->data = malloc( request->offset ))) { - heap_free( stream ); + free( stream ); err = ERROR_OUTOFMEMORY; goto done; } @@ -4588,6 +5943,12 @@ static HRESULT WINAPI winhttp_request_get_Option( V_VT( value ) = VT_I4; V_I4( value ) = request->url_codepage; break; + case WinHttpRequestOption_SslErrorIgnoreFlags: + { + V_VT( value ) = VT_I4; + V_I4( value ) = request->security_flags; + break; + } default: FIXME("unimplemented option %u\n", option); hr = E_NOTIMPL; @@ -4620,9 +5981,7 @@ static HRESULT WINAPI winhttp_request_put_Option( } case WinHttpRequestOption_URLCodePage: { - static const WCHAR utf8W[] = {'u','t','f','-','8',0}; VARIANT cp; - VariantInit( &cp ); hr = VariantChangeType( &cp, &value, 0, VT_UI4 ); if (SUCCEEDED( hr )) @@ -4630,7 +5989,7 @@ static HRESULT WINAPI winhttp_request_put_Option( request->url_codepage = V_UI4( &cp ); TRACE("URL codepage: %u\n", request->url_codepage); } - else if (V_VT( &value ) == VT_BSTR && !strcmpiW( V_BSTR( &value ), utf8W )) + else if (V_VT( &value ) == VT_BSTR && !wcsicmp( V_BSTR( &value ), L"utf-8" )) { TRACE("URL codepage: UTF-8\n"); request->url_codepage = CP_UTF8; @@ -4640,6 +5999,20 @@ static HRESULT WINAPI winhttp_request_put_Option( FIXME("URL codepage %s is not recognized\n", debugstr_variant( &value )); break; } + case WinHttpRequestOption_SslErrorIgnoreFlags: + { + static const DWORD accepted = SECURITY_FLAG_IGNORE_CERT_CN_INVALID | + SECURITY_FLAG_IGNORE_CERT_DATE_INVALID | + SECURITY_FLAG_IGNORE_UNKNOWN_CA | + SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE; + + DWORD flags = V_I4( &value ); + if (flags && (flags & ~accepted)) + hr = E_INVALIDARG; + else + request->security_flags = flags; + break; + } default: FIXME("unimplemented option %u\n", option); hr = E_NOTIMPL; @@ -4702,7 +6075,7 @@ static HRESULT WINAPI winhttp_request_SetTimeouts( { struct winhttp_request *request = impl_from_IWinHttpRequest( iface ); - TRACE("%p, %d, %d, %d, %d\n", request, resolve_timeout, connect_timeout, send_timeout, receive_timeout); + TRACE( "%p, %ld, %ld, %ld, %ld\n", request, resolve_timeout, connect_timeout, send_timeout, receive_timeout ); EnterCriticalSection( &request->cs ); request->resolve_timeout = resolve_timeout; @@ -4785,10 +6158,10 @@ HRESULT WinHttpRequest_create( void **obj ) TRACE("%p\n", obj); - if (!(request = heap_alloc_zero( sizeof(*request) ))) return E_OUTOFMEMORY; + if (!(request = calloc( 1, sizeof(*request) ))) return E_OUTOFMEMORY; request->IWinHttpRequest_iface.lpVtbl = &winhttp_request_vtbl; request->refs = 1; - InitializeCriticalSection( &request->cs ); + InitializeCriticalSectionEx( &request->cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO ); request->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": winhttp_request.cs"); initialize_request( request ); diff --git a/dll/win32/winhttp/session.c b/dll/win32/winhttp/session.c index 4392f022c63..9eb8a3468ba 100644 --- a/dll/win32/winhttp/session.c +++ b/dll/win32/winhttp/session.c @@ -16,17 +16,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include "config.h" #include -#include - -#ifdef HAVE_CORESERVICES_CORESERVICES_H -#define GetCurrentThread MacGetCurrentThread -#define LoadResource MacLoadResource -#include -#undef GetCurrentThread -#undef LoadResource -#endif #include "windef.h" #include "winbase.h" @@ -35,7 +25,9 @@ #include "ws2tcpip.h" #include "winhttp.h" #include "winreg.h" -#include "wine/winternl.h" +#include "winternl.h" +#include "iphlpapi.h" +#include "dhcpcsdk.h" #define COBJMACROS #include "ole2.h" #include "dispex.h" @@ -56,9 +48,11 @@ void send_callback( struct object_header *hdr, DWORD status, void *info, DWORD b { if (hdr->callback && (hdr->notify_mask & status)) { - TRACE("%p, 0x%08x, %p, %u\n", hdr, status, info, buflen); + TRACE( "%p, %#lx, %p, %lu, %lu\n", hdr, status, info, buflen, hdr->recursion_count ); + InterlockedIncrement( &hdr->recursion_count ); hdr->callback( hdr->handle, hdr->context, status, info, buflen ); - TRACE("returning from 0x%08x callback\n", status); + InterlockedDecrement( &hdr->recursion_count ); + TRACE("returning from %#lx callback\n", status); } } @@ -71,9 +65,6 @@ BOOL WINAPI WinHttpCheckPlatform( void ) return TRUE; } -/*********************************************************************** - * session_destroy (internal) - */ static void session_destroy( struct object_header *hdr ) { struct session *session = (struct session *)hdr; @@ -85,12 +76,23 @@ static void session_destroy( struct object_header *hdr ) session->cs.DebugInfo->Spare[0] = 0; DeleteCriticalSection( &session->cs ); - heap_free( session->agent ); - heap_free( session->proxy_server ); - heap_free( session->proxy_bypass ); - heap_free( session->proxy_username ); - heap_free( session->proxy_password ); - heap_free( session ); + free( session->agent ); + free( session->proxy_server ); + free( session->proxy_bypass ); + free( session->proxy_username ); + free( session->proxy_password ); + free( session ); +} + +static BOOL validate_buffer( void *buffer, DWORD *buflen, DWORD required ) +{ + if (!buffer || *buflen < required) + { + *buflen = required; + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + return FALSE; + } + return TRUE; } static BOOL session_query_option( struct object_header *hdr, DWORD option, void *buffer, DWORD *buflen ) @@ -101,44 +103,63 @@ static BOOL session_query_option( struct object_header *hdr, DWORD option, void { case WINHTTP_OPTION_REDIRECT_POLICY: { - if (!buffer || *buflen < sizeof(DWORD)) - { - *buflen = sizeof(DWORD); - SetLastError( ERROR_INSUFFICIENT_BUFFER ); - return FALSE; - } + if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE; *(DWORD *)buffer = hdr->redirect_policy; *buflen = sizeof(DWORD); return TRUE; } case WINHTTP_OPTION_RESOLVE_TIMEOUT: + if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE; + *(DWORD *)buffer = session->resolve_timeout; *buflen = sizeof(DWORD); return TRUE; case WINHTTP_OPTION_CONNECT_TIMEOUT: + if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE; + *(DWORD *)buffer = session->connect_timeout; *buflen = sizeof(DWORD); return TRUE; case WINHTTP_OPTION_SEND_TIMEOUT: + if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE; + *(DWORD *)buffer = session->send_timeout; *buflen = sizeof(DWORD); return TRUE; case WINHTTP_OPTION_RECEIVE_TIMEOUT: + if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE; + *(DWORD *)buffer = session->receive_timeout; *buflen = sizeof(DWORD); return TRUE; case WINHTTP_OPTION_RECEIVE_RESPONSE_TIMEOUT: + if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE; + *(DWORD *)buffer = session->receive_response_timeout; *buflen = sizeof(DWORD); return TRUE; + case WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE: + if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE; + + *(DWORD *)buffer = session->websocket_receive_buffer_size; + *buflen = sizeof(DWORD); + return TRUE; + + case WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE: + if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE; + + *(DWORD *)buffer = session->websocket_send_buffer_size; + *buflen = sizeof(DWORD); + return TRUE; + default: - FIXME("unimplemented option %u\n", option); + FIXME( "unimplemented option %lu\n", option ); SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } @@ -154,7 +175,7 @@ static BOOL session_set_option( struct object_header *hdr, DWORD option, void *b { WINHTTP_PROXY_INFO *pi = buffer; - FIXME("%u %s %s\n", pi->dwAccessType, debugstr_w(pi->lpszProxy), debugstr_w(pi->lpszProxyBypass)); + FIXME( "%lu %s %s\n", pi->dwAccessType, debugstr_w(pi->lpszProxy), debugstr_w(pi->lpszProxyBypass) ); return TRUE; } case WINHTTP_OPTION_REDIRECT_POLICY: @@ -168,7 +189,7 @@ static BOOL session_set_option( struct object_header *hdr, DWORD option, void *b } policy = *(DWORD *)buffer; - TRACE("0x%x\n", policy); + TRACE( "%#lx\n", policy ); hdr->redirect_policy = policy; return TRUE; } @@ -182,7 +203,7 @@ static BOOL session_set_option( struct object_header *hdr, DWORD option, void *b EnterCriticalSection( &session->cs ); session->secure_protocols = *(DWORD *)buffer; LeaveCriticalSection( &session->cs ); - TRACE("0x%x\n", session->secure_protocols); + TRACE( "%#lx\n", session->secure_protocols ); return TRUE; } case WINHTTP_OPTION_DISABLE_FEATURE: @@ -219,15 +240,47 @@ static BOOL session_set_option( struct object_header *hdr, DWORD option, void *b return TRUE; case WINHTTP_OPTION_MAX_CONNS_PER_SERVER: - FIXME("WINHTTP_OPTION_MAX_CONNS_PER_SERVER: %d\n", *(DWORD *)buffer); + FIXME( "WINHTTP_OPTION_MAX_CONNS_PER_SERVER: %lu\n", *(DWORD *)buffer ); return TRUE; case WINHTTP_OPTION_MAX_CONNS_PER_1_0_SERVER: - FIXME("WINHTTP_OPTION_MAX_CONNS_PER_1_0_SERVER: %d\n", *(DWORD *)buffer); + FIXME( "WINHTTP_OPTION_MAX_CONNS_PER_1_0_SERVER: %lu\n", *(DWORD *)buffer ); return TRUE; + case WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE: + { + DWORD buffer_size; + + if (buflen != sizeof(buffer_size)) + { + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + return FALSE; + } + + buffer_size = *(DWORD *)buffer; + TRACE( "%#lx\n", buffer_size ); + session->websocket_receive_buffer_size = buffer_size; + return TRUE; + } + + case WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE: + { + DWORD buffer_size; + + if (buflen != sizeof(buffer_size)) + { + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + return FALSE; + } + + buffer_size = *(DWORD *)buffer; + TRACE( "%#lx\n", buffer_size ); + session->websocket_send_buffer_size = buffer_size; + return TRUE; + } + default: - FIXME("unimplemented option %u\n", option); + FIXME( "unimplemented option %lu\n", option ); SetLastError( ERROR_WINHTTP_INVALID_OPTION ); return FALSE; } @@ -235,6 +288,7 @@ static BOOL session_set_option( struct object_header *hdr, DWORD option, void *b static const struct object_vtbl session_vtbl = { + NULL, session_destroy, session_query_option, session_set_option @@ -252,54 +306,54 @@ HINTERNET WINAPI WinHttpOpen( LPCWSTR agent, DWORD access, LPCWSTR proxy, LPCWST struct session *session; HINTERNET handle = NULL; - TRACE("%s, %u, %s, %s, 0x%08x\n", debugstr_w(agent), access, debugstr_w(proxy), debugstr_w(bypass), flags); + TRACE( "%s, %lu, %s, %s, %#lx\n", debugstr_w(agent), access, debugstr_w(proxy), debugstr_w(bypass), flags ); - if (!(session = heap_alloc_zero( sizeof(struct session) ))) return NULL; + if (!(session = calloc( 1, sizeof(*session) ))) return NULL; session->hdr.type = WINHTTP_HANDLE_TYPE_SESSION; session->hdr.vtbl = &session_vtbl; session->hdr.flags = flags; session->hdr.refs = 1; session->hdr.redirect_policy = WINHTTP_OPTION_REDIRECT_POLICY_DISALLOW_HTTPS_TO_HTTP; - list_init( &session->hdr.children ); session->resolve_timeout = DEFAULT_RESOLVE_TIMEOUT; session->connect_timeout = DEFAULT_CONNECT_TIMEOUT; session->send_timeout = DEFAULT_SEND_TIMEOUT; session->receive_timeout = DEFAULT_RECEIVE_TIMEOUT; session->receive_response_timeout = DEFAULT_RECEIVE_RESPONSE_TIMEOUT; + session->websocket_receive_buffer_size = 32768; + session->websocket_send_buffer_size = 32768; list_init( &session->cookie_cache ); - InitializeCriticalSection( &session->cs ); + InitializeCriticalSectionEx( &session->cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO ); session->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": session.cs"); - if (agent && !(session->agent = strdupW( agent ))) goto end; + if (agent && !(session->agent = wcsdup( agent ))) goto end; if (access == WINHTTP_ACCESS_TYPE_DEFAULT_PROXY) { WINHTTP_PROXY_INFO info; WinHttpGetDefaultProxyConfiguration( &info ); session->access = info.dwAccessType; - if (info.lpszProxy && !(session->proxy_server = strdupW( info.lpszProxy ))) + if (info.lpszProxy && !(session->proxy_server = wcsdup( info.lpszProxy ))) { - GlobalFree( (LPWSTR)info.lpszProxy ); - GlobalFree( (LPWSTR)info.lpszProxyBypass ); + GlobalFree( info.lpszProxy ); + GlobalFree( info.lpszProxyBypass ); goto end; } - if (info.lpszProxyBypass && !(session->proxy_bypass = strdupW( info.lpszProxyBypass ))) + if (info.lpszProxyBypass && !(session->proxy_bypass = wcsdup( info.lpszProxyBypass ))) { - GlobalFree( (LPWSTR)info.lpszProxy ); - GlobalFree( (LPWSTR)info.lpszProxyBypass ); + GlobalFree( info.lpszProxy ); + GlobalFree( info.lpszProxyBypass ); goto end; } } else if (access == WINHTTP_ACCESS_TYPE_NAMED_PROXY) { session->access = access; - if (proxy && !(session->proxy_server = strdupW( proxy ))) goto end; - if (bypass && !(session->proxy_bypass = strdupW( bypass ))) goto end; + if (proxy && !(session->proxy_server = wcsdup( proxy ))) goto end; + if (bypass && !(session->proxy_bypass = wcsdup( bypass ))) goto end; } - if (!(handle = alloc_handle( &session->hdr ))) goto end; - session->hdr.handle = handle; + handle = alloc_handle( &session->hdr ); #ifdef __REACTOS__ winsock_init(); @@ -312,9 +366,6 @@ end: return handle; } -/*********************************************************************** - * connect_destroy (internal) - */ static void connect_destroy( struct object_header *hdr ) { struct connect *connect = (struct connect *)hdr; @@ -323,11 +374,11 @@ static void connect_destroy( struct object_header *hdr ) release_object( &connect->session->hdr ); - heap_free( connect->hostname ); - heap_free( connect->servername ); - heap_free( connect->username ); - heap_free( connect->password ); - heap_free( connect ); + free( connect->hostname ); + free( connect->servername ); + free( connect->username ); + free( connect->password ); + free( connect ); } static BOOL connect_query_option( struct object_header *hdr, DWORD option, void *buffer, DWORD *buflen ) @@ -338,44 +389,49 @@ static BOOL connect_query_option( struct object_header *hdr, DWORD option, void { case WINHTTP_OPTION_PARENT_HANDLE: { - if (!buffer || *buflen < sizeof(HINTERNET)) - { - *buflen = sizeof(HINTERNET); - SetLastError( ERROR_INSUFFICIENT_BUFFER ); - return FALSE; - } + if (!validate_buffer( buffer, buflen, sizeof(HINTERNET) )) return FALSE; - *(HINTERNET *)buffer = ((struct object_header *)connect->session)->handle; + *(HINTERNET *)buffer = connect->session->hdr.handle; *buflen = sizeof(HINTERNET); return TRUE; } case WINHTTP_OPTION_RESOLVE_TIMEOUT: + if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE; + *(DWORD *)buffer = connect->session->resolve_timeout; *buflen = sizeof(DWORD); return TRUE; case WINHTTP_OPTION_CONNECT_TIMEOUT: + if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE; + *(DWORD *)buffer = connect->session->connect_timeout; *buflen = sizeof(DWORD); return TRUE; case WINHTTP_OPTION_SEND_TIMEOUT: + if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE; + *(DWORD *)buffer = connect->session->send_timeout; *buflen = sizeof(DWORD); return TRUE; case WINHTTP_OPTION_RECEIVE_TIMEOUT: + if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE; + *(DWORD *)buffer = connect->session->receive_timeout; *buflen = sizeof(DWORD); return TRUE; case WINHTTP_OPTION_RECEIVE_RESPONSE_TIMEOUT: + if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE; + *(DWORD *)buffer = connect->session->receive_response_timeout; *buflen = sizeof(DWORD); return TRUE; default: - FIXME("unimplemented option %u\n", option); + FIXME( "unimplemented option %lu\n", option ); SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } @@ -383,6 +439,7 @@ static BOOL connect_query_option( struct object_header *hdr, DWORD option, void static const struct object_vtbl connect_vtbl = { + NULL, connect_destroy, connect_query_option, NULL @@ -390,10 +447,9 @@ static const struct object_vtbl connect_vtbl = static BOOL domain_matches(LPCWSTR server, LPCWSTR domain) { - static const WCHAR localW[] = { '<','l','o','c','a','l','>',0 }; BOOL ret = FALSE; - if (!strcmpiW( domain, localW ) && !strchrW( server, '.' )) + if (!wcsicmp( domain, L"" ) && !wcschr( server, '.' )) ret = TRUE; else if (*domain == '*') { @@ -405,12 +461,12 @@ static BOOL domain_matches(LPCWSTR server, LPCWSTR domain) * the wildcard exactly. E.g. if the wildcard is *.a.b, and the * hostname is www.foo.a.b, it matches, but a.b does not. */ - dot = strchrW( server, '.' ); + dot = wcschr( server, '.' ); if (dot) { - int len = strlenW( dot + 1 ); + int len = lstrlenW( dot + 1 ); - if (len > strlenW( domain + 2 )) + if (len > lstrlenW( domain + 2 )) { LPCWSTR ptr; @@ -418,8 +474,8 @@ static BOOL domain_matches(LPCWSTR server, LPCWSTR domain) * could be a subdomain. Compare the last portion of the * server's domain. */ - ptr = dot + len + 1 - strlenW( domain + 2 ); - if (!strcmpiW( ptr, domain + 2 )) + ptr = dot + len + 1 - lstrlenW( domain + 2 ); + if (!wcsicmp( ptr, domain + 2 )) { /* This is only a match if the preceding character is * a '.', i.e. that it is a matching domain. E.g. @@ -430,12 +486,12 @@ static BOOL domain_matches(LPCWSTR server, LPCWSTR domain) } } else - ret = !strcmpiW( dot + 1, domain + 2 ); + ret = !wcsicmp( dot + 1, domain + 2 ); } } } else - ret = !strcmpiW( server, domain ); + ret = !wcsicmp( server, domain ); return ret; } @@ -452,9 +508,9 @@ static BOOL should_bypass_proxy(struct session *session, LPCWSTR server) do { LPCWSTR tmp = ptr; - ptr = strchrW( ptr, ';' ); + ptr = wcschr( ptr, ';' ); if (!ptr) - ptr = strchrW( tmp, ' ' ); + ptr = wcschr( tmp, ' ' ); if (ptr) { if (ptr - tmp < MAX_HOST_NAME_LENGTH) @@ -482,36 +538,33 @@ BOOL set_server_for_hostname( struct connect *connect, const WCHAR *server, INTE { LPCWSTR colon; - if ((colon = strchrW( session->proxy_server, ':' ))) + if ((colon = wcschr( session->proxy_server, ':' ))) { - if (!connect->servername || strncmpiW( connect->servername, + if (!connect->servername || wcsnicmp( connect->servername, session->proxy_server, colon - session->proxy_server - 1 )) { - heap_free( connect->servername ); + free( connect->servername ); connect->resolved = FALSE; - if (!(connect->servername = heap_alloc( - (colon - session->proxy_server + 1) * sizeof(WCHAR) ))) + if (!(connect->servername = malloc( (colon - session->proxy_server + 1) * sizeof(WCHAR) ))) { ret = FALSE; goto end; } - memcpy( connect->servername, session->proxy_server, - (colon - session->proxy_server) * sizeof(WCHAR) ); + memcpy( connect->servername, session->proxy_server, (colon - session->proxy_server) * sizeof(WCHAR) ); connect->servername[colon - session->proxy_server] = 0; if (*(colon + 1)) - connect->serverport = atoiW( colon + 1 ); + connect->serverport = wcstol( colon + 1, NULL, 10 ); else connect->serverport = INTERNET_DEFAULT_PORT; } } else { - if (!connect->servername || strcmpiW( connect->servername, - session->proxy_server )) + if (!connect->servername || wcsicmp( connect->servername, session->proxy_server )) { - heap_free( connect->servername ); + free( connect->servername ); connect->resolved = FALSE; - if (!(connect->servername = strdupW( session->proxy_server ))) + if (!(connect->servername = wcsdup( session->proxy_server ))) { ret = FALSE; goto end; @@ -522,9 +575,9 @@ BOOL set_server_for_hostname( struct connect *connect, const WCHAR *server, INTE } else if (server) { - heap_free( connect->servername ); + free( connect->servername ); connect->resolved = FALSE; - if (!(connect->servername = strdupW( server ))) + if (!(connect->servername = wcsdup( server ))) { ret = FALSE; goto end; @@ -538,13 +591,13 @@ end: /*********************************************************************** * WinHttpConnect (winhttp.@) */ -HINTERNET WINAPI WinHttpConnect( HINTERNET hsession, LPCWSTR server, INTERNET_PORT port, DWORD reserved ) +HINTERNET WINAPI WinHttpConnect( HINTERNET hsession, const WCHAR *server, INTERNET_PORT port, DWORD reserved ) { struct connect *connect; struct session *session; HINTERNET hconnect = NULL; - TRACE("%p, %s, %u, %x\n", hsession, debugstr_w(server), port, reserved); + TRACE( "%p, %s, %u, %#lx\n", hsession, debugstr_w(server), port, reserved ); if (!server) { @@ -562,7 +615,7 @@ HINTERNET WINAPI WinHttpConnect( HINTERNET hsession, LPCWSTR server, INTERNET_PO SetLastError( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE ); return NULL; } - if (!(connect = heap_alloc_zero( sizeof(struct connect) ))) + if (!(connect = calloc( 1, sizeof(*connect) ))) { release_object( &session->hdr ); return NULL; @@ -575,20 +628,18 @@ HINTERNET WINAPI WinHttpConnect( HINTERNET hsession, LPCWSTR server, INTERNET_PO connect->hdr.notify_mask = session->hdr.notify_mask; connect->hdr.context = session->hdr.context; connect->hdr.redirect_policy = session->hdr.redirect_policy; - list_init( &connect->hdr.children ); addref_object( &session->hdr ); connect->session = session; - list_add_head( &session->hdr.children, &connect->hdr.entry ); - if (!(connect->hostname = strdupW( server ))) goto end; + if (!(connect->hostname = wcsdup( server ))) goto end; connect->hostport = port; if (!set_server_for_hostname( connect, server, port )) goto end; - if (!(hconnect = alloc_handle( &connect->hdr ))) goto end; - connect->hdr.handle = hconnect; - - send_callback( &session->hdr, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, &hconnect, sizeof(hconnect) ); + if ((hconnect = alloc_handle( &connect->hdr ))) + { + send_callback( &session->hdr, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, &hconnect, sizeof(hconnect) ); + } end: release_object( &connect->hdr ); @@ -598,9 +649,6 @@ end: return hconnect; } -/*********************************************************************** - * request_destroy (internal) - */ static void request_destroy( struct object_header *hdr ) { struct request *request = (struct request *)hdr; @@ -608,24 +656,7 @@ static void request_destroy( struct object_header *hdr ) TRACE("%p\n", request); -#ifdef __REACTOS__ - if (request->task_thread) -#else - if (request->task_proc_running) -#endif - { - /* Signal to the task proc to quit. It will call this again when it does. */ -#ifdef __REACTOS__ - HANDLE thread = request->task_thread; - request->task_thread = 0; - SetEvent( request->task_cancel ); - CloseHandle( thread ); -#else - request->task_proc_running = FALSE; - SetEvent( request->task_cancel ); -#endif - return; - } + stop_queue( &request->queue ); release_object( &request->connect->hdr ); if (request->cred_handle_initialized) FreeCredentialsHandle( &request->cred_handle ); @@ -635,38 +666,47 @@ static void request_destroy( struct object_header *hdr ) destroy_authinfo( request->authinfo ); destroy_authinfo( request->proxy_authinfo ); - heap_free( request->verb ); - heap_free( request->path ); - heap_free( request->version ); - heap_free( request->raw_headers ); - heap_free( request->status_text ); + free( request->verb ); + free( request->path ); + free( request->version ); + free( request->raw_headers ); + free( request->status_text ); for (i = 0; i < request->num_headers; i++) { - heap_free( request->headers[i].field ); - heap_free( request->headers[i].value ); + free( request->headers[i].field ); + free( request->headers[i].value ); } - heap_free( request->headers ); + free( request->headers ); for (i = 0; i < TARGET_MAX; i++) { for (j = 0; j < SCHEME_MAX; j++) { - heap_free( request->creds[i][j].username ); - heap_free( request->creds[i][j].password ); + free( request->creds[i][j].username ); + free( request->creds[i][j].password ); } } - heap_free( request ); + + free( request ); } -static void str_to_buffer( WCHAR *buffer, const WCHAR *str, LPDWORD buflen ) +static BOOL return_string_option( WCHAR *buffer, const WCHAR *str, LPDWORD buflen ) { - int len = 0; - if (str) len = strlenW( str ); - if (buffer && *buflen > len) + int len = sizeof(WCHAR); + if (str) len += lstrlenW( str ) * sizeof(WCHAR); + if (buffer && *buflen >= len) { - if (str) memcpy( buffer, str, len * sizeof(WCHAR) ); - buffer[len] = 0; + if (str) memcpy( buffer, str, len ); + len -= sizeof(WCHAR); + buffer[len / sizeof(WCHAR)] = 0; + *buflen = len; + return TRUE; + } + else + { + *buflen = len; + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; } - *buflen = len * sizeof(WCHAR); } static WCHAR *blob_to_str( DWORD encoding, CERT_NAME_BLOB *blob ) @@ -707,23 +747,53 @@ static BOOL copy_sockaddr( const struct sockaddr *addr, SOCKADDR_STORAGE *addr_s } } +static WCHAR *build_url( struct request *request ) +{ + URL_COMPONENTS uc; + DWORD len = 0; + WCHAR *ret; + + memset( &uc, 0, sizeof(uc) ); + uc.dwStructSize = sizeof(uc); + uc.nScheme = (request->hdr.flags & WINHTTP_FLAG_SECURE) ? INTERNET_SCHEME_HTTPS : INTERNET_SCHEME_HTTP; + uc.lpszHostName = request->connect->hostname; + uc.dwHostNameLength = wcslen( uc.lpszHostName ); + uc.nPort = request->connect->hostport; + uc.lpszUserName = request->connect->username; + uc.dwUserNameLength = request->connect->username ? wcslen( request->connect->username ) : 0; + uc.lpszPassword = request->connect->password; + uc.dwPasswordLength = request->connect->password ? wcslen( request->connect->password ) : 0; + uc.lpszUrlPath = request->path; + uc.dwUrlPathLength = wcslen( uc.lpszUrlPath ); + + WinHttpCreateUrl( &uc, 0, NULL, &len ); + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER || !(ret = malloc( len * sizeof(WCHAR) ))) return NULL; + + if (WinHttpCreateUrl( &uc, 0, ret, &len )) return ret; + free( ret ); + return NULL; +} + static BOOL request_query_option( struct object_header *hdr, DWORD option, void *buffer, DWORD *buflen ) { struct request *request = (struct request *)hdr; switch (option) { + case WINHTTP_OPTION_PARENT_HANDLE: + { + if (!validate_buffer( buffer, buflen, sizeof(HINTERNET) )) return FALSE; + + *(HINTERNET *)buffer = request->connect->hdr.handle; + *buflen = sizeof(HINTERNET); + return TRUE; + } case WINHTTP_OPTION_SECURITY_FLAGS: { DWORD flags; int bits; - if (!buffer || *buflen < sizeof(flags)) - { - *buflen = sizeof(flags); - SetLastError( ERROR_INSUFFICIENT_BUFFER ); - return FALSE; - } + if (!validate_buffer( buffer, buflen, sizeof(flags) )) return FALSE; flags = request->security_flags; if (request->netconn) @@ -744,12 +814,7 @@ static BOOL request_query_option( struct object_header *hdr, DWORD option, void { const CERT_CONTEXT *cert; - if (!buffer || *buflen < sizeof(cert)) - { - *buflen = sizeof(cert); - SetLastError( ERROR_INSUFFICIENT_BUFFER ); - return FALSE; - } + if (!validate_buffer( buffer, buflen, sizeof(cert) )) return FALSE; if (!(cert = CertDuplicateCertificateContext( request->server_cert ))) return FALSE; *(CERT_CONTEXT **)buffer = (CERT_CONTEXT *)cert; @@ -764,13 +829,7 @@ static BOOL request_query_option( struct object_header *hdr, DWORD option, void FIXME("partial stub\n"); - if (!buffer || *buflen < sizeof(*ci)) - { - *buflen = sizeof(*ci); - SetLastError( ERROR_INSUFFICIENT_BUFFER ); - return FALSE; - } - if (!cert) return FALSE; + if (!validate_buffer( buffer, buflen, sizeof(*ci) ) || !cert) return FALSE; ci->ftExpiry = cert->pCertInfo->NotAfter; ci->ftStart = cert->pCertInfo->NotBefore; @@ -790,12 +849,7 @@ static BOOL request_query_option( struct object_header *hdr, DWORD option, void } case WINHTTP_OPTION_SECURITY_KEY_BITNESS: { - if (!buffer || *buflen < sizeof(DWORD)) - { - *buflen = sizeof(DWORD); - SetLastError( ERROR_INSUFFICIENT_BUFFER ); - return FALSE; - } + if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE; *(DWORD *)buffer = request->netconn ? netconn_get_cipher_strength( request->netconn ) : 0; *buflen = sizeof(DWORD); @@ -808,12 +862,8 @@ static BOOL request_query_option( struct object_header *hdr, DWORD option, void socklen_t len = sizeof(local); const struct sockaddr *remote = (const struct sockaddr *)&request->connect->sockaddr; - if (!buffer || *buflen < sizeof(*info)) - { - *buflen = sizeof(*info); - SetLastError( ERROR_INSUFFICIENT_BUFFER ); - return FALSE; - } + if (!validate_buffer( buffer, buflen, sizeof(*info) )) return FALSE; + if (!request->netconn) { SetLastError( ERROR_WINHTTP_INCORRECT_HANDLE_STATE ); @@ -826,48 +876,94 @@ static BOOL request_query_option( struct object_header *hdr, DWORD option, void return TRUE; } case WINHTTP_OPTION_RESOLVE_TIMEOUT: + if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE; + *(DWORD *)buffer = request->resolve_timeout; *buflen = sizeof(DWORD); return TRUE; case WINHTTP_OPTION_CONNECT_TIMEOUT: + if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE; + *(DWORD *)buffer = request->connect_timeout; *buflen = sizeof(DWORD); return TRUE; case WINHTTP_OPTION_SEND_TIMEOUT: + if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE; + *(DWORD *)buffer = request->send_timeout; *buflen = sizeof(DWORD); return TRUE; case WINHTTP_OPTION_RECEIVE_TIMEOUT: + if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE; + *(DWORD *)buffer = request->receive_timeout; *buflen = sizeof(DWORD); return TRUE; case WINHTTP_OPTION_RECEIVE_RESPONSE_TIMEOUT: + if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE; + *(DWORD *)buffer = request->receive_response_timeout; *buflen = sizeof(DWORD); return TRUE; case WINHTTP_OPTION_USERNAME: - str_to_buffer( buffer, request->connect->username, buflen ); - return TRUE; + return return_string_option( buffer, request->connect->username, buflen ); case WINHTTP_OPTION_PASSWORD: - str_to_buffer( buffer, request->connect->password, buflen ); - return TRUE; + return return_string_option( buffer, request->connect->password, buflen ); case WINHTTP_OPTION_PROXY_USERNAME: - str_to_buffer( buffer, request->connect->session->proxy_username, buflen ); - return TRUE; + return return_string_option( buffer, request->connect->session->proxy_username, buflen ); case WINHTTP_OPTION_PROXY_PASSWORD: - str_to_buffer( buffer, request->connect->session->proxy_password, buflen ); + return return_string_option( buffer, request->connect->session->proxy_password, buflen ); + + case WINHTTP_OPTION_MAX_HTTP_AUTOMATIC_REDIRECTS: + if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE; + + *(DWORD *)buffer = request->max_redirects; + *buflen = sizeof(DWORD); return TRUE; + case WINHTTP_OPTION_HTTP_PROTOCOL_USED: + if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE; + + FIXME("WINHTTP_OPTION_HTTP_PROTOCOL_USED\n"); + *(DWORD *)buffer = 0; + *buflen = sizeof(DWORD); + return TRUE; + + case WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE: + if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE; + + *(DWORD *)buffer = request->websocket_receive_buffer_size; + *buflen = sizeof(DWORD); + return TRUE; + + case WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE: + if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE; + + *(DWORD *)buffer = request->websocket_set_send_buffer_size; + *buflen = sizeof(DWORD); + return TRUE; + + case WINHTTP_OPTION_URL: + { + WCHAR *url; + BOOL ret; + + if (!(url = build_url( request ))) return FALSE; + ret = return_string_option( buffer, url, buflen ); + free( url ); + return ret; + } + default: - FIXME("unimplemented option %u\n", option); + FIXME( "unimplemented option %lu\n", option ); SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } @@ -876,7 +972,7 @@ static BOOL request_query_option( struct object_header *hdr, DWORD option, void static WCHAR *buffer_to_str( WCHAR *buffer, DWORD buflen ) { WCHAR *ret; - if ((ret = heap_alloc( (buflen + 1) * sizeof(WCHAR)))) + if ((ret = malloc( (buflen + 1) * sizeof(WCHAR)))) { memcpy( ret, buffer, buflen * sizeof(WCHAR) ); ret[buflen] = 0; @@ -896,7 +992,7 @@ static BOOL request_set_option( struct object_header *hdr, DWORD option, void *b { WINHTTP_PROXY_INFO *pi = buffer; - FIXME("%u %s %s\n", pi->dwAccessType, debugstr_w(pi->lpszProxy), debugstr_w(pi->lpszProxyBypass)); + FIXME( "%lu %s %s\n", pi->dwAccessType, debugstr_w(pi->lpszProxy), debugstr_w(pi->lpszProxyBypass) ); return TRUE; } case WINHTTP_OPTION_DISABLE_FEATURE: @@ -910,7 +1006,7 @@ static BOOL request_set_option( struct object_header *hdr, DWORD option, void *b } disable = *(DWORD *)buffer; - TRACE("0x%x\n", disable); + TRACE( "%#lx\n", disable ); hdr->disable_flags |= disable; return TRUE; } @@ -925,7 +1021,7 @@ static BOOL request_set_option( struct object_header *hdr, DWORD option, void *b } policy = *(DWORD *)buffer; - TRACE("0x%x\n", policy); + TRACE( "%#lx\n", policy ); hdr->logon_policy = policy; return TRUE; } @@ -940,7 +1036,7 @@ static BOOL request_set_option( struct object_header *hdr, DWORD option, void *b } policy = *(DWORD *)buffer; - TRACE("0x%x\n", policy); + TRACE( "%#lx\n", policy ); hdr->redirect_policy = policy; return TRUE; } @@ -958,7 +1054,7 @@ static BOOL request_set_option( struct object_header *hdr, DWORD option, void *b return FALSE; } flags = *(DWORD *)buffer; - TRACE("0x%x\n", flags); + TRACE( "%#lx\n", flags ); if (flags && (flags & ~accepted)) { SetLastError( ERROR_INVALID_PARAMETER ); @@ -991,7 +1087,7 @@ static BOOL request_set_option( struct object_header *hdr, DWORD option, void *b { struct connect *connect = request->connect; - heap_free( connect->username ); + free( connect->username ); if (!(connect->username = buffer_to_str( buffer, buflen ))) return FALSE; return TRUE; } @@ -999,7 +1095,7 @@ static BOOL request_set_option( struct object_header *hdr, DWORD option, void *b { struct connect *connect = request->connect; - heap_free( connect->password ); + free( connect->password ); if (!(connect->password = buffer_to_str( buffer, buflen ))) return FALSE; return TRUE; } @@ -1007,7 +1103,7 @@ static BOOL request_set_option( struct object_header *hdr, DWORD option, void *b { struct session *session = request->connect->session; - heap_free( session->proxy_username ); + free( session->proxy_username ); if (!(session->proxy_username = buffer_to_str( buffer, buflen ))) return FALSE; return TRUE; } @@ -1015,7 +1111,7 @@ static BOOL request_set_option( struct object_header *hdr, DWORD option, void *b { struct session *session = request->connect->session; - heap_free( session->proxy_password ); + free( session->proxy_password ); if (!(session->proxy_password = buffer_to_str( buffer, buflen ))) return FALSE; return TRUE; } @@ -1033,7 +1129,7 @@ static BOOL request_set_option( struct object_header *hdr, DWORD option, void *b CertFreeCertificateContext( request->client_cert ); request->client_cert = NULL; } - else if (buflen >= sizeof(cert)) + else if (buflen >= sizeof(*cert)) { if (!(cert = CertDuplicateCertificateContext( buffer ))) return FALSE; CertFreeCertificateContext( request->client_cert ); @@ -1066,12 +1162,76 @@ static BOOL request_set_option( struct object_header *hdr, DWORD option, void *b return FALSE; } + case WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET: + request->flags |= REQUEST_FLAG_WEBSOCKET_UPGRADE; + return TRUE; + case WINHTTP_OPTION_CONNECT_RETRIES: FIXME("WINHTTP_OPTION_CONNECT_RETRIES\n"); return TRUE; + case WINHTTP_OPTION_MAX_HTTP_AUTOMATIC_REDIRECTS: + if (buflen == sizeof(DWORD)) + { + request->max_redirects = *(DWORD *)buffer; + SetLastError(NO_ERROR); + return TRUE; + } + + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + + case WINHTTP_OPTION_MAX_RESPONSE_HEADER_SIZE: + FIXME("WINHTTP_OPTION_MAX_RESPONSE_HEADER_SIZE\n"); + return TRUE; + + case WINHTTP_OPTION_MAX_RESPONSE_DRAIN_SIZE: + FIXME("WINHTTP_OPTION_MAX_RESPONSE_DRAIN_SIZE\n"); + return TRUE; + + case WINHTTP_OPTION_ENABLE_HTTP_PROTOCOL: + if (buflen == sizeof(DWORD)) + { + FIXME( "WINHTTP_OPTION_ENABLE_HTTP_PROTOCOL %#lx\n", *(DWORD *)buffer ); + return TRUE; + } + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + + case WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE: + { + DWORD buffer_size; + + if (buflen != sizeof(buffer_size)) + { + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + return FALSE; + } + + buffer_size = *(DWORD *)buffer; + WARN( "Setting websocket receive buffer size currently has not effct, size %lu\n", buffer_size ); + request->websocket_receive_buffer_size = buffer_size; + return TRUE; + } + + case WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE: + { + DWORD buffer_size; + + if (buflen != sizeof(buffer_size)) + { + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + return FALSE; + } + + buffer_size = *(DWORD *)buffer; + request->websocket_set_send_buffer_size = buffer_size; + TRACE( "Websocket send buffer size %lu.\n", buffer_size); + return TRUE; + } + default: - FIXME("unimplemented option %u\n", option); + FIXME( "unimplemented option %lu\n", option ); SetLastError( ERROR_WINHTTP_INVALID_OPTION ); return FALSE; } @@ -1079,6 +1239,7 @@ static BOOL request_set_option( struct object_header *hdr, DWORD option, void *b static const struct object_vtbl request_vtbl = { + NULL, request_destroy, request_query_option, request_set_option @@ -1086,13 +1247,12 @@ static const struct object_vtbl request_vtbl = static BOOL add_accept_types_header( struct request *request, const WCHAR **types ) { - static const WCHAR acceptW[] = {'A','c','c','e','p','t',0}; static const DWORD flags = WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA; if (!types) return TRUE; while (*types) { - if (!process_header( request, acceptW, *types, flags, TRUE )) return FALSE; + if (process_header( request, L"Accept", *types, flags, TRUE )) return FALSE; types++; } return TRUE; @@ -1100,13 +1260,13 @@ static BOOL add_accept_types_header( struct request *request, const WCHAR **type static WCHAR *get_request_path( const WCHAR *object ) { - int len = object ? strlenW(object) : 0; + int len = object ? lstrlenW(object) : 0; WCHAR *p, *ret; if (!object || object[0] != '/') len++; - if (!(p = ret = heap_alloc( (len + 1) * sizeof(WCHAR) ))) return NULL; + if (!(p = ret = malloc( (len + 1) * sizeof(WCHAR) ))) return NULL; if (!object || object[0] != '/') *p++ = '/'; - if (object) strcpyW( p, object ); + if (object) lstrcpyW( p, object ); ret[len] = 0; return ret; } @@ -1114,15 +1274,15 @@ static WCHAR *get_request_path( const WCHAR *object ) /*********************************************************************** * WinHttpOpenRequest (winhttp.@) */ -HINTERNET WINAPI WinHttpOpenRequest( HINTERNET hconnect, LPCWSTR verb, LPCWSTR object, LPCWSTR version, - LPCWSTR referrer, LPCWSTR *types, DWORD flags ) +HINTERNET WINAPI WinHttpOpenRequest( HINTERNET hconnect, const WCHAR *verb, const WCHAR *object, const WCHAR *version, + const WCHAR *referrer, const WCHAR **types, DWORD flags ) { struct request *request; struct connect *connect; HINTERNET hrequest = NULL; - TRACE("%p, %s, %s, %s, %s, %p, 0x%08x\n", hconnect, debugstr_w(verb), debugstr_w(object), - debugstr_w(version), debugstr_w(referrer), types, flags); + TRACE( "%p, %s, %s, %s, %s, %p, %#lx\n", hconnect, debugstr_w(verb), debugstr_w(object), + debugstr_w(version), debugstr_w(referrer), types, flags ); if (types && TRACE_ON(winhttp)) { @@ -1142,7 +1302,7 @@ HINTERNET WINAPI WinHttpOpenRequest( HINTERNET hconnect, LPCWSTR verb, LPCWSTR o SetLastError( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE ); return NULL; } - if (!(request = heap_alloc_zero( sizeof(struct request) ))) + if (!(request = calloc( 1, sizeof(*request) ))) { release_object( &connect->hdr ); return NULL; @@ -1155,31 +1315,34 @@ HINTERNET WINAPI WinHttpOpenRequest( HINTERNET hconnect, LPCWSTR verb, LPCWSTR o request->hdr.notify_mask = connect->hdr.notify_mask; request->hdr.context = connect->hdr.context; request->hdr.redirect_policy = connect->hdr.redirect_policy; - list_init( &request->hdr.children ); - list_init( &request->task_queue ); + init_queue( &request->queue ); addref_object( &connect->hdr ); request->connect = connect; - list_add_head( &connect->hdr.children, &request->hdr.entry ); request->resolve_timeout = connect->session->resolve_timeout; request->connect_timeout = connect->session->connect_timeout; request->send_timeout = connect->session->send_timeout; request->receive_timeout = connect->session->receive_timeout; request->receive_response_timeout = connect->session->receive_response_timeout; + request->max_redirects = 10; + request->websocket_receive_buffer_size = connect->session->websocket_receive_buffer_size; + request->websocket_send_buffer_size = connect->session->websocket_send_buffer_size; + request->websocket_set_send_buffer_size = request->websocket_send_buffer_size; + request->read_reply_status = ERROR_WINHTTP_INCORRECT_HANDLE_STATE; - if (!verb || !verb[0]) verb = getW; - if (!(request->verb = strdupW( verb ))) goto end; + if (!verb || !verb[0]) verb = L"GET"; + if (!(request->verb = wcsdup( verb ))) goto end; if (!(request->path = get_request_path( object ))) goto end; - if (!version || !version[0]) version = http1_1; - if (!(request->version = strdupW( version ))) goto end; + if (!version || !version[0]) version = L"HTTP/1.1"; + if (!(request->version = wcsdup( version ))) goto end; if (!(add_accept_types_header( request, types ))) goto end; - if (!(hrequest = alloc_handle( &request->hdr ))) goto end; - request->hdr.handle = hrequest; - - send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, &hrequest, sizeof(hrequest) ); + if ((hrequest = alloc_handle( &request->hdr ))) + { + send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, &hrequest, sizeof(hrequest) ); + } end: release_object( &request->hdr ); @@ -1221,14 +1384,18 @@ static BOOL query_option( struct object_header *hdr, DWORD option, void *buffer, switch (option) { + case WINHTTP_OPTION_WORKER_THREAD_COUNT: + { + FIXME( "WINHTTP_OPTION_WORKER_THREAD_COUNT semi-stub.\n" ); + if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE; + + *(DWORD *)buffer = 0; + *buflen = sizeof(DWORD); + return TRUE; + } case WINHTTP_OPTION_CONTEXT_VALUE: { - if (!buffer || *buflen < sizeof(DWORD_PTR)) - { - *buflen = sizeof(DWORD_PTR); - SetLastError( ERROR_INSUFFICIENT_BUFFER ); - return FALSE; - } + if (!validate_buffer( buffer, buflen, sizeof(DWORD_PTR) )) return FALSE; *(DWORD_PTR *)buffer = hdr->context; *buflen = sizeof(DWORD_PTR); @@ -1238,7 +1405,7 @@ static BOOL query_option( struct object_header *hdr, DWORD option, void *buffer, if (hdr->vtbl->query_option) ret = hdr->vtbl->query_option( hdr, option, buffer, buflen ); else { - FIXME("unimplemented option %u\n", option); + FIXME( "unimplemented option %lu\n", option ); SetLastError( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE ); return FALSE; } @@ -1250,12 +1417,12 @@ static BOOL query_option( struct object_header *hdr, DWORD option, void *buffer, /*********************************************************************** * WinHttpQueryOption (winhttp.@) */ -BOOL WINAPI WinHttpQueryOption( HINTERNET handle, DWORD option, LPVOID buffer, LPDWORD buflen ) +BOOL WINAPI WinHttpQueryOption( HINTERNET handle, DWORD option, void *buffer, DWORD *buflen ) { BOOL ret = FALSE; struct object_header *hdr; - TRACE("%p, %u, %p, %p\n", handle, option, buffer, buflen); + TRACE( "%p, %lu, %p, %p\n", handle, option, buffer, buflen ); if (!(hdr = grab_object( handle ))) { @@ -1297,7 +1464,7 @@ static BOOL set_option( struct object_header *hdr, DWORD option, void *buffer, D if (hdr->vtbl->set_option) ret = hdr->vtbl->set_option( hdr, option, buffer, buflen ); else { - FIXME("unimplemented option %u\n", option); + FIXME( "unimplemented option %lu\n", option ); SetLastError( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE ); return FALSE; } @@ -1309,12 +1476,12 @@ static BOOL set_option( struct object_header *hdr, DWORD option, void *buffer, D /*********************************************************************** * WinHttpSetOption (winhttp.@) */ -BOOL WINAPI WinHttpSetOption( HINTERNET handle, DWORD option, LPVOID buffer, DWORD buflen ) +BOOL WINAPI WinHttpSetOption( HINTERNET handle, DWORD option, void *buffer, DWORD buflen ) { BOOL ret = FALSE; struct object_header *hdr; - TRACE("%p, %u, %p, %u\n", handle, option, buffer, buflen); + TRACE( "%p, %lu, %p, %lu\n", handle, option, buffer, buflen ); if (!(hdr = grab_object( handle ))) { @@ -1329,6 +1496,80 @@ BOOL WINAPI WinHttpSetOption( HINTERNET handle, DWORD option, LPVOID buffer, DWO return ret; } +static IP_ADAPTER_ADDRESSES *get_adapters(void) +{ + ULONG err, size = 1024, flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | + GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME; + IP_ADAPTER_ADDRESSES *tmp, *ret; + + if (!(ret = malloc( size ))) return NULL; + err = GetAdaptersAddresses( AF_UNSPEC, flags, NULL, ret, &size ); + while (err == ERROR_BUFFER_OVERFLOW) + { + if (!(tmp = realloc( ret, size ))) break; + ret = tmp; + err = GetAdaptersAddresses( AF_UNSPEC, flags, NULL, ret, &size ); + } + if (err == ERROR_SUCCESS) return ret; + free( ret ); + return NULL; +} + +static WCHAR *detect_autoproxyconfig_url_dhcp(void) +{ + IP_ADAPTER_ADDRESSES *adapters, *ptr; + DHCPCAPI_PARAMS_ARRAY send_params, recv_params; + DHCPCAPI_PARAMS param; + WCHAR name[MAX_ADAPTER_NAME_LENGTH + 1], *ret = NULL; + DWORD err, size; + BYTE *tmp, *buf = NULL; + + if (!(adapters = get_adapters())) return NULL; + + memset( &send_params, 0, sizeof(send_params) ); + memset( ¶m, 0, sizeof(param) ); + param.OptionId = OPTION_MSFT_IE_PROXY; + recv_params.nParams = 1; + recv_params.Params = ¶m; + + for (ptr = adapters; ptr; ptr = ptr->Next) + { + MultiByteToWideChar( CP_ACP, 0, ptr->AdapterName, -1, name, ARRAY_SIZE(name) ); + TRACE( "adapter '%s' type %lu dhcpv4 enabled %d\n", wine_dbgstr_w(name), ptr->IfType, ptr->Dhcpv4Enabled ); + + if (ptr->IfType == IF_TYPE_SOFTWARE_LOOPBACK) continue; + /* FIXME: also skip adapters where DHCP is disabled */ + + size = 256; + if (!(buf = malloc( size ))) goto done; + err = DhcpRequestParams( DHCPCAPI_REQUEST_SYNCHRONOUS, NULL, name, NULL, send_params, recv_params, + buf, &size, NULL ); + while (err == ERROR_MORE_DATA) + { + if (!(tmp = realloc( buf, size ))) goto done; + buf = tmp; + err = DhcpRequestParams( DHCPCAPI_REQUEST_SYNCHRONOUS, NULL, name, NULL, send_params, recv_params, + buf, &size, NULL ); + } + if (err == ERROR_SUCCESS && param.nBytesData) + { + int len = MultiByteToWideChar( CP_ACP, 0, (const char *)param.Data, param.nBytesData, NULL, 0 ); + if ((ret = malloc( (len + 1) * sizeof(WCHAR) ))) + { + MultiByteToWideChar( CP_ACP, 0, (const char *)param.Data, param.nBytesData, ret, len ); + ret[len] = 0; + } + TRACE("returning %s\n", debugstr_w(ret)); + break; + } + } + +done: + free( buf ); + free( adapters ); + return ret; +} + static char *get_computer_name( COMPUTER_NAME_FORMAT format ) { char *ret; @@ -1336,10 +1577,10 @@ static char *get_computer_name( COMPUTER_NAME_FORMAT format ) GetComputerNameExA( format, NULL, &size ); if (GetLastError() != ERROR_MORE_DATA) return NULL; - if (!(ret = heap_alloc( size ))) return NULL; + if (!(ret = malloc( size ))) return NULL; if (!GetComputerNameExA( format, ret, &size )) { - heap_free( ret ); + free( ret ); return NULL; } return ret; @@ -1350,7 +1591,7 @@ 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 (!_strnicmp( domain + len_domain - len_suffix, suffix, -1 )) return TRUE; + if (!stricmp( domain + len_domain - len_suffix, suffix )) return TRUE; return FALSE; } @@ -1361,8 +1602,6 @@ static int reverse_lookup( const struct addrinfo *ai, char *hostname, size_t len static WCHAR *build_wpad_url( const char *hostname, const struct addrinfo *ai ) { - static const WCHAR httpW[] = {'h','t','t','p',':','/','/',0}; - static const WCHAR wpadW[] = {'/','w','p','a','d','.','d','a','t',0}; char name[NI_MAXHOST]; WCHAR *ret, *p; int len; @@ -1372,142 +1611,97 @@ static WCHAR *build_wpad_url( const char *hostname, const struct addrinfo *ai ) if (!reverse_lookup( ai, name, sizeof(name) )) hostname = name; - len = strlenW( httpW ) + strlen( hostname ) + strlenW( wpadW ); + len = lstrlenW( L"http://" ) + strlen( hostname ) + lstrlenW( L"/wpad.dat" ); if (!(ret = p = GlobalAlloc( 0, (len + 1) * sizeof(WCHAR) ))) return NULL; - strcpyW( p, httpW ); - p += strlenW( httpW ); + lstrcpyW( p, L"http://" ); + p += lstrlenW( L"http://" ); while (*hostname) { *p++ = *hostname++; } - strcpyW( p, wpadW ); + lstrcpyW( p, L"/wpad.dat" ); return ret; } -static BOOL get_system_proxy_autoconfig_url( char *buf, DWORD buflen ) +static WCHAR *detect_autoproxyconfig_url_dns(void) { -#if defined(MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 - CFDictionaryRef settings = CFNetworkCopySystemProxySettings(); - const void *ref; - BOOL ret = FALSE; + char *fqdn, *domain, *p; + WCHAR *ret = NULL; - if (!settings) return FALSE; + if (!(fqdn = get_computer_name( ComputerNamePhysicalDnsFullyQualified ))) return NULL; + if (!(domain = get_computer_name( ComputerNamePhysicalDnsDomain ))) + { + free( fqdn ); + return NULL; + } + p = fqdn; + while ((p = strchr( p, '.' )) && is_domain_suffix( p + 1, domain )) + { + char *name; + struct addrinfo *ai, hints; + int res; - if (!(ref = CFDictionaryGetValue( settings, kCFNetworkProxiesProxyAutoConfigURLString ))) - { - CFRelease( settings ); - return FALSE; + if (!(name = malloc( sizeof("wpad") + strlen(p) ))) + { + free( fqdn ); + free( domain ); + return NULL; + } + strcpy( name, "wpad" ); + strcat( name, p ); + memset( &hints, 0, sizeof(hints) ); + hints.ai_flags = AI_ALL | AI_DNS_ONLY; + hints.ai_family = AF_UNSPEC; + res = getaddrinfo( name, NULL, &hints, &ai ); + if (!res) + { + ret = build_wpad_url( name, ai ); + freeaddrinfo( ai ); + if (ret) + { + TRACE("returning %s\n", debugstr_w(ret)); + free( name ); + break; + } + } + free( name ); + p++; } - if (CFStringGetCString( ref, buf, buflen, kCFStringEncodingASCII )) - { - TRACE( "returning %s\n", debugstr_a(buf) ); - ret = TRUE; - } - CFRelease( settings ); + free( domain ); + free( fqdn ); return ret; -#else - static BOOL first = TRUE; - if (first) - { - FIXME( "no support on this platform\n" ); - first = FALSE; - } - else - TRACE( "no support on this platform\n" ); - return FALSE; -#endif } -#define INTERNET_MAX_URL_LENGTH 2084 - /*********************************************************************** * WinHttpDetectAutoProxyConfigUrl (winhttp.@) */ -BOOL WINAPI WinHttpDetectAutoProxyConfigUrl( DWORD flags, LPWSTR *url ) +BOOL WINAPI WinHttpDetectAutoProxyConfigUrl( DWORD flags, WCHAR **url ) { - BOOL ret = FALSE; - char system_url[INTERNET_MAX_URL_LENGTH + 1]; - - TRACE("0x%08x, %p\n", flags, url); + TRACE( "%#lx, %p\n", flags, url ); if (!flags || !url) { SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } - if (get_system_proxy_autoconfig_url( system_url, sizeof(system_url) )) - { - WCHAR *urlW; - - if (!(urlW = strdupAW( system_url ))) return FALSE; - *url = urlW; - SetLastError( ERROR_SUCCESS ); - return TRUE; - } + *url = NULL; if (flags & WINHTTP_AUTO_DETECT_TYPE_DHCP) { - static int fixme_shown; - if (!fixme_shown++) FIXME("discovery via DHCP not supported\n"); + *url = detect_autoproxyconfig_url_dhcp(); } if (flags & WINHTTP_AUTO_DETECT_TYPE_DNS_A) { - 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 ); - if (!res) - { - *url = build_wpad_url( name, ai ); - freeaddrinfo( ai ); - if (*url) - { - TRACE("returning %s\n", debugstr_w(*url)); - heap_free( name ); - ret = TRUE; - break; - } - } - heap_free( name ); - p++; - } - heap_free( domain ); - heap_free( fqdn ); + if (!*url) *url = detect_autoproxyconfig_url_dns(); } - if (!ret) + if (!*url) { SetLastError( ERROR_WINHTTP_AUTODETECTION_FAILED ); - *url = NULL; + return FALSE; } - else SetLastError( ERROR_SUCCESS ); - return ret; + SetLastError( ERROR_SUCCESS ); + return TRUE; } -static const WCHAR Connections[] = { - 'S','o','f','t','w','a','r','e','\\', - 'M','i','c','r','o','s','o','f','t','\\', - 'W','i','n','d','o','w','s','\\', - 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', - 'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s','\\', - 'C','o','n','n','e','c','t','i','o','n','s',0 }; -static const WCHAR WinHttpSettings[] = { - 'W','i','n','H','t','t','p','S','e','t','t','i','n','g','s',0 }; +static const WCHAR path_connections[] = + L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Connections"; + static const DWORD WINHTTP_SETTINGS_MAGIC = 0x18; static const DWORD WININET_SETTINGS_MAGIC = 0x46; static const DWORD PROXY_TYPE_DIRECT = 1; @@ -1539,20 +1733,20 @@ BOOL WINAPI WinHttpGetDefaultProxyConfiguration( WINHTTP_PROXY_INFO *info ) LONG l; HKEY key; BOOL got_from_reg = FALSE, direct = TRUE; - char *envproxy; + WCHAR *envproxy; TRACE("%p\n", info); - l = RegOpenKeyExW( HKEY_LOCAL_MACHINE, Connections, 0, KEY_READ, &key ); + l = RegOpenKeyExW( HKEY_LOCAL_MACHINE, path_connections, 0, KEY_READ, &key ); if (!l) { DWORD type, size = 0; - l = RegQueryValueExW( key, WinHttpSettings, NULL, &type, NULL, &size ); + l = RegQueryValueExW( key, L"WinHttpSettings", NULL, &type, NULL, &size ); if (!l && type == REG_BINARY && size >= sizeof(struct connection_settings_header) + 2 * sizeof(DWORD)) { - BYTE *buf = heap_alloc( size ); + BYTE *buf = malloc( size ); if (buf) { @@ -1560,7 +1754,7 @@ BOOL WINAPI WinHttpGetDefaultProxyConfiguration( WINHTTP_PROXY_INFO *info ) (struct connection_settings_header *)buf; DWORD *len = (DWORD *)(hdr + 1); - l = RegQueryValueExW( key, WinHttpSettings, NULL, NULL, buf, + l = RegQueryValueExW( key, L"WinHttpSettings", NULL, NULL, buf, &size ); if (!l && hdr->magic == WINHTTP_SETTINGS_MAGIC && hdr->unknown == 0) @@ -1610,42 +1804,35 @@ BOOL WINAPI WinHttpGetDefaultProxyConfiguration( WINHTTP_PROXY_INFO *info ) } } } - heap_free( buf ); + free( buf ); } } RegCloseKey( key ); } - if (!got_from_reg && (envproxy = getenv( "http_proxy" ))) + if (!got_from_reg && (envproxy = _wgetenv( L"http_proxy" ))) { - char *colon, *http_proxy = NULL; + WCHAR *colon, *http_proxy = NULL; - if (!(colon = strchr( envproxy, ':' ))) http_proxy = envproxy; + if (!(colon = wcschr( envproxy, ':' ))) http_proxy = envproxy; else { if (*(colon + 1) == '/' && *(colon + 2) == '/') { /* It's a scheme, check that it's http */ - if (!strncmp( envproxy, "http://", 7 )) http_proxy = envproxy + 7; - else WARN("unsupported scheme in $http_proxy: %s\n", envproxy); + if (!wcsncmp( envproxy, L"http://", 7 )) http_proxy = envproxy + 7; + else WARN("unsupported scheme in $http_proxy: %s\n", debugstr_w(envproxy)); } else http_proxy = envproxy; } if (http_proxy && http_proxy[0]) { - WCHAR *http_proxyW; - int len; - - len = MultiByteToWideChar( CP_UNIXCP, 0, http_proxy, -1, NULL, 0 ); - if ((http_proxyW = GlobalAlloc( 0, len * sizeof(WCHAR)))) - { - MultiByteToWideChar( CP_UNIXCP, 0, http_proxy, -1, http_proxyW, len ); - direct = FALSE; - info->dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY; - info->lpszProxy = http_proxyW; - info->lpszProxyBypass = NULL; - TRACE("http proxy (from environment) = %s\n", debugstr_w(info->lpszProxy)); - } + direct = FALSE; + info->dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY; + info->lpszProxy = GlobalAlloc( 0, (lstrlenW(http_proxy) + 1) * sizeof(WCHAR) ); + wcscpy( info->lpszProxy, http_proxy ); + info->lpszProxyBypass = NULL; + TRACE("http proxy (from environment) = %s\n", debugstr_w(info->lpszProxy)); } } if (direct) @@ -1663,8 +1850,6 @@ BOOL WINAPI WinHttpGetDefaultProxyConfiguration( WINHTTP_PROXY_INFO *info ) */ BOOL WINAPI WinHttpGetIEProxyConfigForCurrentUser( WINHTTP_CURRENT_USER_IE_PROXY_CONFIG *config ) { - static const WCHAR settingsW[] = - {'D','e','f','a','u','l','t','C','o','n','n','e','c','t','i','o','n','S','e','t','t','i','n','g','s',0}; HKEY hkey = NULL; struct connection_settings_header *hdr = NULL; DWORD type, offset, len, size = 0; @@ -1680,15 +1865,15 @@ BOOL WINAPI WinHttpGetIEProxyConfigForCurrentUser( WINHTTP_CURRENT_USER_IE_PROXY memset( config, 0, sizeof(*config) ); config->fAutoDetect = TRUE; - if (RegOpenKeyExW( HKEY_CURRENT_USER, Connections, 0, KEY_READ, &hkey ) || - RegQueryValueExW( hkey, settingsW, NULL, &type, NULL, &size ) || + if (RegOpenKeyExW( HKEY_CURRENT_USER, path_connections, 0, KEY_READ, &hkey ) || + RegQueryValueExW( hkey, L"DefaultConnectionSettings", NULL, &type, NULL, &size ) || type != REG_BINARY || size < sizeof(struct connection_settings_header)) { ret = TRUE; goto done; } - if (!(hdr = heap_alloc( size ))) goto done; - if (RegQueryValueExW( hkey, settingsW, NULL, &type, (BYTE *)hdr, &size ) || + if (!(hdr = malloc( size ))) goto done; + if (RegQueryValueExW( hkey, L"DefaultConnectionSettings", NULL, &type, (BYTE *)hdr, &size ) || hdr->magic != WININET_SETTINGS_MAGIC) { ret = TRUE; @@ -1727,7 +1912,7 @@ BOOL WINAPI WinHttpGetIEProxyConfigForCurrentUser( WINHTTP_CURRENT_USER_IE_PROXY done: RegCloseKey( hkey ); - heap_free( hdr ); + free( hdr ); if (!ret) { GlobalFree( config->lpszAutoConfigUrl ); @@ -1761,7 +1946,17 @@ static BOOL parse_script_result( const char *result, WINHTTP_PROXY_INFO *info ) p += 5; while (*p == ' ') p++; if (!*p || *p == ';') return TRUE; - if (!(info->lpszProxy = q = strdupAW( p ))) return FALSE; + if (!(q = strdupAW( p ))) return FALSE; + len = wcslen( q ); + info->lpszProxy = GlobalAlloc( 0, (len + 1) * sizeof(WCHAR) ); + if (!info->lpszProxy) + { + free( q ); + return FALSE; + } + memcpy( info->lpszProxy, q, (len + 1) * sizeof(WCHAR) ); + free( q ); + q = info->lpszProxy; info->dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY; for (; *q; q++) { @@ -1775,39 +1970,88 @@ static BOOL parse_script_result( const char *result, WINHTTP_PROXY_INFO *info ) return TRUE; } +static SRWLOCK cache_lock = SRWLOCK_INIT; +static DWORD cached_script_size; +static ULONGLONG cache_update_time; +static char *cached_script; +static WCHAR *cached_url; + +static BOOL get_cached_script( const WCHAR *url, char **buffer, DWORD *out_size ) +{ + BOOL ret = FALSE; + + *buffer = NULL; + *out_size = 0; + + AcquireSRWLockExclusive( &cache_lock ); + if (cached_url && !wcscmp( cached_url, url ) && GetTickCount64() - cache_update_time < 60000) + { + ret = TRUE; + if (cached_script && (*buffer = malloc( cached_script_size ))) + { + memcpy( *buffer, cached_script, cached_script_size ); + *out_size = cached_script_size; + } + } + ReleaseSRWLockExclusive( &cache_lock ); + return ret; +} + +static void cache_script( const WCHAR *url, char *buffer, DWORD size ) +{ + AcquireSRWLockExclusive( &cache_lock ); + free( cached_url ); + free( cached_script ); + cached_script_size = 0; + cached_script = NULL; + + if ((cached_url = wcsdup( url )) && buffer && (cached_script = malloc( size ))) + { + memcpy( cached_script, buffer, size ); + cached_script_size = size; + } + cache_update_time = GetTickCount64(); + ReleaseSRWLockExclusive( &cache_lock ); +} + static char *download_script( const WCHAR *url, DWORD *out_size ) { - static const WCHAR typeW[] = {'*','/','*',0}; - static const WCHAR *acceptW[] = {typeW, NULL}; + static const WCHAR *acceptW[] = {L"*/*", NULL}; HINTERNET ses, con = NULL, req = NULL; WCHAR *hostname; URL_COMPONENTSW uc; DWORD status, size = sizeof(status), offset, to_read, bytes_read, flags = 0; - char *tmp, *buffer = NULL; + char *tmp, *buffer; - *out_size = 0; + if (get_cached_script( url, &buffer, out_size )) + { + TRACE( "Returning cached result.\n" ); + if (!buffer) SetLastError( ERROR_WINHTTP_UNABLE_TO_DOWNLOAD_SCRIPT ); + return buffer; + } memset( &uc, 0, sizeof(uc) ); uc.dwStructSize = sizeof(uc); uc.dwHostNameLength = -1; uc.dwUrlPathLength = -1; if (!WinHttpCrackUrl( url, 0, 0, &uc )) return NULL; - if (!(hostname = heap_alloc( (uc.dwHostNameLength + 1) * sizeof(WCHAR) ))) return NULL; + if (!(hostname = malloc( (uc.dwHostNameLength + 1) * sizeof(WCHAR) ))) return NULL; memcpy( hostname, uc.lpszHostName, uc.dwHostNameLength * sizeof(WCHAR) ); hostname[uc.dwHostNameLength] = 0; if (!(ses = WinHttpOpen( NULL, WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0 ))) goto done; + WinHttpSetTimeouts( ses, 5000, 60000, 30000, 30000 ); 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 (!WinHttpReceiveResponse( req, 0 )) goto done; if (!WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL ) || status != HTTP_STATUS_OK) goto done; size = 4096; - if (!(buffer = heap_alloc( size ))) goto done; + if (!(buffer = malloc( size ))) goto done; to_read = size; offset = 0; for (;;) @@ -1821,7 +2065,7 @@ static char *download_script( const WCHAR *url, DWORD *out_size ) { to_read = size; size *= 2; - if (!(tmp = heap_realloc( buffer, size ))) goto done; + if (!(tmp = realloc( buffer, size ))) goto done; buffer = tmp; } } @@ -1830,7 +2074,8 @@ done: WinHttpCloseHandle( req ); WinHttpCloseHandle( con ); WinHttpCloseHandle( ses ); - heap_free( hostname ); + free( hostname ); + cache_script( url, buffer, *out_size ); if (!buffer) SetLastError( ERROR_WINHTTP_UNABLE_TO_DOWNLOAD_SCRIPT ); return buffer; } @@ -1846,44 +2091,72 @@ BOOL WINAPI InternetDeInitializeAutoProxyDll(LPSTR, DWORD); BOOL WINAPI InternetGetProxyInfo(LPCSTR, DWORD, LPSTR, DWORD, LPSTR *, LPDWORD); BOOL WINAPI InternetInitializeAutoProxyDll(DWORD, LPSTR, LPSTR, void *, struct AUTO_PROXY_SCRIPT_BUFFER *); -static BOOL run_script( char *script, DWORD size, const WCHAR *url, WINHTTP_PROXY_INFO *info ) +#define MAX_SCHEME_LENGTH 32 +static BOOL run_script( char *script, DWORD size, const WCHAR *url, WINHTTP_PROXY_INFO *info, DWORD flags ) { + WCHAR scheme[MAX_SCHEME_LENGTH + 1], buf[MAX_HOST_NAME_LENGTH + 1], *hostname; BOOL ret; - char *result, *urlA; - DWORD len_result; + char *result, *urlA, *hostnameA; + DWORD len, len_scheme, len_hostname; struct AUTO_PROXY_SCRIPT_BUFFER buffer; URL_COMPONENTSW uc; + memset( &uc, 0, sizeof(uc) ); + uc.dwStructSize = sizeof(uc); + uc.dwSchemeLength = -1; + uc.dwHostNameLength = -1; + + if (!WinHttpCrackUrl( url, 0, 0, &uc )) + return FALSE; + + memcpy( scheme, uc.lpszScheme, uc.dwSchemeLength * sizeof(WCHAR) ); + scheme[uc.dwSchemeLength] = 0; + wcslwr( scheme ); + len_scheme = WideCharToMultiByte( CP_ACP, 0, scheme, uc.dwSchemeLength, NULL, 0, NULL, NULL ); + + if (flags & WINHTTP_AUTOPROXY_HOST_LOWERCASE && !(flags & WINHTTP_AUTOPROXY_HOST_KEEPCASE)) + { + memcpy( buf, uc.lpszHostName, uc.dwHostNameLength * sizeof(WCHAR) ); + buf[uc.dwHostNameLength] = 0; + wcslwr( buf ); + hostname = buf; + } + else + { + hostname = uc.lpszHostName; + } + len_hostname = WideCharToMultiByte( CP_ACP, 0, hostname, uc.dwHostNameLength, NULL, 0, NULL, NULL ); + + len = WideCharToMultiByte( CP_ACP, 0, uc.lpszHostName + uc.dwHostNameLength, -1, NULL, 0, NULL, NULL ); + if (!(urlA = malloc( len + len_scheme + len_hostname + 3 ))) return FALSE; + WideCharToMultiByte( CP_ACP, 0, scheme, uc.dwSchemeLength, urlA, len_scheme, NULL, NULL ); + urlA[len_scheme++] = ':'; + urlA[len_scheme++] = '/'; + urlA[len_scheme++] = '/'; + WideCharToMultiByte( CP_ACP, 0, hostname, uc.dwHostNameLength, urlA + len_scheme, len_hostname, NULL, NULL ); + hostnameA = urlA + len_scheme; + WideCharToMultiByte( CP_ACP, 0, uc.lpszHostName + uc.dwHostNameLength, -1, + urlA + len_scheme + len_hostname, len, NULL, NULL ); + buffer.dwStructSize = sizeof(buffer); buffer.lpszScriptBuffer = script; buffer.dwScriptBufferSize = size; - if (!(urlA = strdupWA( url ))) return FALSE; - if (!(ret = InternetInitializeAutoProxyDll( 0, NULL, NULL, NULL, &buffer ))) + if (!InternetInitializeAutoProxyDll( 0, NULL, NULL, NULL, &buffer )) { - heap_free( urlA ); + free( urlA ); return FALSE; } - memset( &uc, 0, sizeof(uc) ); - uc.dwStructSize = sizeof(uc); - uc.dwHostNameLength = -1; - - if (WinHttpCrackUrl( url, 0, 0, &uc )) + if ((ret = InternetGetProxyInfo( urlA, strlen(urlA), hostnameA, len_hostname, &result, &len ))) { - char *hostnameA = strdupWA_sized( uc.lpszHostName, uc.dwHostNameLength ); - - if ((ret = InternetGetProxyInfo( urlA, strlen(urlA), - hostnameA, strlen(hostnameA), &result, &len_result ))) - { - ret = parse_script_result( result, info ); - heap_free( result ); - } - - heap_free( hostnameA ); + ret = parse_script_result( result, info ); + free( result ); } - heap_free( urlA ); - return InternetDeInitializeAutoProxyDll( NULL, 0 ); + + free( urlA ); + InternetDeInitializeAutoProxyDll( NULL, 0 ); + return ret; } /*********************************************************************** @@ -1892,10 +2165,9 @@ static BOOL run_script( char *script, DWORD size, const WCHAR *url, WINHTTP_PROX BOOL WINAPI WinHttpGetProxyForUrl( HINTERNET hsession, LPCWSTR url, WINHTTP_AUTOPROXY_OPTIONS *options, WINHTTP_PROXY_INFO *info ) { - WCHAR *detected_pac_url = NULL; - const WCHAR *pac_url; + WCHAR *pac_url; struct session *session; - char *script; + char *script = NULL; DWORD size; BOOL ret = FALSE; @@ -1915,28 +2187,29 @@ BOOL WINAPI WinHttpGetProxyForUrl( HINTERNET hsession, LPCWSTR url, WINHTTP_AUTO 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))) + (options->dwFlags & WINHTTP_AUTOPROXY_CONFIG_URL && !options->lpszAutoConfigUrl)) { release_object( &session->hdr ); SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } + if (options->dwFlags & WINHTTP_AUTOPROXY_AUTO_DETECT && - !WinHttpDetectAutoProxyConfigUrl( options->dwAutoDetectFlags, &detected_pac_url )) - goto done; - - if (options->dwFlags & WINHTTP_AUTOPROXY_CONFIG_URL) pac_url = options->lpszAutoConfigUrl; - else pac_url = detected_pac_url; - - if ((script = download_script( pac_url, &size ))) + WinHttpDetectAutoProxyConfigUrl( options->dwAutoDetectFlags, &pac_url )) { - ret = run_script( script, size, url, info ); - heap_free( script ); + script = download_script( pac_url, &size ); + GlobalFree( pac_url ); + } + + if (!script && options->dwFlags & WINHTTP_AUTOPROXY_CONFIG_URL) + script = download_script( options->lpszAutoConfigUrl, &size ); + + if (script) + { + ret = run_script( script, size, url, info, options->dwFlags ); + free( script ); } -done: - GlobalFree( detected_pac_url ); release_object( &session->hdr ); if (ret) SetLastError( ERROR_SUCCESS ); return ret; @@ -1991,7 +2264,7 @@ BOOL WINAPI WinHttpSetDefaultProxyConfiguration( WINHTTP_PROXY_INFO *info ) return FALSE; } - l = RegCreateKeyExW( HKEY_LOCAL_MACHINE, Connections, 0, NULL, 0, + l = RegCreateKeyExW( HKEY_LOCAL_MACHINE, path_connections, 0, NULL, 0, KEY_WRITE, NULL, &key, NULL ); if (!l) { @@ -2000,12 +2273,11 @@ BOOL WINAPI WinHttpSetDefaultProxyConfiguration( WINHTTP_PROXY_INFO *info ) if (info->dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY) { - size += strlenW( info->lpszProxy ); + size += lstrlenW( info->lpszProxy ); if (info->lpszProxyBypass) - size += strlenW( info->lpszProxyBypass ); + size += lstrlenW( info->lpszProxyBypass ); } - buf = heap_alloc( size ); - if (buf) + if ((buf = malloc( size ))) { struct connection_settings_header *hdr = (struct connection_settings_header *)buf; @@ -2018,14 +2290,14 @@ BOOL WINAPI WinHttpSetDefaultProxyConfiguration( WINHTTP_PROXY_INFO *info ) BYTE *dst; hdr->flags = PROXY_TYPE_PROXY; - *len++ = strlenW( info->lpszProxy ); + *len++ = lstrlenW( info->lpszProxy ); for (dst = (BYTE *)len, src = info->lpszProxy; *src; src++, dst++) *dst = *src; len = (DWORD *)dst; if (info->lpszProxyBypass) { - *len++ = strlenW( info->lpszProxyBypass ); + *len++ = lstrlenW( info->lpszProxyBypass ); for (dst = (BYTE *)len, src = info->lpszProxyBypass; *src; src++, dst++) *dst = *src; @@ -2039,10 +2311,10 @@ BOOL WINAPI WinHttpSetDefaultProxyConfiguration( WINHTTP_PROXY_INFO *info ) *len++ = 0; *len++ = 0; } - l = RegSetValueExW( key, WinHttpSettings, 0, REG_BINARY, buf, size ); + l = RegSetValueExW( key, L"WinHttpSettings", 0, REG_BINARY, buf, size ); if (!l) ret = TRUE; - heap_free( buf ); + free( buf ); } RegCloseKey( key ); } @@ -2050,6 +2322,113 @@ BOOL WINAPI WinHttpSetDefaultProxyConfiguration( WINHTTP_PROXY_INFO *info ) return ret; } +/*********************************************************************** + * WinHttpCreateProxyResolver (winhttp.@) + */ +DWORD WINAPI WinHttpCreateProxyResolver( HINTERNET hsession, HINTERNET *hresolver ) +{ + FIXME("%p, %p\n", hsession, hresolver); + return ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR; +} + +/*********************************************************************** + * WinHttpFreeProxyResult (winhttp.@) + */ +void WINAPI WinHttpFreeProxyResult( WINHTTP_PROXY_RESULT *result ) +{ + FIXME("%p\n", result); +} + +/*********************************************************************** + * WinHttpFreeProxyResultEx (winhttp.@) + */ +void WINAPI WinHttpFreeProxyResultEx( WINHTTP_PROXY_RESULT_EX *result ) +{ + FIXME("%p\n", result); +} + +/*********************************************************************** + * WinHttpFreeProxySettings (winhttp.@) + */ +void WINAPI WinHttpFreeProxySettings( WINHTTP_PROXY_SETTINGS *settings ) +{ + FIXME("%p\n", settings); +} + +/*********************************************************************** + * WinHttpGetProxyForUrlEx (winhttp.@) + */ +DWORD WINAPI WinHttpGetProxyForUrlEx( HINTERNET hresolver, const WCHAR *url, WINHTTP_AUTOPROXY_OPTIONS *options, + DWORD_PTR ctx ) +{ + FIXME( "%p, %s, %p, %Ix\n", hresolver, debugstr_w(url), options, ctx ); + return ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR; +} + +/*********************************************************************** + * WinHttpGetProxyForUrlEx2 (winhttp.@) + */ +DWORD WINAPI WinHttpGetProxyForUrlEx2( HINTERNET hresolver, const WCHAR *url, WINHTTP_AUTOPROXY_OPTIONS *options, + DWORD selection_len, BYTE *selection, DWORD_PTR ctx ) +{ + FIXME( "%p, %s, %p, %lu, %p, %Ix\n", hresolver, debugstr_w(url), options, selection_len, selection, ctx ); + return ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR; +} + +/*********************************************************************** + * WinHttpGetProxyResult (winhttp.@) + */ +DWORD WINAPI WinHttpGetProxyResult( HINTERNET hresolver, WINHTTP_PROXY_RESULT *result ) +{ + FIXME("%p, %p\n", hresolver, result); + return ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR; +} + +/*********************************************************************** + * WinHttpGetProxyResultEx (winhttp.@) + */ +DWORD WINAPI WinHttpGetProxyResultEx( HINTERNET hresolver, WINHTTP_PROXY_RESULT_EX *result ) +{ + FIXME("%p, %p\n", hresolver, result); + return ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR; +} + +/*********************************************************************** + * WinHttpGetProxySettingsVersion (winhttp.@) + */ +DWORD WINAPI WinHttpGetProxySettingsVersion( HINTERNET hsession, DWORD *version ) +{ + FIXME("%p, %p\n", hsession, version); + return ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR; +} + +/*********************************************************************** + * WinHttpReadProxySettings (winhttp.@) + */ +DWORD WINAPI WinHttpReadProxySettings( HINTERNET hsession, const WCHAR *connection, BOOL use_defaults, + BOOL set_autodiscover, DWORD *version, BOOL *defaults_returned, + WINHTTP_PROXY_SETTINGS *settings) +{ + FIXME("%p, %s, %d, %d, %p, %p, %p\n", hsession, debugstr_w(connection), use_defaults, set_autodiscover, + version, defaults_returned, settings); + return ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR; +} + +/*********************************************************************** + * WinHttpResetAutoProxy (winhttp.@) + */ +DWORD WINAPI WinHttpResetAutoProxy( HINTERNET hsession, DWORD flags ) +{ + FIXME( "%p, %#lx\n", hsession, flags ); + return ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR; +} + +DWORD WINAPI WinHttpWriteProxySettings( HINTERNET hsession, BOOL force, WINHTTP_PROXY_SETTINGS *settings ) +{ + FIXME("%p, %d, %p\n", hsession, force, settings); + return ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR; +} + /*********************************************************************** * WinHttpSetStatusCallback (winhttp.@) */ @@ -2059,7 +2438,7 @@ WINHTTP_STATUS_CALLBACK WINAPI WinHttpSetStatusCallback( HINTERNET handle, WINHT struct object_header *hdr; WINHTTP_STATUS_CALLBACK ret; - TRACE("%p, %p, 0x%08x, 0x%lx\n", handle, callback, flags, reserved); + TRACE( "%p, %p, %#lx, %Ix\n", handle, callback, flags, reserved ); if (!(hdr = grab_object( handle ))) { @@ -2145,22 +2524,15 @@ BOOL WINAPI WinHttpSetTimeouts( HINTERNET handle, int resolve, int connect, int } static const WCHAR wkday[7][4] = - {{'S','u','n', 0}, {'M','o','n', 0}, {'T','u','e', 0}, {'W','e','d', 0}, - {'T','h','u', 0}, {'F','r','i', 0}, {'S','a','t', 0}}; + {L"Sun", L"Mon", L"Tue", L"Wed", L"Thu", L"Fri", L"Sat"}; static const WCHAR month[12][4] = - {{'J','a','n', 0}, {'F','e','b', 0}, {'M','a','r', 0}, {'A','p','r', 0}, - {'M','a','y', 0}, {'J','u','n', 0}, {'J','u','l', 0}, {'A','u','g', 0}, - {'S','e','p', 0}, {'O','c','t', 0}, {'N','o','v', 0}, {'D','e','c', 0}}; + {L"Jan", L"Feb", L"Mar", L"Apr", L"May", L"Jun", L"Jul", L"Aug", L"Sep", L"Oct", L"Nov", L"Dec"}; /*********************************************************************** * WinHttpTimeFromSystemTime (WININET.@) */ BOOL WINAPI WinHttpTimeFromSystemTime( const SYSTEMTIME *time, LPWSTR string ) { - static const WCHAR format[] = - {'%','s',',',' ','%','0','2','d',' ','%','s',' ','%','4','d',' ','%','0', - '2','d',':','%','0','2','d',':','%','0','2','d',' ','G','M','T', 0}; - TRACE("%p, %p\n", time, string); if (!time || !string) @@ -2169,7 +2541,8 @@ BOOL WINAPI WinHttpTimeFromSystemTime( const SYSTEMTIME *time, LPWSTR string ) return FALSE; } - sprintfW( string, format, + swprintf( string, WINHTTP_TIME_FORMAT_BUFSIZE / sizeof(WCHAR), + L"%s, %02d %s %4d %02d:%02d:%02d GMT", wkday[time->wDayOfWeek], time->wDay, month[time->wMonth - 1], @@ -2208,15 +2581,15 @@ BOOL WINAPI WinHttpTimeToSystemTime( LPCWSTR string, SYSTEMTIME *time ) SetLastError( ERROR_SUCCESS ); - while (*s && !isalphaW( *s )) s++; + while (*s && !iswalpha( *s )) s++; if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE; time->wDayOfWeek = 7; for (i = 0; i < 7; i++) { - if (toupperW( wkday[i][0] ) == toupperW( s[0] ) && - toupperW( wkday[i][1] ) == toupperW( s[1] ) && - toupperW( wkday[i][2] ) == toupperW( s[2] ) ) + if (towupper( wkday[i][0] ) == towupper( s[0] ) && + towupper( wkday[i][1] ) == towupper( s[1] ) && + towupper( wkday[i][2] ) == towupper( s[2] ) ) { time->wDayOfWeek = i; break; @@ -2224,19 +2597,19 @@ BOOL WINAPI WinHttpTimeToSystemTime( LPCWSTR string, SYSTEMTIME *time ) } if (time->wDayOfWeek > 6) return TRUE; - while (*s && !isdigitW( *s )) s++; - time->wDay = strtolW( s, &end, 10 ); + while (*s && !iswdigit( *s )) s++; + time->wDay = wcstol( s, &end, 10 ); s = end; - while (*s && !isalphaW( *s )) s++; + while (*s && !iswalpha( *s )) s++; if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE; time->wMonth = 0; for (i = 0; i < 12; i++) { - if (toupperW( month[i][0]) == toupperW( s[0] ) && - toupperW( month[i][1]) == toupperW( s[1] ) && - toupperW( month[i][2]) == toupperW( s[2] ) ) + if (towupper( month[i][0]) == towupper( s[0] ) && + towupper( month[i][1]) == towupper( s[1] ) && + towupper( month[i][2]) == towupper( s[2] ) ) { time->wMonth = i + 1; break; @@ -2244,24 +2617,24 @@ BOOL WINAPI WinHttpTimeToSystemTime( LPCWSTR string, SYSTEMTIME *time ) } if (time->wMonth == 0) return TRUE; - while (*s && !isdigitW( *s )) s++; + while (*s && !iswdigit( *s )) s++; if (*s == '\0') return TRUE; - time->wYear = strtolW( s, &end, 10 ); + time->wYear = wcstol( s, &end, 10 ); s = end; - while (*s && !isdigitW( *s )) s++; + while (*s && !iswdigit( *s )) s++; if (*s == '\0') return TRUE; - time->wHour = strtolW( s, &end, 10 ); + time->wHour = wcstol( s, &end, 10 ); s = end; - while (*s && !isdigitW( *s )) s++; + while (*s && !iswdigit( *s )) s++; if (*s == '\0') return TRUE; - time->wMinute = strtolW( s, &end, 10 ); + time->wMinute = wcstol( s, &end, 10 ); s = end; - while (*s && !isdigitW( *s )) s++; + while (*s && !iswdigit( *s )) s++; if (*s == '\0') return TRUE; - time->wSecond = strtolW( s, &end, 10 ); + time->wSecond = wcstol( s, &end, 10 ); time->wMilliseconds = 0; return TRUE; diff --git a/dll/win32/winhttp/url.c b/dll/win32/winhttp/url.c index e1255bd6b15..4d10a17f6a0 100644 --- a/dll/win32/winhttp/url.c +++ b/dll/win32/winhttp/url.c @@ -16,12 +16,10 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include "config.h" -#include "ws2tcpip.h" -#include - +#include #include "windef.h" #include "winbase.h" +#include "ws2tcpip.h" #include "winreg.h" #include "winhttp.h" #include "shlwapi.h" @@ -31,9 +29,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(winhttp); -static const WCHAR scheme_http[] = {'h','t','t','p',0}; -static const WCHAR scheme_https[] = {'h','t','t','p','s',0}; - struct url_component { WCHAR **str; @@ -70,16 +65,16 @@ static WCHAR *decode_url( LPCWSTR url, DWORD *len ) const WCHAR *p = url; WCHAR hex[3], *q, *ret; - if (!(ret = heap_alloc( *len * sizeof(WCHAR) ))) return NULL; + if (!(ret = malloc( *len * sizeof(WCHAR) ))) return NULL; q = ret; while (*len > 0) { - if (p[0] == '%' && isxdigitW( p[1] ) && isxdigitW( p[2] )) + if (p[0] == '%' && iswxdigit( p[1] ) && iswxdigit( p[2] )) { hex[0] = p[1]; hex[1] = p[2]; hex[2] = 0; - *q++ = strtolW( hex, NULL, 16 ); + *q++ = wcstol( hex, NULL, 16 ); p += 3; *len -= 3; } @@ -95,8 +90,7 @@ static WCHAR *decode_url( LPCWSTR url, DWORD *len ) static inline BOOL need_escape( WCHAR ch ) { - static const WCHAR escapes[] = {' ','"','#','%','<','>','[','\\',']','^','`','{','|','}','~',0}; - const WCHAR *p = escapes; + const WCHAR *p = L" \"#%<>[\\]^`{|}~"; if (ch <= 31 || ch >= 127) return TRUE; while (*p) @@ -108,7 +102,7 @@ static inline BOOL need_escape( WCHAR ch ) static BOOL escape_string( const WCHAR *src, DWORD src_len, WCHAR *dst, DWORD *dst_len ) { - static const WCHAR hex[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; + static const WCHAR hex[] = L"0123456789ABCDEF"; WCHAR *p = dst; DWORD i; @@ -139,7 +133,7 @@ static DWORD escape_url( const WCHAR *url, DWORD *len, WCHAR **ret ) const WCHAR *p; DWORD len_base, len_path; - if ((p = strrchrW( url, '/' ))) + if ((p = wcsrchr( url, '/' ))) { len_base = p - url; if (!escape_string( p, *len - len_base, NULL, &len_path )) return ERROR_INVALID_PARAMETER; @@ -150,7 +144,7 @@ static DWORD escape_url( const WCHAR *url, DWORD *len, WCHAR **ret ) len_path = 0; } - if (!(*ret = heap_alloc( (len_base + len_path + 1) * sizeof(WCHAR) ))) return ERROR_OUTOFMEMORY; + if (!(*ret = malloc( (len_base + len_path + 1) * sizeof(WCHAR) ))) return ERROR_OUTOFMEMORY; memcpy( *ret, url, len_base * sizeof(WCHAR) ); if (p) escape_string( p, *len - (p - url), *ret + len_base, &len_path ); @@ -164,7 +158,7 @@ static DWORD parse_port( const WCHAR *str, DWORD len, INTERNET_PORT *ret ) { const WCHAR *p = str; DWORD port = 0; - while (len && isdigitW( *p )) + while (len && '0' <= *p && *p <= '9') { if ((port = port * 10 + *p - '0') > 65535) return ERROR_WINHTTP_INVALID_URL; p++; len--; @@ -176,48 +170,49 @@ static DWORD parse_port( const WCHAR *str, DWORD len, INTERNET_PORT *ret ) /*********************************************************************** * WinHttpCrackUrl (winhttp.@) */ -BOOL WINAPI WinHttpCrackUrl( LPCWSTR url, DWORD len, DWORD flags, LPURL_COMPONENTSW uc ) +BOOL WINAPI WinHttpCrackUrl( const WCHAR *url, DWORD len, DWORD flags, URL_COMPONENTSW *uc ) { - WCHAR *p, *q, *r, *url_decoded = NULL, *url_escaped = NULL; + WCHAR *p, *q, *r, *url_transformed = NULL; INTERNET_SCHEME scheme_number = 0; struct url_component scheme, username, password, hostname, path, extra; BOOL overflow = FALSE; DWORD err; - TRACE("%s, %d, %x, %p\n", debugstr_wn(url, len), len, flags, uc); + TRACE( "%s, %lu, %#lx, %p\n", debugstr_wn(url, len), len, flags, uc ); if (!url || !uc || uc->dwStructSize != sizeof(*uc)) { SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } - if (!len) len = strlenW( url ); + if (!len) len = lstrlenW( url ); if (flags & ICU_ESCAPE) { - if ((err = escape_url( url, &len, &url_escaped ))) + if ((err = escape_url( url, &len, &url_transformed ))) { SetLastError( err ); return FALSE; } - url = url_escaped; + url = url_transformed; } else if (flags & ICU_DECODE) { - if (!(url_decoded = decode_url( url, &len ))) + if (!(url_transformed = decode_url( url, &len ))) { SetLastError( ERROR_OUTOFMEMORY ); return FALSE; } - url = url_decoded; + url = url_transformed; } - if (!(p = strchrW( url, ':' ))) + if (!(p = wcschr( url, ':' ))) { SetLastError( ERROR_WINHTTP_UNRECOGNIZED_SCHEME ); + free( url_transformed ); return FALSE; } - if (p - url == 4 && !strncmpiW( url, scheme_http, 4 )) scheme_number = INTERNET_SCHEME_HTTP; - else if (p - url == 5 && !strncmpiW( url, scheme_https, 5 )) scheme_number = INTERNET_SCHEME_HTTPS; + if (p - url == 4 && !wcsnicmp( url, L"http", 4 )) scheme_number = INTERNET_SCHEME_HTTP; + else if (p - url == 5 && !wcsnicmp( url, L"https", 5 )) scheme_number = INTERNET_SCHEME_HTTPS; else { err = ERROR_WINHTTP_UNRECOGNIZED_SCHEME; @@ -248,10 +243,10 @@ BOOL WINAPI WinHttpCrackUrl( LPCWSTR url, DWORD len, DWORD flags, LPURL_COMPONEN password.str = &uc->lpszPassword; password.len = &uc->dwPasswordLength; - if ((q = memchrW( p, '@', len - (p - url) )) && !(memchrW( p, '/', q - p ))) + if ((q = wmemchr( p, '@', len - (p - url) )) && !(wmemchr( p, '/', q - p ))) { - if ((r = memchrW( p, ':', q - p ))) + if ((r = wmemchr( p, ':', q - p ))) { if ((err = set_component( &username, p, r - p, flags, &overflow ))) goto exit; r++; @@ -279,22 +274,27 @@ BOOL WINAPI WinHttpCrackUrl( LPCWSTR url, DWORD len, DWORD flags, LPURL_COMPONEN extra.str = &uc->lpszExtraInfo; extra.len = &uc->dwExtraInfoLength; - if ((q = memchrW( p, '/', len - (p - url) ))) + if ((q = wmemchr( p, '/', len - (p - url) ))) { - if ((r = memchrW( p, ':', q - p ))) + if ((r = wmemchr( p, ':', q - p ))) { if ((err = set_component( &hostname, p, r - p, flags, &overflow ))) goto exit; r++; - if ((err = parse_port( r, q - r, &uc->nPort ))) goto exit; + if (!(q - r)) + { + if (scheme_number == INTERNET_SCHEME_HTTP) uc->nPort = INTERNET_DEFAULT_HTTP_PORT; + else if (scheme_number == INTERNET_SCHEME_HTTPS) uc->nPort = INTERNET_DEFAULT_HTTPS_PORT; + } + else if ((err = parse_port( r, q - r, &uc->nPort ))) goto exit; } else { if ((err = set_component( &hostname, p, q - p, flags, &overflow ))) goto exit; if (scheme_number == INTERNET_SCHEME_HTTP) uc->nPort = INTERNET_DEFAULT_HTTP_PORT; - if (scheme_number == INTERNET_SCHEME_HTTPS) uc->nPort = INTERNET_DEFAULT_HTTPS_PORT; + else if (scheme_number == INTERNET_SCHEME_HTTPS) uc->nPort = INTERNET_DEFAULT_HTTPS_PORT; } - if ((r = memchrW( q, '?', len - (q - url) ))) + if ((r = wmemchr( q, '?', len - (q - url) ))) { if (*extra.len) { @@ -311,17 +311,22 @@ BOOL WINAPI WinHttpCrackUrl( LPCWSTR url, DWORD len, DWORD flags, LPURL_COMPONEN } else { - if ((r = memchrW( p, ':', len - (p - url) ))) + if ((r = wmemchr( p, ':', len - (p - url) ))) { if ((err = set_component( &hostname, p, r - p, flags, &overflow ))) goto exit; r++; - if ((err = parse_port( r, len - (r - url), &uc->nPort ))) goto exit; + if (!*r) + { + if (scheme_number == INTERNET_SCHEME_HTTP) uc->nPort = INTERNET_DEFAULT_HTTP_PORT; + else if (scheme_number == INTERNET_SCHEME_HTTPS) uc->nPort = INTERNET_DEFAULT_HTTPS_PORT; + } + else if ((err = parse_port( r, len - (r - url), &uc->nPort ))) goto exit; } else { if ((err = set_component( &hostname, p, len - (p - url), flags, &overflow ))) goto exit; if (scheme_number == INTERNET_SCHEME_HTTP) uc->nPort = INTERNET_DEFAULT_HTTP_PORT; - if (scheme_number == INTERNET_SCHEME_HTTPS) uc->nPort = INTERNET_DEFAULT_HTTPS_PORT; + else if (scheme_number == INTERNET_SCHEME_HTTPS) uc->nPort = INTERNET_DEFAULT_HTTPS_PORT; } if ((err = set_component( &path, (WCHAR *)url + len, 0, flags, &overflow ))) goto exit; if ((err = set_component( &extra, (WCHAR *)url + len, 0, flags, &overflow ))) goto exit; @@ -337,23 +342,22 @@ exit: if (overflow) err = ERROR_INSUFFICIENT_BUFFER; uc->nScheme = scheme_number; } - heap_free( url_decoded ); - heap_free( url_escaped ); + free( url_transformed ); SetLastError( err ); return !err; } static INTERNET_SCHEME get_scheme( const WCHAR *scheme, DWORD len ) { - if (!strncmpW( scheme, scheme_http, len )) return INTERNET_SCHEME_HTTP; - if (!strncmpW( scheme, scheme_https, len )) return INTERNET_SCHEME_HTTPS; + if (!wcsncmp( scheme, L"http", len )) return INTERNET_SCHEME_HTTP; + if (!wcsncmp( scheme, L"https", len )) return INTERNET_SCHEME_HTTPS; return 0; } static const WCHAR *get_scheme_string( INTERNET_SCHEME scheme ) { - if (scheme == INTERNET_SCHEME_HTTP) return scheme_http; - if (scheme == INTERNET_SCHEME_HTTPS) return scheme_https; + if (scheme == INTERNET_SCHEME_HTTP) return L"http"; + if (scheme == INTERNET_SCHEME_HTTPS) return L"https"; return NULL; } @@ -369,7 +373,7 @@ static DWORD get_comp_length( DWORD len, DWORD flags, WCHAR *comp ) DWORD ret; unsigned int i; - ret = len ? len : strlenW( comp ); + ret = len ? len : lstrlenW( comp ); if (!(flags & ICU_ESCAPE)) return ret; for (i = 0; i < len; i++) if (need_escape( comp[i] )) ret += 2; return ret; @@ -377,7 +381,6 @@ static DWORD get_comp_length( DWORD len, DWORD flags, WCHAR *comp ) static BOOL get_url_length( URL_COMPONENTS *uc, DWORD flags, DWORD *len ) { - static const WCHAR formatW[] = {'%','u',0}; INTERNET_SCHEME scheme; *len = 0; @@ -391,7 +394,7 @@ static BOOL get_url_length( URL_COMPONENTS *uc, DWORD flags, DWORD *len ) { scheme = uc->nScheme; if (!scheme) scheme = INTERNET_SCHEME_HTTP; - *len += strlenW( get_scheme_string( scheme ) ); + *len += lstrlenW( get_scheme_string( scheme ) ); } *len += 3; /* "://" */ @@ -421,7 +424,7 @@ static BOOL get_url_length( URL_COMPONENTS *uc, DWORD flags, DWORD *len ) { WCHAR port[sizeof("65535")]; - *len += sprintfW( port, formatW, uc->nPort ); + *len += swprintf( port, ARRAY_SIZE(port), L"%u", uc->nPort ); *len += 1; /* ":" */ } if (uc->lpszUrlPath && *uc->lpszUrlPath != '/') *len += 1; /* '/' */ @@ -434,13 +437,12 @@ static BOOL get_url_length( URL_COMPONENTS *uc, DWORD flags, DWORD *len ) /*********************************************************************** * WinHttpCreateUrl (winhttp.@) */ -BOOL WINAPI WinHttpCreateUrl( LPURL_COMPONENTS uc, DWORD flags, LPWSTR url, LPDWORD required ) +BOOL WINAPI WinHttpCreateUrl( URL_COMPONENTS *uc, DWORD flags, WCHAR *url, DWORD *required ) { - static const WCHAR formatW[] = {'%','u',0}; DWORD len, len_escaped; INTERNET_SCHEME scheme; - TRACE("%p, 0x%08x, %p, %p\n", uc, flags, url, required); + TRACE( "%p, %#lx, %p, %p\n", uc, flags, url, required ); if (!uc || uc->dwStructSize != sizeof(URL_COMPONENTS) || !required) { @@ -480,7 +482,7 @@ BOOL WINAPI WinHttpCreateUrl( LPURL_COMPONENTS uc, DWORD flags, LPWSTR url, LPDW if (!scheme) scheme = INTERNET_SCHEME_HTTP; schemeW = get_scheme_string( scheme ); - len = strlenW( schemeW ); + len = lstrlenW( schemeW ); memcpy( url, schemeW, len * sizeof(WCHAR) ); url += len; } @@ -513,7 +515,7 @@ BOOL WINAPI WinHttpCreateUrl( LPURL_COMPONENTS uc, DWORD flags, LPWSTR url, LPDW if (!uses_default_port( scheme, uc->nPort )) { *url++ = ':'; - url += sprintfW( url, formatW, uc->nPort ); + url += swprintf( url, sizeof("65535"), L"%u", uc->nPort ); } /* add slash between hostname and path if necessary */ diff --git a/dll/win32/winhttp/winhttp.spec b/dll/win32/winhttp/winhttp.spec index 28dcb1598b7..581918791e3 100644 --- a/dll/win32/winhttp/winhttp.spec +++ b/dll/win32/winhttp/winhttp.spec @@ -7,11 +7,20 @@ @ stdcall WinHttpCloseHandle(ptr) @ stdcall WinHttpConnect(ptr wstr long long) @ stdcall WinHttpCrackUrl(wstr long long ptr) +@ stdcall WinHttpCreateProxyResolver(ptr ptr) @ stdcall WinHttpCreateUrl(ptr long ptr ptr) @ stdcall WinHttpDetectAutoProxyConfigUrl(long ptr) +@ stdcall WinHttpFreeProxyResult(ptr) +@ stdcall WinHttpFreeProxyResultEx(ptr) +@ stdcall WinHttpFreeProxySettings(ptr) @ stdcall WinHttpGetDefaultProxyConfiguration(ptr) @ stdcall WinHttpGetIEProxyConfigForCurrentUser(ptr) @ stdcall WinHttpGetProxyForUrl(ptr wstr ptr ptr) +@ stdcall WinHttpGetProxyForUrlEx(ptr wstr ptr ptr) +@ stdcall WinHttpGetProxyForUrlEx2(ptr wstr ptr long ptr ptr) +@ stdcall WinHttpGetProxyResult(ptr ptr) +@ stdcall WinHttpGetProxyResultEx(ptr ptr) +@ stdcall WinHttpGetProxySettingsVersion(ptr ptr) @ stdcall WinHttpOpen(wstr long wstr wstr long) @ stdcall WinHttpOpenRequest(ptr wstr wstr wstr wstr ptr long) @ stdcall WinHttpQueryAuthSchemes(ptr ptr ptr ptr) @@ -19,7 +28,9 @@ @ stdcall WinHttpQueryHeaders(ptr long wstr ptr ptr ptr) @ stdcall WinHttpQueryOption(ptr long ptr ptr) @ stdcall WinHttpReadData(ptr ptr long ptr) +@ stdcall WinHttpReadProxySettings(ptr wstr long long ptr ptr ptr) @ stdcall WinHttpReceiveResponse(ptr ptr) +@ stdcall WinHttpResetAutoProxy(ptr long) @ stdcall WinHttpSendRequest(ptr wstr long ptr long long long) @ stdcall WinHttpSetCredentials(ptr long long wstr ptr ptr) @ stdcall WinHttpSetDefaultProxyConfiguration(ptr) @@ -28,4 +39,11 @@ @ stdcall WinHttpSetTimeouts(ptr long long long long) @ stdcall WinHttpTimeFromSystemTime(ptr ptr) @ stdcall WinHttpTimeToSystemTime(wstr ptr) +@ stdcall WinHttpWebSocketClose(ptr long ptr long) +@ stdcall WinHttpWebSocketCompleteUpgrade(ptr ptr) +@ stdcall WinHttpWebSocketQueryCloseStatus(ptr ptr ptr long ptr) +@ stdcall WinHttpWebSocketReceive(ptr ptr long ptr ptr) +@ stdcall WinHttpWebSocketSend(ptr long ptr long) +@ stdcall WinHttpWebSocketShutdown(ptr long ptr long) @ stdcall WinHttpWriteData(ptr ptr long ptr) +@ stdcall WinHttpWriteProxySettings(ptr long ptr) diff --git a/dll/win32/winhttp/winhttp_private.h b/dll/win32/winhttp/winhttp_private.h index 3732dfaa8c1..d50d28316d4 100644 --- a/dll/win32/winhttp/winhttp_private.h +++ b/dll/win32/winhttp/winhttp_private.h @@ -19,29 +19,25 @@ #ifndef _WINE_WINHTTP_PRIVATE_H_ #define _WINE_WINHTTP_PRIVATE_H_ -#ifndef __WINE_CONFIG_H -# error You must include config.h to use this header -#endif - -#include "wine/heap.h" -#include "wine/list.h" -#include "wine/unicode.h" +#include #include "ole2.h" #include "sspi.h" #include "wincrypt.h" -static const WCHAR getW[] = {'G','E','T',0}; -static const WCHAR postW[] = {'P','O','S','T',0}; -static const WCHAR headW[] = {'H','E','A','D',0}; -static const WCHAR slashW[] = {'/',0}; -static const WCHAR http1_0[] = {'H','T','T','P','/','1','.','0',0}; -static const WCHAR http1_1[] = {'H','T','T','P','/','1','.','1',0}; -static const WCHAR chunkedW[] = {'c','h','u','n','k','e','d',0}; +#ifdef __REACTOS__ +#include +#include +#endif + +#include "wine/list.h" + +#define WINHTTP_HANDLE_TYPE_SOCKET 4 struct object_header; struct object_vtbl { + void (*handle_closing) ( struct object_header * ); void (*destroy)( struct object_header * ); BOOL (*query_option)( struct object_header *, DWORD, void *, DWORD * ); BOOL (*set_option)( struct object_header *, DWORD, void *, DWORD ); @@ -61,8 +57,10 @@ struct object_header LONG refs; WINHTTP_STATUS_CALLBACK callback; DWORD notify_mask; + LONG recursion_count; struct list entry; - struct list children; + volatile LONG pending_sends; + volatile LONG pending_receives; }; struct hostdata @@ -94,6 +92,8 @@ struct session HANDLE unload_event; DWORD secure_protocols; DWORD passport_flags; + unsigned int websocket_receive_buffer_size; + unsigned int websocket_send_buffer_size; }; struct connect @@ -113,6 +113,7 @@ struct connect struct netconn { struct list entry; + LONG refs; int socket; struct sockaddr_storage sockaddr; BOOL secure; /* SSL active on connection? */ @@ -120,12 +121,13 @@ struct netconn ULONGLONG keep_until; CtxtHandle ssl_ctx; SecPkgContext_StreamSizes ssl_sizes; - char *ssl_buf; + char *ssl_read_buf, *ssl_write_buf; char *extra_buf; size_t extra_len; char *peek_msg; char *peek_msg_mem; size_t peek_len; + HANDLE port; }; struct header @@ -167,10 +169,36 @@ struct authinfo BOOL finished; /* finished authenticating */ }; +struct queue +{ + SRWLOCK lock; + struct list queued_tasks; + BOOL callback_running; +}; + +enum request_flags +{ + REQUEST_FLAG_WEBSOCKET_UPGRADE = 0x01, +}; + +enum request_response_state +{ + REQUEST_RESPONSE_STATE_NONE, + REQUEST_RESPONSE_STATE_SENDING_REQUEST, + REQUEST_RESPONSE_STATE_READ_RESPONSE_QUEUED, + REQUEST_RESPONSE_STATE_REQUEST_SENT, + REQUEST_RESPONSE_STATE_READ_RESPONSE_QUEUED_REQUEST_SENT, + REQUEST_RESPONSE_STATE_REPLY_RECEIVED, + REQUEST_RESPONSE_STATE_READ_RESPONSE_QUEUED_REPLY_RECEIVED, + REQUEST_RESPONSE_RECURSIVE_REQUEST, + REQUEST_RESPONSE_STATE_RESPONSE_RECEIVED, +}; + struct request { struct object_header hdr; struct connect *connect; + enum request_flags flags; WCHAR *verb; WCHAR *path; WCHAR *version; @@ -189,6 +217,8 @@ struct request int send_timeout; int receive_timeout; int receive_response_timeout; + DWORD max_redirects; + DWORD redirect_count; /* total number of redirects during this request */ WCHAR *status_text; DWORD content_length; /* total number of bytes to be read */ DWORD content_read; /* bytes read so far */ @@ -204,30 +234,112 @@ struct request struct authinfo *proxy_authinfo; HANDLE task_wait; HANDLE task_cancel; + struct queue queue; #ifdef __REACTOS__ HANDLE task_thread; -#else - BOOL task_proc_running; #endif - struct list task_queue; - CRITICAL_SECTION task_cs; struct { WCHAR *username; WCHAR *password; } creds[TARGET_MAX][SCHEME_MAX]; + unsigned int websocket_receive_buffer_size; + unsigned int websocket_send_buffer_size, websocket_set_send_buffer_size; + int read_reply_len; + DWORD read_reply_status; + enum request_response_state state; }; +enum socket_state +{ + SOCKET_STATE_OPEN = 0, + SOCKET_STATE_SHUTDOWN = 1, + SOCKET_STATE_CLOSED = 2, +}; + +/* rfc6455 */ +enum socket_opcode +{ + SOCKET_OPCODE_CONTINUE = 0x00, + SOCKET_OPCODE_TEXT = 0x01, + SOCKET_OPCODE_BINARY = 0x02, + SOCKET_OPCODE_RESERVED3 = 0x03, + SOCKET_OPCODE_RESERVED4 = 0x04, + SOCKET_OPCODE_RESERVED5 = 0x05, + SOCKET_OPCODE_RESERVED6 = 0x06, + SOCKET_OPCODE_RESERVED7 = 0x07, + SOCKET_OPCODE_CLOSE = 0x08, + SOCKET_OPCODE_PING = 0x09, + SOCKET_OPCODE_PONG = 0x0a, + SOCKET_OPCODE_INVALID = 0xff, +}; + +enum fragment_type +{ + SOCKET_FRAGMENT_NONE, + SOCKET_FRAGMENT_BINARY, + SOCKET_FRAGMENT_UTF8, +}; + +struct socket +{ + struct object_header hdr; + struct netconn *netconn; + int keepalive_interval; + unsigned int send_buffer_size; + enum socket_state state; + struct queue send_q; + struct queue recv_q; + enum socket_opcode opcode; + DWORD read_size; + char mask[4]; + unsigned int mask_index; + BOOL close_frame_received; + DWORD close_frame_receive_err; + USHORT status; + char reason[123]; + DWORD reason_len; + char *send_frame_buffer; + unsigned int send_frame_buffer_size; + unsigned int send_remaining_size; + unsigned int bytes_in_send_frame_buffer; + unsigned int client_buffer_offset; + char *read_buffer; + unsigned int bytes_in_read_buffer; + SRWLOCK send_lock; + volatile LONG pending_noncontrol_send; + enum fragment_type sending_fragment_type; + enum fragment_type receiving_fragment_type; + BOOL last_receive_final; +}; + +typedef void (*TASK_CALLBACK)( void *ctx, BOOL abort ); + struct task_header { struct list entry; - struct request *request; - void (*proc)( struct task_header * ); + TASK_CALLBACK callback; + struct object_header *obj; + volatile LONG refs; + volatile LONG completion_sent; +}; + +struct send_callback +{ + struct task_header task_hdr; + DWORD status; + void *info; + DWORD buflen; + union + { + WINHTTP_ASYNC_RESULT result; + DWORD count; + }; }; struct send_request { - struct task_header hdr; + struct task_header task_hdr; WCHAR *headers; DWORD headers_len; void *optional; @@ -238,18 +350,18 @@ struct send_request struct receive_response { - struct task_header hdr; + struct task_header task_hdr; }; struct query_data { - struct task_header hdr; + struct task_header task_hdr; DWORD *available; }; struct read_data { - struct task_header hdr; + struct task_header task_hdr; void *buffer; DWORD to_read; DWORD *read; @@ -257,69 +369,87 @@ struct read_data struct write_data { - struct task_header hdr; + struct task_header task_hdr; const void *buffer; DWORD to_write; DWORD *written; }; -struct object_header *addref_object( struct object_header * ) DECLSPEC_HIDDEN; -struct object_header *grab_object( HINTERNET ) DECLSPEC_HIDDEN; -void release_object( struct object_header * ) DECLSPEC_HIDDEN; -HINTERNET alloc_handle( struct object_header * ) DECLSPEC_HIDDEN; -BOOL free_handle( HINTERNET ) DECLSPEC_HIDDEN; - -void send_callback( struct object_header *, DWORD, LPVOID, DWORD ) DECLSPEC_HIDDEN; -void close_connection( struct request * ) DECLSPEC_HIDDEN; - -void netconn_close( struct netconn * ) DECLSPEC_HIDDEN; -struct netconn *netconn_create( struct hostdata *, const struct sockaddr_storage *, int ) DECLSPEC_HIDDEN; -void netconn_unload( void ) DECLSPEC_HIDDEN; -ULONG netconn_query_data_available( struct netconn * ) DECLSPEC_HIDDEN; -BOOL netconn_recv( struct netconn *, void *, size_t, int, int * ) DECLSPEC_HIDDEN; -BOOL netconn_resolve( WCHAR *, INTERNET_PORT, struct sockaddr_storage *, int ) DECLSPEC_HIDDEN; -BOOL netconn_secure_connect( struct netconn *, WCHAR *, DWORD, CredHandle *, BOOL ) DECLSPEC_HIDDEN; -BOOL netconn_send( struct netconn *, const void *, size_t, int * ) DECLSPEC_HIDDEN; -DWORD netconn_set_timeout( struct netconn *, BOOL, int ) DECLSPEC_HIDDEN; -BOOL netconn_is_alive( struct netconn * ) DECLSPEC_HIDDEN; -const void *netconn_get_certificate( struct netconn * ) DECLSPEC_HIDDEN; -int netconn_get_cipher_strength( struct netconn * ) DECLSPEC_HIDDEN; - -BOOL set_cookies( struct request *, const WCHAR * ) DECLSPEC_HIDDEN; -BOOL add_cookie_headers( struct request * ) DECLSPEC_HIDDEN; -BOOL add_request_headers( struct request *, const WCHAR *, DWORD, DWORD ) DECLSPEC_HIDDEN; -void destroy_cookies( struct session * ) DECLSPEC_HIDDEN; -BOOL set_server_for_hostname( struct connect *, const WCHAR *, INTERNET_PORT ) DECLSPEC_HIDDEN; -void destroy_authinfo( struct authinfo * ) DECLSPEC_HIDDEN; - -void release_host( struct hostdata * ) DECLSPEC_HIDDEN; -BOOL process_header( struct request *, const WCHAR *, const WCHAR *, DWORD, BOOL ) DECLSPEC_HIDDEN; - -extern HRESULT WinHttpRequest_create( void ** ) DECLSPEC_HIDDEN; -void release_typelib( void ) DECLSPEC_HIDDEN; - -static inline void* __WINE_ALLOC_SIZE(2) heap_realloc_zero( LPVOID mem, SIZE_T size ) +struct socket_send { - return HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, mem, size ); -} + struct task_header task_hdr; + WINHTTP_WEB_SOCKET_BUFFER_TYPE type; + const void *buf; + DWORD len; + WSAOVERLAPPED ovr; + BOOL complete_async; +}; -static inline WCHAR *strdupW( const WCHAR *src ) +struct socket_receive { - WCHAR *dst; + struct task_header task_hdr; + void *buf; + DWORD len; +}; - if (!src) return NULL; - dst = heap_alloc( (strlenW( src ) + 1) * sizeof(WCHAR) ); - if (dst) strcpyW( dst, src ); - return dst; -} +struct socket_shutdown +{ + struct task_header task_hdr; + USHORT status; + char reason[123]; + DWORD len; + BOOL send_callback; + WSAOVERLAPPED ovr; + BOOL complete_async; +}; + +struct object_header *addref_object( struct object_header * ); +struct object_header *grab_object( HINTERNET ); +void release_object( struct object_header * ); +HINTERNET alloc_handle( struct object_header * ); +BOOL free_handle( HINTERNET ); + +void send_callback( struct object_header *, DWORD, LPVOID, DWORD ); +void close_connection( struct request * ); +void init_queue( struct queue *queue ); +void stop_queue( struct queue * ); + +void netconn_addref( struct netconn * ); +void netconn_release( struct netconn * ); +DWORD netconn_create( struct hostdata *, const struct sockaddr_storage *, int, struct netconn ** ); +void netconn_unload( void ); +ULONG netconn_query_data_available( struct netconn * ); +DWORD netconn_recv( struct netconn *, void *, size_t, int, int * ); +DWORD netconn_resolve( WCHAR *, INTERNET_PORT, struct sockaddr_storage *, int ); +DWORD netconn_secure_connect( struct netconn *, WCHAR *, DWORD, CredHandle *, BOOL ); +DWORD netconn_send( struct netconn *, const void *, size_t, int *, WSAOVERLAPPED * ); +BOOL netconn_wait_overlapped_result( struct netconn *conn, WSAOVERLAPPED *ovr, DWORD *len ); +void netconn_cancel_io( struct netconn *conn ); +DWORD netconn_set_timeout( struct netconn *, BOOL, int ); +BOOL netconn_is_alive( struct netconn * ); +const void *netconn_get_certificate( struct netconn * ); +int netconn_get_cipher_strength( struct netconn * ); + +BOOL set_cookies( struct request *, const WCHAR * ); +DWORD add_cookie_headers( struct request * ); +DWORD add_request_headers( struct request *, const WCHAR *, DWORD, DWORD ); +void destroy_cookies( struct session * ); +BOOL set_server_for_hostname( struct connect *, const WCHAR *, INTERNET_PORT ); +void destroy_authinfo( struct authinfo * ); + +void release_host( struct hostdata * ); +DWORD process_header( struct request *, const WCHAR *, const WCHAR *, DWORD, BOOL ); + +extern HRESULT WinHttpRequest_create( void ** ); +void release_typelib( void ); static inline WCHAR *strdupAW( const char *src ) { WCHAR *dst = NULL; if (src) { - DWORD len = MultiByteToWideChar( CP_ACP, 0, src, -1, NULL, 0 ); - if ((dst = heap_alloc( len * sizeof(WCHAR) ))) + int len = MultiByteToWideChar( CP_ACP, 0, src, -1, NULL, 0 ); + if ((dst = malloc( len * sizeof(WCHAR) ))) MultiByteToWideChar( CP_ACP, 0, src, -1, dst, len ); } return dst; @@ -331,27 +461,14 @@ static inline char *strdupWA( const WCHAR *src ) if (src) { int len = WideCharToMultiByte( CP_ACP, 0, src, -1, NULL, 0, NULL, NULL ); - if ((dst = heap_alloc( len ))) + if ((dst = malloc( len ))) WideCharToMultiByte( CP_ACP, 0, src, -1, dst, len, NULL, NULL ); } return dst; } -static inline char *strdupWA_sized( const WCHAR *src, DWORD size ) -{ - char *dst = NULL; - if (src) - { - int len = WideCharToMultiByte( CP_ACP, 0, src, size, NULL, 0, NULL, NULL ) + 1; - if ((dst = heap_alloc( len ))) - { - WideCharToMultiByte( CP_ACP, 0, src, len, dst, size, NULL, NULL ); - dst[len - 1] = 0; - } - } - return dst; -} +extern HINSTANCE winhttp_instance; -extern HINSTANCE winhttp_instance DECLSPEC_HIDDEN; +#define MIN_WEBSOCKET_SEND_BUFFER_SIZE 16 #endif /* _WINE_WINHTTP_PRIVATE_H_ */ diff --git a/media/doc/WINESYNC.txt b/media/doc/WINESYNC.txt index 57cfa3570e9..fef3fbe6a1d 100644 --- a/media/doc/WINESYNC.txt +++ b/media/doc/WINESYNC.txt @@ -213,7 +213,7 @@ dll/win32/windowscodecs # Synced to Wine-10.0 dll/win32/windowscodecsext # Synced to Wine-10.0 dll/win32/winemp3.acm # Synced to WineStaging-4.18 dll/win32/wing32 # Synced to WineStaging-3.3 -dll/win32/winhttp # Synced to WineStaging-4.18 +dll/win32/winhttp # Synced to Wine-10.0 dll/win32/wininet # Synced to WineStaging-6.0rc1 dll/win32/winmm # Forked at Wine-20050628 dll/win32/winmm/midimap # Forked at Wine-20050628 diff --git a/modules/rostests/winetests/winhttp/CMakeLists.txt b/modules/rostests/winetests/winhttp/CMakeLists.txt index 66725934496..2b4a890170a 100644 --- a/modules/rostests/winetests/winhttp/CMakeLists.txt +++ b/modules/rostests/winetests/winhttp/CMakeLists.txt @@ -1,5 +1,6 @@ add_definitions(-DUSE_WINE_TODOS) +remove_definitions(-D_CRT_NON_CONFORMING_SWPRINTFS) list(APPEND SOURCE notification.c diff --git a/modules/rostests/winetests/winhttp/notification.c b/modules/rostests/winetests/winhttp/notification.c index e2bbb714fe9..db419e7a36c 100644 --- a/modules/rostests/winetests/winhttp/notification.c +++ b/modules/rostests/winetests/winhttp/notification.c @@ -28,11 +28,12 @@ #include "wine/test.h" -static const WCHAR user_agent[] = {'w','i','n','e','t','e','s','t',0}; -static const WCHAR test_winehq[] = {'t','e','s','t','.','w','i','n','e','h','q','.','o','r','g',0}; -static const WCHAR tests_hello_html[] = {'/','t','e','s','t','s','/','h','e','l','l','o','.','h','t','m','l',0}; -static const WCHAR tests_redirect[] = {'/','t','e','s','t','s','/','r','e','d','i','r','e','c','t',0}; -static const WCHAR localhostW[] = {'l','o','c','a','l','h','o','s','t',0}; +static DWORD (WINAPI *pWinHttpWebSocketClose)(HINTERNET,USHORT,void*,DWORD); +static HINTERNET (WINAPI *pWinHttpWebSocketCompleteUpgrade)(HINTERNET,DWORD_PTR); +static DWORD (WINAPI *pWinHttpWebSocketQueryCloseStatus)(HINTERNET,USHORT*,void*,DWORD,DWORD*); +static DWORD (WINAPI *pWinHttpWebSocketReceive)(HINTERNET,void*,DWORD,DWORD*,WINHTTP_WEB_SOCKET_BUFFER_TYPE*); +static DWORD (WINAPI *pWinHttpWebSocketSend)(HINTERNET,WINHTTP_WEB_SOCKET_BUFFER_TYPE,void*,DWORD); +static DWORD (WINAPI *pWinHttpWebSocketShutdown)(HINTERNET,USHORT,void*,DWORD); enum api { @@ -40,6 +41,11 @@ enum api winhttp_open_request, winhttp_send_request, winhttp_receive_response, + winhttp_websocket_complete_upgrade, + winhttp_websocket_send, + winhttp_websocket_receive, + winhttp_websocket_shutdown, + winhttp_websocket_close, winhttp_query_data, winhttp_read_data, winhttp_write_data, @@ -56,6 +62,9 @@ struct notification #define NF_ALLOW 0x0001 /* notification may or may not happen */ #define NF_WINE_ALLOW 0x0002 /* wine sends notification when it should not */ #define NF_SIGNAL 0x0004 /* signal wait handle when notified */ +#define NF_MAIN_THREAD 0x0008 /* the operation completes synchronously and callback is called from the main thread */ +#define NF_SAVE_BUFFER 0x0010 /* save buffer data when notified */ +#define NF_OTHER_THREAD 0x0020 /* the operation completes asynchronously and callback is called from the other thread */ struct info { @@ -65,6 +74,11 @@ struct info unsigned int index; HANDLE wait; unsigned int line; + DWORD main_thread_id; + DWORD last_thread_id; + DWORD last_status; + char buffer[256]; + unsigned int buflen; }; struct test_request @@ -79,6 +93,9 @@ static void CALLBACK check_notification( HINTERNET handle, DWORD_PTR context, DW BOOL status_ok, function_ok; struct info *info = (struct info *)context; + info->last_status = status; + info->last_thread_id = GetCurrentThreadId(); + if (status == WINHTTP_CALLBACK_STATUS_HANDLE_CREATED) { DWORD size = sizeof(struct info *); @@ -88,48 +105,65 @@ static void CALLBACK check_notification( HINTERNET handle, DWORD_PTR context, DW info->index++; while (info->index < info->count && (info->test[info->index].flags & NF_WINE_ALLOW)) { - todo_wine ok(info->test[info->index].status != status, "unexpected %x notification\n", status); + todo_wine ok( info->test[info->index].status != status, "unexpected %#lx notification\n", status ); if (info->test[info->index].status == status) break; info->index++; } - ok(info->index < info->count, "%u: unexpected notification 0x%08x\n", info->line, status); + ok( info->index < info->count, "%u: unexpected notification %#lx\n", info->line, status ); if (info->index >= info->count) return; status_ok = (info->test[info->index].status == status); function_ok = (info->test[info->index].function == info->function); - ok(status_ok, "%u: expected status 0x%08x got 0x%08x\n", info->line, info->test[info->index].status, status); + + ok( status_ok, "%u: expected status %#x got %#lx\n", info->line, info->test[info->index].status, status ); ok(function_ok, "%u: expected function %u got %u\n", info->line, info->test[info->index].function, info->function); + if (info->test[info->index].flags & NF_MAIN_THREAD) + { + ok(GetCurrentThreadId() == info->main_thread_id, "%u: expected callback %#lx to be called from the same thread\n", + info->line, status); + } + else if (info->test[info->index].flags & NF_OTHER_THREAD) + { + ok(GetCurrentThreadId() != info->main_thread_id, "%u: expected callback %#lx to be called from the other thread\n", + info->line, status); + } + if (info->test[info->index].flags & NF_SAVE_BUFFER) + { + info->buflen = buflen; + memcpy( info->buffer, buffer, min( buflen, sizeof(info->buffer) )); + } + if (status_ok && function_ok && info->test[info->index++].flags & NF_SIGNAL) { SetEvent( info->wait ); } } -static const struct notification cache_test[] = +static const struct notification cache_test_async[] = { { winhttp_connect, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, - { winhttp_send_request, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME }, - { winhttp_send_request, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED }, - { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER }, - { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME, NF_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED, NF_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, NF_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, NF_ALLOW }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED }, - { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION, NF_WINE_ALLOW }, - { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED, NF_WINE_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE, NF_SIGNAL }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NF_MAIN_THREAD | NF_SIGNAL }, { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }, { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, NF_WINE_ALLOW }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, NF_WINE_ALLOW }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED }, - { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION, NF_WINE_ALLOW }, - { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED, NF_WINE_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE, NF_SIGNAL }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NF_MAIN_THREAD | NF_SIGNAL }, { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING }, { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }, { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }, @@ -141,20 +175,62 @@ static const struct notification cache_test[] = { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, NF_WINE_ALLOW }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED }, - { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION, NF_WINE_ALLOW }, - { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED, NF_WINE_ALLOW }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_MAIN_THREAD }, { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }, { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, NF_WINE_ALLOW }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, NF_WINE_ALLOW }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED }, - { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION, NF_WINE_ALLOW }, - { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED, NF_WINE_ALLOW }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_MAIN_THREAD }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL } +}; + +static const struct notification cache_test[] = +{ + { winhttp_connect, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, + { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT, NF_SIGNAL }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_MAIN_THREAD | NF_SIGNAL }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }, + { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, NF_WINE_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, NF_WINE_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT, NF_SIGNAL }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_MAIN_THREAD | NF_SIGNAL }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }, + { winhttp_connect, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, + { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME, NF_WINE_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED, NF_WINE_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, NF_WINE_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, NF_WINE_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_MAIN_THREAD }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }, + { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, NF_WINE_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, NF_WINE_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_MAIN_THREAD }, { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING }, { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }, { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL } @@ -171,6 +247,9 @@ static void setup_test( struct info *info, enum api function, unsigned int line ok_(__FILE__,line)(info->test[info->index].function == function, "unexpected function %u, expected %u. probably some notifications were missing\n", info->test[info->index].function, function); + info->last_thread_id = 0xdeadbeef; + info->last_status = 0xdeadbeef; + info->main_thread_id = GetCurrentThreadId(); } static void end_test( struct info *info, unsigned int line ) @@ -179,20 +258,20 @@ static void end_test( struct info *info, unsigned int line ) info->test[info->index].status); } -static void test_connection_cache( void ) +static void test_connection_cache( BOOL async ) { HANDLE ses, con, req, event; DWORD size, status, err; BOOL ret, unload = TRUE; struct info info, *context = &info; - info.test = cache_test; - info.count = ARRAY_SIZE( cache_test ); + info.test = async ? cache_test_async : cache_test; + info.count = async ? ARRAY_SIZE( cache_test_async ) : ARRAY_SIZE ( cache_test ); info.index = 0; info.wait = CreateEventW( NULL, FALSE, FALSE, NULL ); - ses = WinHttpOpen( user_agent, 0, NULL, NULL, 0 ); - ok(ses != NULL, "failed to open session %u\n", GetLastError()); + ses = WinHttpOpen( L"winetest", 0, NULL, NULL, async ? WINHTTP_FLAG_ASYNC : 0 ); + ok( ses != NULL, "failed to open session %lu\n", GetLastError() ); event = CreateEventW( NULL, FALSE, FALSE, NULL ); ret = WinHttpSetOption( ses, WINHTTP_OPTION_UNLOAD_NOTIFY_EVENT, &event, sizeof(event) ); @@ -205,15 +284,15 @@ static void test_connection_cache( void ) WinHttpSetStatusCallback( ses, check_notification, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0 ); ret = WinHttpSetOption( ses, WINHTTP_OPTION_CONTEXT_VALUE, &context, sizeof(struct info *) ); - ok(ret, "failed to set context value %u\n", GetLastError()); + ok( ret, "failed to set context value %lu\n", GetLastError() ); setup_test( &info, winhttp_connect, __LINE__ ); - con = WinHttpConnect( ses, test_winehq, 0, 0 ); - ok(con != NULL, "failed to open a connection %u\n", GetLastError()); + con = WinHttpConnect( ses, L"test.winehq.org", 0, 0 ); + ok( con != NULL, "failed to open a connection %lu\n", GetLastError() ); setup_test( &info, winhttp_open_request, __LINE__ ); - req = WinHttpOpenRequest( con, NULL, tests_hello_html, NULL, NULL, NULL, 0 ); - ok(req != NULL, "failed to open a request %u\n", GetLastError()); + req = WinHttpOpenRequest( con, NULL, L"/tests/hello.html", NULL, NULL, NULL, 0 ); + ok( req != NULL, "failed to open a request %lu\n", GetLastError() ); setup_test( &info, winhttp_send_request, __LINE__ ); ret = WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 ); @@ -223,28 +302,32 @@ static void test_connection_cache( void ) skip("connection failed, skipping\n"); goto done; } - ok(ret, "failed to send request %u\n", GetLastError()); + ok( ret, "failed to send request %lu\n", GetLastError() ); + WaitForSingleObject( info.wait, INFINITE ); setup_test( &info, winhttp_receive_response, __LINE__ ); ret = WinHttpReceiveResponse( req, NULL ); - ok(ret, "failed to receive response %u\n", GetLastError()); + ok( ret, "failed to receive response %lu\n", GetLastError() ); + + WaitForSingleObject( info.wait, INFINITE ); size = sizeof(status); ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL ); - ok(ret, "failed unexpectedly %u\n", GetLastError()); - ok(status == 200, "request failed unexpectedly %u\n", status); + ok( ret, "failed unexpectedly %lu\n", GetLastError() ); + ok( status == 200, "request failed unexpectedly %lu\n", status ); ResetEvent( info.wait ); setup_test( &info, winhttp_close_handle, __LINE__ ); WinHttpCloseHandle( req ); + WaitForSingleObject( info.wait, INFINITE ); setup_test( &info, winhttp_open_request, __LINE__ ); - req = WinHttpOpenRequest( con, NULL, tests_hello_html, NULL, NULL, NULL, 0 ); - ok(req != NULL, "failed to open a request %u\n", GetLastError()); + req = WinHttpOpenRequest( con, NULL, L"/tests/hello.html", NULL, NULL, NULL, 0 ); + ok( req != NULL, "failed to open a request %lu\n", GetLastError() ); ret = WinHttpSetOption( req, WINHTTP_OPTION_CONTEXT_VALUE, &context, sizeof(struct info *) ); - ok(ret, "failed to set context value %u\n", GetLastError()); + ok( ret, "failed to set context value %lu\n", GetLastError() ); setup_test( &info, winhttp_send_request, __LINE__ ); ret = WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 ); @@ -254,16 +337,20 @@ static void test_connection_cache( void ) skip("connection failed, skipping\n"); goto done; } - ok(ret, "failed to send request %u\n", GetLastError()); + ok( ret, "failed to send request %lu\n", GetLastError() ); + + WaitForSingleObject( info.wait, INFINITE ); setup_test( &info, winhttp_receive_response, __LINE__ ); ret = WinHttpReceiveResponse( req, NULL ); - ok(ret, "failed to receive response %u\n", GetLastError()); + ok( ret, "failed to receive response %lu\n", GetLastError() ); + + WaitForSingleObject( info.wait, INFINITE ); size = sizeof(status); ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL ); - ok(ret, "failed unexpectedly %u\n", GetLastError()); - ok(status == 200, "request failed unexpectedly %u\n", status); + ok( ret, "failed unexpectedly %lu\n", GetLastError() ); + ok( status == 200, "request failed unexpectedly %lu\n", status ); ResetEvent( info.wait ); setup_test( &info, winhttp_close_handle, __LINE__ ); @@ -275,7 +362,7 @@ static void test_connection_cache( void ) if (unload) { status = WaitForSingleObject( event, 0 ); - ok(status == WAIT_TIMEOUT, "got %08x\n", status); + ok( status == WAIT_TIMEOUT, "got %#lx\n", status ); } setup_test( &info, winhttp_close_handle, __LINE__ ); @@ -285,12 +372,11 @@ static void test_connection_cache( void ) if (unload) { status = WaitForSingleObject( event, 100 ); - ok(status == WAIT_OBJECT_0, "got %08x\n", status); + ok( status == WAIT_OBJECT_0, "got %#lx\n", status ); } - - ses = WinHttpOpen( user_agent, 0, NULL, NULL, 0 ); - ok(ses != NULL, "failed to open session %u\n", GetLastError()); + ses = WinHttpOpen( L"winetest", 0, NULL, NULL, 0 ); + ok( ses != NULL, "failed to open session %lu\n", GetLastError() ); if (unload) { @@ -301,18 +387,18 @@ static void test_connection_cache( void ) WinHttpSetStatusCallback( ses, check_notification, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0 ); ret = WinHttpSetOption( ses, WINHTTP_OPTION_CONTEXT_VALUE, &context, sizeof(struct info *) ); - ok(ret, "failed to set context value %u\n", GetLastError()); + ok( ret, "failed to set context value %lu\n", GetLastError() ); setup_test( &info, winhttp_connect, __LINE__ ); - con = WinHttpConnect( ses, test_winehq, 0, 0 ); - ok(con != NULL, "failed to open a connection %u\n", GetLastError()); + con = WinHttpConnect( ses, L"test.winehq.org", 0, 0 ); + ok( con != NULL, "failed to open a connection %lu\n", GetLastError() ); setup_test( &info, winhttp_open_request, __LINE__ ); - req = WinHttpOpenRequest( con, NULL, tests_hello_html, NULL, NULL, NULL, 0 ); - ok(req != NULL, "failed to open a request %u\n", GetLastError()); + req = WinHttpOpenRequest( con, NULL, L"/tests/hello.html", NULL, NULL, NULL, 0 ); + ok( req != NULL, "failed to open a request %lu\n", GetLastError() ); ret = WinHttpSetOption( req, WINHTTP_OPTION_CONTEXT_VALUE, &context, sizeof(struct info *) ); - ok(ret, "failed to set context value %u\n", GetLastError()); + ok( ret, "failed to set context value %lu\n", GetLastError() ); setup_test( &info, winhttp_send_request, __LINE__ ); ret = WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 ); @@ -322,16 +408,16 @@ static void test_connection_cache( void ) skip("connection failed, skipping\n"); goto done; } - ok(ret, "failed to send request %u\n", GetLastError()); + ok( ret, "failed to send request %lu\n", GetLastError() ); setup_test( &info, winhttp_receive_response, __LINE__ ); ret = WinHttpReceiveResponse( req, NULL ); - ok(ret, "failed to receive response %u\n", GetLastError()); + ok( ret, "failed to receive response %lu\n", GetLastError() ); size = sizeof(status); ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL ); - ok(ret, "failed unexpectedly %u\n", GetLastError()); - ok(status == 200, "request failed unexpectedly %u\n", status); + ok( ret, "failed unexpectedly %lu\n", GetLastError() ); + ok( status == 200, "request failed unexpectedly %lu\n", status ); ResetEvent( info.wait ); setup_test( &info, winhttp_close_handle, __LINE__ ); @@ -339,11 +425,11 @@ static void test_connection_cache( void ) WaitForSingleObject( info.wait, INFINITE ); setup_test( &info, winhttp_open_request, __LINE__ ); - req = WinHttpOpenRequest( con, NULL, tests_hello_html, NULL, NULL, NULL, 0 ); - ok(req != NULL, "failed to open a request %u\n", GetLastError()); + req = WinHttpOpenRequest( con, NULL, L"/tests/hello.html", NULL, NULL, NULL, 0 ); + ok( req != NULL, "failed to open a request %lu\n", GetLastError() ); ret = WinHttpSetOption( req, WINHTTP_OPTION_CONTEXT_VALUE, &context, sizeof(struct info *) ); - ok(ret, "failed to set context value %u\n", GetLastError()); + ok( ret, "failed to set context value %lu\n", GetLastError() ); setup_test( &info, winhttp_send_request, __LINE__ ); ret = WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 ); @@ -353,16 +439,16 @@ static void test_connection_cache( void ) skip("connection failed, skipping\n"); goto done; } - ok(ret, "failed to send request %u\n", GetLastError()); + ok( ret, "failed to send request %lu\n", GetLastError() ); setup_test( &info, winhttp_receive_response, __LINE__ ); ret = WinHttpReceiveResponse( req, NULL ); - ok(ret, "failed to receive response %u\n", GetLastError()); + ok( ret, "failed to receive response %lu\n", GetLastError() ); size = sizeof(status); ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL ); - ok(ret, "failed unexpectedly %u\n", GetLastError()); - ok(status == 200, "request failed unexpectedly %u\n", status); + ok( ret, "failed unexpectedly %lu\n", GetLastError() ); + ok( status == 200, "request failed unexpectedly %lu\n", status ); setup_test( &info, winhttp_close_handle, __LINE__ ); done: @@ -373,7 +459,7 @@ done: if (unload) { status = WaitForSingleObject( event, 0 ); - ok(status == WAIT_TIMEOUT, "got %08x\n", status); + ok( status == WAIT_TIMEOUT, "got %#lx\n", status ); } setup_test( &info, winhttp_close_handle, __LINE__ ); @@ -385,7 +471,7 @@ done: if (unload) { status = WaitForSingleObject( event, 100 ); - ok(status == WAIT_OBJECT_0, "got %08x\n", status); + ok( status == WAIT_OBJECT_0, "got %#lx\n", status ); } CloseHandle( event ); @@ -399,53 +485,79 @@ static const struct notification redirect_test[] = { winhttp_send_request, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED, NF_WINE_ALLOW }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, NF_WINE_ALLOW }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, NF_WINE_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST, NF_MAIN_THREAD }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT, NF_MAIN_THREAD | NF_SIGNAL }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_REDIRECT, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME, NF_ALLOW | NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED, NF_ALLOW | NF_MAIN_THREAD}, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, NF_ALLOW | NF_MAIN_THREAD}, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, NF_ALLOW | NF_MAIN_THREAD}, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST, NF_MAIN_THREAD}, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_REQUEST_SENT, NF_MAIN_THREAD}, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_MAIN_THREAD}, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_MAIN_THREAD | NF_SIGNAL}, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL } +}; + +static const struct notification redirect_test_async[] = +{ + { winhttp_connect, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, + { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME, NF_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED, NF_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, NF_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, NF_ALLOW }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_REDIRECT }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE, NF_SIGNAL | NF_OTHER_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_REDIRECT, NF_MAIN_THREAD }, { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME, NF_ALLOW }, { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED, NF_ALLOW }, { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, NF_ALLOW }, { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, NF_ALLOW }, { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_REQUEST_SENT }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED }, - { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION, NF_WINE_ALLOW }, - { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED, NF_WINE_ALLOW }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_OTHER_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_OTHER_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NF_OTHER_THREAD | NF_SIGNAL }, { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING }, { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING }, { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL } }; -static void test_redirect( void ) +static void test_redirect( BOOL async ) { HANDLE ses, con, req; DWORD size, status, err; BOOL ret; struct info info, *context = &info; - info.test = redirect_test; - info.count = ARRAY_SIZE( redirect_test ); + info.test = async ? redirect_test_async : redirect_test; + info.count = async ? ARRAY_SIZE( redirect_test_async ) : ARRAY_SIZE( redirect_test ); info.index = 0; info.wait = CreateEventW( NULL, FALSE, FALSE, NULL ); - ses = WinHttpOpen( user_agent, 0, NULL, NULL, 0 ); - ok(ses != NULL, "failed to open session %u\n", GetLastError()); + ses = WinHttpOpen( L"winetest", 0, NULL, NULL, async ? WINHTTP_FLAG_ASYNC : 0 ); + ok( ses != NULL, "failed to open session %lu\n", GetLastError() ); WinHttpSetStatusCallback( ses, check_notification, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0 ); ret = WinHttpSetOption( ses, WINHTTP_OPTION_CONTEXT_VALUE, &context, sizeof(struct info *) ); - ok(ret, "failed to set context value %u\n", GetLastError()); + ok( ret, "failed to set context value %lu\n", GetLastError() ); setup_test( &info, winhttp_connect, __LINE__ ); - con = WinHttpConnect( ses, test_winehq, 0, 0 ); - ok(con != NULL, "failed to open a connection %u\n", GetLastError()); + con = WinHttpConnect( ses, L"test.winehq.org", 0, 0 ); + ok( con != NULL, "failed to open a connection %lu\n", GetLastError() ); setup_test( &info, winhttp_open_request, __LINE__ ); - req = WinHttpOpenRequest( con, NULL, tests_redirect, NULL, NULL, NULL, 0 ); - ok(req != NULL, "failed to open a request %u\n", GetLastError()); + req = WinHttpOpenRequest( con, NULL, L"/tests/redirect", NULL, NULL, NULL, 0 ); + ok( req != NULL, "failed to open a request %lu\n", GetLastError() ); setup_test( &info, winhttp_send_request, __LINE__ ); ret = WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 ); @@ -455,16 +567,19 @@ static void test_redirect( void ) skip("connection failed, skipping\n"); goto done; } - ok(ret, "failed to send request %u\n", GetLastError()); + ok( ret, "failed to send request %lu\n", GetLastError() ); + WaitForSingleObject( info.wait, INFINITE ); setup_test( &info, winhttp_receive_response, __LINE__ ); ret = WinHttpReceiveResponse( req, NULL ); - ok(ret, "failed to receive response %u\n", GetLastError()); + ok( ret, "failed to receive response %lu\n", GetLastError() ); + WaitForSingleObject( info.wait, INFINITE ); size = sizeof(status); + status = 0xdeadbeef; ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL ); - ok(ret, "failed unexpectedly %u\n", GetLastError()); - ok(status == 200, "request failed unexpectedly %u\n", status); + ok( ret, "failed unexpectedly %lu\n", GetLastError() ); + ok( status == 200, "request failed unexpectedly %lu\n", status ); setup_test( &info, winhttp_close_handle, __LINE__ ); done: @@ -487,12 +602,15 @@ static const struct notification async_test[] = { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE, NF_SIGNAL }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NF_SIGNAL }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, NF_SIGNAL | NF_MAIN_THREAD }, { winhttp_query_data, WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE, NF_SIGNAL }, { winhttp_read_data, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_ALLOW }, { winhttp_read_data, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_ALLOW }, + { winhttp_read_data, WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION }, + { winhttp_read_data, WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED }, { winhttp_read_data, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, NF_SIGNAL }, { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING }, { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING }, @@ -512,8 +630,8 @@ static void test_async( void ) info.index = 0; info.wait = CreateEventW( NULL, FALSE, FALSE, NULL ); - ses = WinHttpOpen( user_agent, 0, NULL, NULL, WINHTTP_FLAG_ASYNC ); - ok(ses != NULL, "failed to open session %u\n", GetLastError()); + ses = WinHttpOpen( L"winetest", 0, NULL, NULL, WINHTTP_FLAG_ASYNC ); + ok( ses != NULL, "failed to open session %lu\n", GetLastError() ); event = CreateEventW( NULL, FALSE, FALSE, NULL ); ret = WinHttpSetOption( ses, WINHTTP_OPTION_UNLOAD_NOTIFY_EVENT, &event, sizeof(event) ); @@ -526,27 +644,31 @@ static void test_async( void ) SetLastError( 0xdeadbeef ); WinHttpSetStatusCallback( ses, check_notification, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0 ); err = GetLastError(); - ok(err == ERROR_SUCCESS || broken(err == 0xdeadbeef) /* < win7 */, "got %u\n", err); + ok( err == ERROR_SUCCESS || broken(err == 0xdeadbeef) /* < win7 */, "got %lu\n", err ); SetLastError( 0xdeadbeef ); ret = WinHttpSetOption( ses, WINHTTP_OPTION_CONTEXT_VALUE, &context, sizeof(struct info *) ); err = GetLastError(); - ok(ret, "failed to set context value %u\n", err); - ok(err == ERROR_SUCCESS || broken(err == 0xdeadbeef) /* < win7 */, "got %u\n", err); + ok( ret, "failed to set context value %lu\n", err ); + ok( err == ERROR_SUCCESS || broken(err == 0xdeadbeef) /* < win7 */, "got %lu\n", err ); setup_test( &info, winhttp_connect, __LINE__ ); SetLastError( 0xdeadbeef ); - con = WinHttpConnect( ses, test_winehq, 0, 0 ); + con = WinHttpConnect( ses, L"test.winehq.org", 0, 0 ); err = GetLastError(); - ok(con != NULL, "failed to open a connection %u\n", err); - ok(err == ERROR_SUCCESS || broken(err == WSAEINVAL) /* < win7 */, "got %u\n", err); + ok( con != NULL, "failed to open a connection %lu\n", err ); + ok( err == ERROR_SUCCESS || broken(err == WSAEINVAL) /* < win7 */, "got %lu\n", err ); setup_test( &info, winhttp_open_request, __LINE__ ); SetLastError( 0xdeadbeef ); - req = WinHttpOpenRequest( con, NULL, tests_hello_html, NULL, NULL, NULL, 0 ); + req = WinHttpOpenRequest( con, NULL, L"/tests/hello.html", NULL, NULL, NULL, 0 ); err = GetLastError(); - ok(req != NULL, "failed to open a request %u\n", err); - ok(err == ERROR_SUCCESS, "got %u\n", err); + ok( req != NULL, "failed to open a request %lu\n", err ); + ok( err == ERROR_SUCCESS, "got %lu\n", err ); + + ret = WinHttpAddRequestHeaders( req , L"Connection: close", -1L, WINHTTP_ADDREQ_FLAG_REPLACE | WINHTTP_ADDREQ_FLAG_ADD ); + err = GetLastError(); + ok(ret, "WinHttpAddRequestHeaders failed to add new header, got %d with error %lu\n", ret, err); setup_test( &info, winhttp_send_request, __LINE__ ); SetLastError( 0xdeadbeef ); @@ -561,8 +683,8 @@ static void test_async( void ) CloseHandle( info.wait ); return; } - ok(ret, "failed to send request %u\n", err); - ok(err == ERROR_SUCCESS, "got %u\n", err); + ok( ret, "failed to send request %lu\n", err ); + ok( err == ERROR_SUCCESS, "got %lu\n", err ); WaitForSingleObject( info.wait, INFINITE ); @@ -570,8 +692,14 @@ static void test_async( void ) SetLastError( 0xdeadbeef ); ret = WinHttpReceiveResponse( req, NULL ); err = GetLastError(); - ok(ret, "failed to receive response %u\n", err); - ok(err == ERROR_SUCCESS, "got %u\n", err); + ok( ret, "failed to receive response %lu\n", err ); + ok( err == ERROR_SUCCESS, "got %lu\n", err ); + + SetLastError( 0xdeadbeef ); + ret = WinHttpReceiveResponse( req, NULL ); + err = GetLastError(); + ok( ret, "failed to receive response %lu\n", err ); + ok( err == ERROR_SUCCESS, "got %lu\n", err ); WaitForSingleObject( info.wait, INFINITE ); @@ -579,25 +707,34 @@ static void test_async( void ) SetLastError( 0xdeadbeef ); ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL ); err = GetLastError(); - ok(ret, "failed unexpectedly %u\n", err); - ok(status == 200, "request failed unexpectedly %u\n", status); - ok(err == ERROR_SUCCESS || broken(err == 0xdeadbeef) /* < win7 */, "got %u\n", err); + ok( ret, "failed unexpectedly %lu\n", err ); + ok( status == 200, "request failed unexpectedly %lu\n", status ); + ok( err == ERROR_SUCCESS || broken(err == 0xdeadbeef) /* < win7 */, "got %lu\n", err ); setup_test( &info, winhttp_query_data, __LINE__ ); SetLastError( 0xdeadbeef ); ret = WinHttpQueryDataAvailable( req, NULL ); err = GetLastError(); - ok(ret, "failed to query data available %u\n", err); - ok(err == ERROR_SUCCESS || err == ERROR_IO_PENDING || broken(err == 0xdeadbeef) /* < win7 */, "got %u\n", err); + ok( ret, "failed to query data available %lu\n", err ); + ok( err == ERROR_SUCCESS || err == ERROR_IO_PENDING || broken(err == 0xdeadbeef) /* < win7 */, "got %lu\n", err ); WaitForSingleObject( info.wait, INFINITE ); + ok( info.last_status == WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE, "got status %#lx\n", status ); + ok(( err == ERROR_SUCCESS && info.last_thread_id == GetCurrentThreadId()) + || (err == ERROR_IO_PENDING && info.last_thread_id != GetCurrentThreadId()), + "got unexpected thread %#lx, err %#lx\n", info.last_thread_id, err ); setup_test( &info, winhttp_read_data, __LINE__ ); ret = WinHttpReadData( req, buffer, sizeof(buffer), NULL ); - ok(ret, "failed to read data %u\n", err); + ok( ret, "failed to read data %lu\n", err ); WaitForSingleObject( info.wait, INFINITE ); + ok( info.last_status == WINHTTP_CALLBACK_STATUS_READ_COMPLETE, "got status %#lx\n", status ); + ok( (err == ERROR_SUCCESS && info.last_thread_id == GetCurrentThreadId()) + || (err == ERROR_IO_PENDING && info.last_thread_id != GetCurrentThreadId()), + "got unexpected thread %#lx, err %#lx\n", info.last_thread_id, err ); + setup_test( &info, winhttp_close_handle, __LINE__ ); WinHttpCloseHandle( req ); WinHttpCloseHandle( con ); @@ -605,7 +742,7 @@ static void test_async( void ) if (unload) { status = WaitForSingleObject( event, 0 ); - ok(status == WAIT_TIMEOUT, "got %08x\n", status); + ok( status == WAIT_TIMEOUT, "got %#lx\n", status ); } WinHttpCloseHandle( ses ); WaitForSingleObject( info.wait, INFINITE ); @@ -614,7 +751,722 @@ static void test_async( void ) if (unload) { status = WaitForSingleObject( event, 2000 ); - ok(status == WAIT_OBJECT_0, "got %08x\n", status); + ok( status == WAIT_OBJECT_0, "got %#lx\n", status ); + } + CloseHandle( event ); + CloseHandle( info.wait ); + end_test( &info, __LINE__ ); +} + +static const struct notification websocket_test[] = +{ + { winhttp_connect, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, + { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, NF_SIGNAL }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE, NF_SIGNAL }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NF_MAIN_THREAD | NF_SIGNAL }, + { winhttp_websocket_complete_upgrade, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, + { winhttp_websocket_complete_upgrade, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }, + { winhttp_websocket_send, WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE, NF_MAIN_THREAD | NF_SIGNAL }, + { winhttp_websocket_send, WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE, NF_MAIN_THREAD | NF_SIGNAL }, + { winhttp_websocket_send, WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE, NF_MAIN_THREAD | NF_SIGNAL }, + { winhttp_websocket_send, WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE, NF_MAIN_THREAD | NF_SIGNAL }, + { winhttp_websocket_shutdown, WINHTTP_CALLBACK_STATUS_SHUTDOWN_COMPLETE, NF_MAIN_THREAD | NF_SIGNAL }, + { winhttp_websocket_receive, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, NF_SAVE_BUFFER | NF_SIGNAL }, + { winhttp_websocket_receive, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, NF_SAVE_BUFFER | NF_SIGNAL }, + { winhttp_websocket_close, WINHTTP_CALLBACK_STATUS_CLOSE_COMPLETE, NF_SIGNAL }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }, +}; + +static const struct notification websocket_test2[] = +{ + { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME, NF_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED, NF_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE, NF_SIGNAL }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NF_SIGNAL | NF_MAIN_THREAD}, + { winhttp_websocket_complete_upgrade, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, NF_SIGNAL }, + { winhttp_websocket_receive, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, NF_SIGNAL }, + { winhttp_websocket_close, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, NF_MAIN_THREAD | NF_SAVE_BUFFER}, + { winhttp_websocket_close, WINHTTP_CALLBACK_STATUS_CLOSE_COMPLETE, NF_SIGNAL }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL } +}; + +static const struct notification websocket_test3[] = +{ + { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME, NF_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED, NF_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE, NF_SIGNAL }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NF_SIGNAL | NF_MAIN_THREAD }, + { winhttp_websocket_complete_upgrade, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, NF_SIGNAL }, + { winhttp_websocket_receive, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, NF_SIGNAL }, + + { winhttp_websocket_close, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, NF_MAIN_THREAD }, + { winhttp_websocket_close, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, NF_SAVE_BUFFER }, + { winhttp_websocket_close, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }, + + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }, +}; + +static struct notification websocket_test4[] = +{ + { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME, NF_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED, NF_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE, NF_SIGNAL }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NF_SIGNAL | NF_MAIN_THREAD }, + { winhttp_websocket_complete_upgrade, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, NF_SIGNAL }, + { winhttp_websocket_receive, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, NF_SIGNAL }, + + { winhttp_websocket_close, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, NF_SAVE_BUFFER }, + { winhttp_websocket_close, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }, + + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }, +}; + +static const struct notification websocket_test5[] = +{ + { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME, NF_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED, NF_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE, NF_SIGNAL }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NF_SIGNAL | NF_MAIN_THREAD }, + { winhttp_websocket_complete_upgrade, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, NF_SIGNAL | NF_MAIN_THREAD }, + { winhttp_websocket_receive, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, NF_SIGNAL }, + + { winhttp_websocket_shutdown, WINHTTP_CALLBACK_STATUS_SHUTDOWN_COMPLETE, NF_MAIN_THREAD }, + { winhttp_websocket_shutdown, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, NF_SAVE_BUFFER | NF_SIGNAL }, + { winhttp_websocket_close, WINHTTP_CALLBACK_STATUS_CLOSE_COMPLETE, + NF_MAIN_THREAD| NF_SAVE_BUFFER | NF_SIGNAL }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL } +}; + +#define BIG_BUFFER_SIZE (16 * 1024) + +static void test_websocket(BOOL secure) +{ + HANDLE session, connection, request, socket, event; + WINHTTP_WEB_SOCKET_ASYNC_RESULT *result; + WINHTTP_WEB_SOCKET_STATUS *ws_status; + WINHTTP_WEB_SOCKET_BUFFER_TYPE type; + DWORD size, status, err, value; + BOOL ret, unload = TRUE; + struct info info, *context = &info; + unsigned char *big_buffer; + char buffer[1024]; + USHORT close_status; + DWORD protocols, flags; + unsigned int i, test_index, offset; + + if (!pWinHttpWebSocketCompleteUpgrade) + { + win_skip( "WinHttpWebSocketCompleteUpgrade not supported\n" ); + return; + } + + info.test = websocket_test; + info.count = ARRAY_SIZE( websocket_test ); + info.index = 0; + info.wait = CreateEventW( NULL, FALSE, FALSE, NULL ); + + session = WinHttpOpen( L"winetest", 0, NULL, NULL, WINHTTP_FLAG_ASYNC ); + ok( session != NULL, "got %lu\n", GetLastError() ); + + event = CreateEventW( NULL, FALSE, FALSE, NULL ); + ret = WinHttpSetOption( session, WINHTTP_OPTION_UNLOAD_NOTIFY_EVENT, &event, sizeof(event) ); + if (!ret) + { + win_skip( "Unload event not supported\n" ); + unload = FALSE; + } + + if (secure) + { + protocols = WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2; + ret = WinHttpSetOption(session, WINHTTP_OPTION_SECURE_PROTOCOLS, &protocols, sizeof(protocols)); + ok( ret, "failed to set protocols %lu\n", GetLastError() ); + } + + SetLastError( 0xdeadbeef ); + WinHttpSetStatusCallback( session, check_notification, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0 ); + err = GetLastError(); + ok( err == ERROR_SUCCESS || broken(err == 0xdeadbeef) /* < win7 */, "got %lu\n", err ); + + SetLastError( 0xdeadbeef ); + ret = WinHttpSetOption( session, WINHTTP_OPTION_CONTEXT_VALUE, &context, sizeof(context) ); + err = GetLastError(); + ok( ret, "got %lu\n", err ); + ok( err == ERROR_SUCCESS || broken(err == 0xdeadbeef) /* < win7 */, "got %lu\n", err ); + + setup_test( &info, winhttp_connect, __LINE__ ); + SetLastError( 0xdeadbeef ); + connection = WinHttpConnect( session, L"ws.ifelse.io", 0, 0 ); + err = GetLastError(); + ok( connection != NULL, "got %lu\n", err ); + ok( err == ERROR_SUCCESS || broken(err == WSAEINVAL) /* < win7 */, "got %lu\n", err ); + + setup_test( &info, winhttp_open_request, __LINE__ ); + SetLastError( 0xdeadbeef ); + request = WinHttpOpenRequest( connection, NULL, L"/", NULL, NULL, NULL, secure ? WINHTTP_FLAG_SECURE : 0); + err = GetLastError(); + ok( request != NULL, "got %lu\n", err ); + ok( err == ERROR_SUCCESS, "got %lu\n", err ); + + if (secure) + { + flags = SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID | + SECURITY_FLAG_IGNORE_CERT_CN_INVALID; + ret = WinHttpSetOption(request, WINHTTP_OPTION_SECURITY_FLAGS, &flags, sizeof(flags)); + ok( ret, "failed to set security flags %lu\n", GetLastError() ); + } + + ret = WinHttpSetOption( request, WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET, NULL, 0 ); + ok( ret, "got %lu\n", GetLastError() ); + + setup_test( &info, winhttp_send_request, __LINE__ ); + + value = 15; + ret = WinHttpSetOption(request, WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE, &value, sizeof(DWORD)); + ok(ret, "got %lu\n", GetLastError()); + ret = WinHttpSendRequest( request, NULL, 0, NULL, 0, 0, 0 ); + err = GetLastError(); + ok( ret, "got err %lu.\n", err ); + + WaitForSingleObject( info.wait, INFINITE ); + + value = 32768; + ret = WinHttpSetOption(request, WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE, &value, sizeof(DWORD)); + ok(ret, "got %lu\n", GetLastError()); + + SetLastError( 0xdeadbeef ); + ret = WinHttpSendRequest( request, NULL, 0, NULL, 0, 0, 0 ); + err = GetLastError(); + if (!ret && (err == ERROR_WINHTTP_CANNOT_CONNECT || err == ERROR_WINHTTP_TIMEOUT)) + { + skip( "connection failed, skipping\n" ); + WinHttpCloseHandle( request ); + WinHttpCloseHandle( connection ); + WinHttpCloseHandle( session ); + CloseHandle( info.wait ); + return; + } + ok( ret, "got %lu\n", err ); + ok( err == ERROR_SUCCESS, "got %lu\n", err ); + WaitForSingleObject( info.wait, INFINITE ); + + setup_test( &info, winhttp_receive_response, __LINE__ ); + SetLastError( 0xdeadbeef ); + ret = WinHttpReceiveResponse( request, NULL ); + err = GetLastError(); + ok( ret, "got %lu\n", err ); + ok( err == ERROR_SUCCESS, "got %lu\n", err ); + WaitForSingleObject( info.wait, INFINITE ); + + size = sizeof(status); + SetLastError( 0xdeadbeef ); + ret = WinHttpQueryHeaders( request, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL ); + err = GetLastError(); + ok( ret, "failed unexpectedly %lu\n", err ); + ok( status == 101, "got %lu\n", status ); + ok( err == ERROR_SUCCESS || broken(err == 0xdeadbeef) /* < win7 */, "got %lu\n", err ); + + setup_test( &info, winhttp_websocket_complete_upgrade, __LINE__ ); + SetLastError( 0xdeadbeef ); + socket = pWinHttpWebSocketCompleteUpgrade( request, (DWORD_PTR)context ); + err = GetLastError(); + ok( socket != NULL, "got %lu\n", err ); + ok( err == ERROR_SUCCESS, "got %lu\n", err ); + + WinHttpCloseHandle( request ); + + WaitForSingleObject( info.wait, INFINITE ); + + /* The send is executed synchronously (even if sending a reasonably big buffer exceeding SSL buffer size). + * It is possible to trigger queueing the send into another thread but that involves sending a considerable + * amount of big enough buffers. */ + big_buffer = malloc( BIG_BUFFER_SIZE ); + for (i = 0; i < BIG_BUFFER_SIZE; ++i) big_buffer[i] = (i & 0xff) ^ 0xcc; + + setup_test( &info, winhttp_websocket_send, __LINE__ ); + err = pWinHttpWebSocketSend( socket, WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE, big_buffer, BIG_BUFFER_SIZE / 2 ); + ok( err == ERROR_SUCCESS, "got %lu\n", err ); + WaitForSingleObject( info.wait, INFINITE ); + + err = pWinHttpWebSocketSend( socket, WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE, + big_buffer + BIG_BUFFER_SIZE / 2, BIG_BUFFER_SIZE / 2 ); + ok( err == ERROR_INVALID_PARAMETER, "got %lu\n", err ); + err = pWinHttpWebSocketSend( socket, WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE, + big_buffer + BIG_BUFFER_SIZE / 2, BIG_BUFFER_SIZE / 2 ); + ok( err == ERROR_INVALID_PARAMETER, "got %lu\n", err ); + + setup_test( &info, winhttp_websocket_send, __LINE__ ); + err = pWinHttpWebSocketSend( socket, WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE, + big_buffer + BIG_BUFFER_SIZE / 2, BIG_BUFFER_SIZE / 2 ); + ok( err == ERROR_SUCCESS, "got %lu\n", err ); + WaitForSingleObject( info.wait, INFINITE ); + + setup_test( &info, winhttp_websocket_send, __LINE__ ); + err = pWinHttpWebSocketSend( socket, WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE, NULL, 0 ); + ok( err == ERROR_SUCCESS, "got %lu\n", err ); + WaitForSingleObject( info.wait, INFINITE ); + + setup_test( &info, winhttp_websocket_send, __LINE__ ); + err = pWinHttpWebSocketSend( socket, WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE, (void *)"hello", sizeof("hello") ); + ok( err == ERROR_SUCCESS, "got %lu\n", err ); + WaitForSingleObject( info.wait, INFINITE ); + + setup_test( &info, winhttp_websocket_shutdown, __LINE__ ); + err = pWinHttpWebSocketShutdown( socket, 1000, (void *)"success", sizeof("success") ); + ok( err == ERROR_SUCCESS, "got %lu\n", err ); + + err = pWinHttpWebSocketSend( socket, WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE, (void *)"hello", sizeof("hello") ); + ok( err == ERROR_INVALID_OPERATION, "got %lu\n", err ); + + WaitForSingleObject( info.wait, INFINITE ); + + err = pWinHttpWebSocketShutdown( socket, 1000, (void *)"success", sizeof("success") ); + ok( err == ERROR_INVALID_OPERATION, "got %lu\n", err ); + err = pWinHttpWebSocketSend( socket, WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE, (void *)"hello", sizeof("hello") ); + ok( err == ERROR_INVALID_OPERATION, "got %lu\n", err ); + + setup_test( &info, winhttp_websocket_receive, __LINE__ ); + buffer[0] = 0; + size = 0xdeadbeef; + type = 0xdeadbeef; + err = pWinHttpWebSocketReceive( socket, buffer, sizeof(buffer), &size, &type ); + ok( err == ERROR_SUCCESS, "got %lu\n", err ); + WaitForSingleObject( info.wait, INFINITE ); + ok( info.buflen == sizeof(*ws_status), "got %u\n", info.buflen ); + ws_status = (WINHTTP_WEB_SOCKET_STATUS *)info.buffer; + ok( ws_status->eBufferType == WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE, + "got unexpected eBufferType %u\n", ws_status->eBufferType ); + ok( size == 0xdeadbeef, "got %lu\n", size ); + ok( type == 0xdeadbeef, "got %u\n", type ); + ok( buffer[0] == 'R', "unexpected data\n" ); + + memset( big_buffer, 0, BIG_BUFFER_SIZE ); + offset = 0; + test_index = info.index; + do + { + info.index = test_index; + setup_test( &info, winhttp_websocket_receive, __LINE__ ); + size = 0xdeadbeef; + type = 0xdeadbeef; + ws_status = (WINHTTP_WEB_SOCKET_STATUS *)info.buffer; + ws_status->eBufferType = ~0u; + err = pWinHttpWebSocketReceive( socket, big_buffer + offset, BIG_BUFFER_SIZE - offset, &size, &type ); + ok( err == ERROR_SUCCESS, "got %lu\n", err ); + WaitForSingleObject( info.wait, INFINITE ); + ok( info.buflen == sizeof(*ws_status), "got %u\n", info.buflen ); + ok( ws_status->eBufferType == WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE + || ws_status->eBufferType == WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE, "got %u\n", ws_status->eBufferType ); + offset += ws_status->dwBytesTransferred; + ok( offset <= BIG_BUFFER_SIZE, "got %lu\n", ws_status->dwBytesTransferred ); + ok( size == 0xdeadbeef, "got %lu\n", size ); + ok( type == 0xdeadbeef, "got %u\n", type ); + } + while (ws_status->eBufferType == WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE); + + ok( offset == BIG_BUFFER_SIZE, "got %u\n", offset ); + + for (i = 0; i < BIG_BUFFER_SIZE; ++i) + if (big_buffer[i] != ((i & 0xff) ^ 0xcc)) break; + ok( i == BIG_BUFFER_SIZE, "unexpected data %#x at %u\n", (unsigned char)big_buffer[i], i ); + + free( big_buffer ); + + close_status = 0xdead; + size = sizeof(buffer) + 1; + err = pWinHttpWebSocketQueryCloseStatus( socket, &close_status, buffer, sizeof(buffer), &size ); + ok( err == ERROR_INVALID_OPERATION, "got %lu\n", err ); + ok( close_status == 0xdead, "got %u\n", close_status ); + ok( size == sizeof(buffer) + 1, "got %lu\n", size ); + + setup_test( &info, winhttp_websocket_close, __LINE__ ); + err = pWinHttpWebSocketClose( socket, 1000, (void *)"success", sizeof("success") ); + ok( err == ERROR_SUCCESS, "got %lu\n", err ); + WaitForSingleObject( info.wait, INFINITE ); + + close_status = 0xdead; + size = sizeof(buffer) + 1; + err = pWinHttpWebSocketQueryCloseStatus( socket, &close_status, buffer, sizeof(buffer), &size ); + ok( err == ERROR_SUCCESS, "got %lu\n", err ); + ok( close_status == 1000, "got %u\n", close_status ); + ok( size <= sizeof(buffer), "got %lu\n", size ); + + setup_test( &info, winhttp_close_handle, __LINE__ ); + WinHttpCloseHandle( socket ); + + WaitForSingleObject( info.wait, INFINITE ); + end_test( &info, __LINE__ ); + + /* Test socket close while receive is pending. */ + info.test = websocket_test2; + info.count = ARRAY_SIZE( websocket_test2 ); + info.index = 0; + + setup_test( &info, winhttp_open_request, __LINE__ ); + request = WinHttpOpenRequest( connection, NULL, L"/", NULL, NULL, NULL, secure ? WINHTTP_FLAG_SECURE : 0); + ok( request != NULL, "got %lu\n", err ); + + if (secure) + { + flags = SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID | + SECURITY_FLAG_IGNORE_CERT_CN_INVALID; + ret = WinHttpSetOption(request, WINHTTP_OPTION_SECURITY_FLAGS, &flags, sizeof(flags)); + ok( ret, "failed to set security flags %lu\n", GetLastError() ); + } + + ret = WinHttpSetOption( request, WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET, NULL, 0 ); + ok( ret, "got %lu\n", GetLastError() ); + + setup_test( &info, winhttp_send_request, __LINE__ ); + ret = WinHttpSendRequest( request, NULL, 0, NULL, 0, 0, 0 ); + ok( ret, "got %lu\n", GetLastError() ); + WaitForSingleObject( info.wait, INFINITE ); + + setup_test( &info, winhttp_receive_response, __LINE__ ); + ret = WinHttpReceiveResponse( request, NULL ); + ok( ret, "got %lu\n", err ); + WaitForSingleObject( info.wait, INFINITE ); + + size = sizeof(status); + ret = WinHttpQueryHeaders( request, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL ); + ok( ret, "failed unexpectedly %lu\n", err ); + ok( status == 101, "got %lu\n", status ); + + setup_test( &info, winhttp_websocket_complete_upgrade, __LINE__ ); + socket = pWinHttpWebSocketCompleteUpgrade( request, (DWORD_PTR)context ); + ok( socket != NULL, "got %lu\n", err ); + WaitForSingleObject( info.wait, INFINITE ); + + setup_test( &info, winhttp_websocket_receive, __LINE__ ); + buffer[0] = 0; + err = pWinHttpWebSocketReceive( socket, buffer, sizeof(buffer), &size, &type ); + ok( err == ERROR_SUCCESS, "got %lu\n", err ); + WaitForSingleObject( info.wait, INFINITE ); + ok( buffer[0] == 'R', "unexpected data\n" ); + + err = pWinHttpWebSocketReceive( socket, buffer, sizeof(buffer), &size, &type ); + ok( err == ERROR_SUCCESS, "got %lu\n", err ); + + setup_test( &info, winhttp_websocket_close, __LINE__ ); + err = pWinHttpWebSocketClose( socket, 1000, (void *)"success", sizeof("success") ); + ok( err == ERROR_SUCCESS, "got %lu\n", err ); + ok( info.buflen == sizeof(*result), "got %u\n", info.buflen ); + result = (WINHTTP_WEB_SOCKET_ASYNC_RESULT *)info.buffer; + ok( result->Operation == WINHTTP_WEB_SOCKET_RECEIVE_OPERATION, "got %u\n", result->Operation ); + ok( !result->AsyncResult.dwResult, "got %Iu\n", result->AsyncResult.dwResult ); + ok( result->AsyncResult.dwError == ERROR_WINHTTP_OPERATION_CANCELLED, "got %lu\n", result->AsyncResult.dwError ); + + close_status = 0xdead; + size = sizeof(buffer) + 1; + err = pWinHttpWebSocketQueryCloseStatus( socket, &close_status, buffer, sizeof(buffer), &size ); + ok( err == ERROR_INVALID_OPERATION, "got %lu\n", err ); + ok( close_status == 0xdead, "got %u\n", close_status ); + ok( size == sizeof(buffer) + 1, "got %lu\n", size ); + + WaitForSingleObject( info.wait, INFINITE ); + + close_status = 0xdead; + size = sizeof(buffer) + 1; + err = pWinHttpWebSocketQueryCloseStatus( socket, &close_status, buffer, sizeof(buffer), &size ); + ok( err == ERROR_SUCCESS, "got %lu\n", err ); + ok( close_status == 1000, "got %u\n", close_status ); + ok( size <= sizeof(buffer), "got %lu\n", size ); + + setup_test( &info, winhttp_close_handle, __LINE__ ); + WinHttpCloseHandle( socket ); + WinHttpCloseHandle( request ); + + WaitForSingleObject( info.wait, INFINITE ); + end_test( &info, __LINE__ ); + + + /* Test socket handle close while web socket close is pending. */ + info.test = websocket_test3; + info.count = ARRAY_SIZE( websocket_test3 ); + info.index = 0; + + setup_test( &info, winhttp_open_request, __LINE__ ); + request = WinHttpOpenRequest( connection, NULL, L"/", NULL, NULL, NULL, secure ? WINHTTP_FLAG_SECURE : 0); + ok( request != NULL, "got %lu\n", err ); + + if (secure) + { + flags = SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID | + SECURITY_FLAG_IGNORE_CERT_CN_INVALID; + ret = WinHttpSetOption(request, WINHTTP_OPTION_SECURITY_FLAGS, &flags, sizeof(flags)); + ok( ret, "failed to set security flags %lu\n", GetLastError() ); + } + + ret = WinHttpSetOption( request, WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET, NULL, 0 ); + ok( ret, "got %lu\n", GetLastError() ); + + setup_test( &info, winhttp_send_request, __LINE__ ); + ret = WinHttpSendRequest( request, NULL, 0, NULL, 0, 0, 0 ); + ok( ret, "got %lu\n", GetLastError() ); + WaitForSingleObject( info.wait, INFINITE ); + + setup_test( &info, winhttp_receive_response, __LINE__ ); + ret = WinHttpReceiveResponse( request, NULL ); + ok( ret, "got %lu\n", err ); + WaitForSingleObject( info.wait, INFINITE ); + + size = sizeof(status); + ret = WinHttpQueryHeaders( request, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL ); + ok( ret, "failed unexpectedly %lu\n", err ); + ok( status == 101, "got %lu\n", status ); + + setup_test( &info, winhttp_websocket_complete_upgrade, __LINE__ ); + socket = pWinHttpWebSocketCompleteUpgrade( request, (DWORD_PTR)context ); + ok( socket != NULL, "got %lu\n", err ); + WaitForSingleObject( info.wait, INFINITE ); + + setup_test( &info, winhttp_websocket_receive, __LINE__ ); + buffer[0] = 0; + err = pWinHttpWebSocketReceive( socket, buffer, sizeof(buffer), &size, &type ); + ok( err == ERROR_SUCCESS, "got %lu\n", err ); + WaitForSingleObject( info.wait, INFINITE ); + ok( buffer[0] == 'R', "unexpected data\n" ); + + setup_test( &info, winhttp_websocket_close, __LINE__ ); + + err = pWinHttpWebSocketReceive( socket, buffer, sizeof(buffer), &size, &type ); + ok( err == ERROR_SUCCESS, "got %lu\n", err ); + + err = pWinHttpWebSocketClose( socket, 1000, (void *)"success", sizeof("success") ); + ok( err == ERROR_SUCCESS, "got %lu\n", err ); + + info.buflen = 0xdeadbeef; + WinHttpCloseHandle( socket ); + WaitForSingleObject( info.wait, INFINITE ); + + ok( info.buflen == sizeof(*result), "got %u\n", info.buflen ); + result = (WINHTTP_WEB_SOCKET_ASYNC_RESULT *)info.buffer; + ok( result->Operation == WINHTTP_WEB_SOCKET_CLOSE_OPERATION, "got %u\n", result->Operation ); + todo_wine ok( !result->AsyncResult.dwResult, "got %Iu\n", result->AsyncResult.dwResult ); + ok( result->AsyncResult.dwError == ERROR_WINHTTP_OPERATION_CANCELLED, "got %lu\n", result->AsyncResult.dwError ); + + setup_test( &info, winhttp_close_handle, __LINE__ ); + WinHttpCloseHandle( request ); + WaitForSingleObject( info.wait, INFINITE ); + end_test( &info, __LINE__ ); + + /* Test socket handle close while receive is pending. */ + info.test = websocket_test4; + info.count = ARRAY_SIZE( websocket_test4 ); + info.index = 0; + + setup_test( &info, winhttp_open_request, __LINE__ ); + request = WinHttpOpenRequest( connection, NULL, L"/", NULL, NULL, NULL, secure ? WINHTTP_FLAG_SECURE : 0); + ok( request != NULL, "got %lu\n", err ); + + if (secure) + { + flags = SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID | + SECURITY_FLAG_IGNORE_CERT_CN_INVALID; + ret = WinHttpSetOption(request, WINHTTP_OPTION_SECURITY_FLAGS, &flags, sizeof(flags)); + ok( ret, "failed to set security flags %lu\n", GetLastError() ); + } + + ret = WinHttpSetOption( request, WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET, NULL, 0 ); + ok( ret, "got %lu\n", GetLastError() ); + + setup_test( &info, winhttp_send_request, __LINE__ ); + ret = WinHttpSendRequest( request, NULL, 0, NULL, 0, 0, 0 ); + ok( ret, "got %lu\n", GetLastError() ); + WaitForSingleObject( info.wait, INFINITE ); + + setup_test( &info, winhttp_receive_response, __LINE__ ); + ret = WinHttpReceiveResponse( request, NULL ); + ok( ret, "got %lu\n", err ); + WaitForSingleObject( info.wait, INFINITE ); + + size = sizeof(status); + ret = WinHttpQueryHeaders( request, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL ); + ok( ret, "failed unexpectedly %lu\n", err ); + ok( status == 101, "got %lu\n", status ); + + setup_test( &info, winhttp_websocket_complete_upgrade, __LINE__ ); + socket = pWinHttpWebSocketCompleteUpgrade( request, (DWORD_PTR)context ); + ok( socket != NULL, "got %lu\n", err ); + WaitForSingleObject( info.wait, INFINITE ); + + setup_test( &info, winhttp_websocket_receive, __LINE__ ); + buffer[0] = 0; + err = pWinHttpWebSocketReceive( socket, buffer, sizeof(buffer), &size, &type ); + ok( err == ERROR_SUCCESS, "got %lu\n", err ); + WaitForSingleObject( info.wait, INFINITE ); + ok( buffer[0] == 'R', "unexpected data\n" ); + + setup_test( &info, winhttp_websocket_close, __LINE__ ); + + info.buflen = 0xdeadbeef; + + err = pWinHttpWebSocketReceive( socket, buffer, sizeof(buffer), &size, &type ); + ok( err == ERROR_SUCCESS, "got %lu\n", err ); + + WinHttpCloseHandle( socket ); + WaitForSingleObject( info.wait, INFINITE ); + + ok( info.buflen == sizeof(*result), "got %u\n", info.buflen ); + result = (WINHTTP_WEB_SOCKET_ASYNC_RESULT *)info.buffer; + ok( result->Operation == WINHTTP_WEB_SOCKET_RECEIVE_OPERATION, "got %u\n", result->Operation ); + ok( !result->AsyncResult.dwResult, "got %Iu\n", result->AsyncResult.dwResult ); + ok( result->AsyncResult.dwError == ERROR_WINHTTP_OPERATION_CANCELLED, "got %lu\n", result->AsyncResult.dwError ); + + setup_test( &info, winhttp_close_handle, __LINE__ ); + WinHttpCloseHandle( request ); + WaitForSingleObject( info.wait, INFINITE ); + end_test( &info, __LINE__ ); + + /* Test socket shutdown while receive is pending. */ + info.test = websocket_test5; + info.count = ARRAY_SIZE( websocket_test5 ); + info.index = 0; + + setup_test( &info, winhttp_open_request, __LINE__ ); + request = WinHttpOpenRequest( connection, NULL, L"/", NULL, NULL, NULL, secure ? WINHTTP_FLAG_SECURE : 0); + ok( request != NULL, "got %lu\n", err ); + + if (secure) + { + flags = SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID | + SECURITY_FLAG_IGNORE_CERT_CN_INVALID; + ret = WinHttpSetOption(request, WINHTTP_OPTION_SECURITY_FLAGS, &flags, sizeof(flags)); + ok( ret, "failed to set security flags %lu\n", GetLastError() ); + } + + ret = WinHttpSetOption( request, WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET, NULL, 0 ); + ok( ret, "got %lu\n", GetLastError() ); + + setup_test( &info, winhttp_send_request, __LINE__ ); + ret = WinHttpSendRequest( request, NULL, 0, NULL, 0, 0, 0 ); + ok( ret, "got %lu\n", GetLastError() ); + WaitForSingleObject( info.wait, INFINITE ); + + setup_test( &info, winhttp_receive_response, __LINE__ ); + ret = WinHttpReceiveResponse( request, NULL ); + ok( ret, "got %lu\n", err ); + WaitForSingleObject( info.wait, INFINITE ); + + size = sizeof(status); + ret = WinHttpQueryHeaders( request, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL ); + ok( ret, "failed unexpectedly %lu\n", err ); + ok( status == 101, "got %lu\n", status ); + + setup_test( &info, winhttp_websocket_complete_upgrade, __LINE__ ); + socket = pWinHttpWebSocketCompleteUpgrade( request, (DWORD_PTR)context ); + ok( socket != NULL, "got %lu\n", err ); + WaitForSingleObject( info.wait, INFINITE ); + + setup_test( &info, winhttp_websocket_receive, __LINE__ ); + buffer[0] = 0; + err = pWinHttpWebSocketReceive( socket, buffer, sizeof(buffer), &size, &type ); + ok( err == ERROR_SUCCESS, "got %lu\n", err ); + WaitForSingleObject( info.wait, INFINITE ); + ok( buffer[0] == 'R', "unexpected data\n" ); + + err = pWinHttpWebSocketReceive( socket, buffer, sizeof(buffer), &size, &type ); + ok( err == ERROR_SUCCESS, "got %lu\n", err ); + err = pWinHttpWebSocketReceive( socket, buffer, sizeof(buffer), &size, &type ); + ok( err == ERROR_INVALID_OPERATION, "got %lu\n", err ); + + setup_test( &info, winhttp_websocket_shutdown, __LINE__ ); + ws_status = (WINHTTP_WEB_SOCKET_STATUS *)info.buffer; + ws_status->eBufferType = ~0u; + err = pWinHttpWebSocketShutdown( socket, 1000, (void *)"success", sizeof("success") ); + ok( err == ERROR_SUCCESS, "got %lu\n", err ); + + close_status = 0xdead; + size = sizeof(buffer) + 1; + err = pWinHttpWebSocketQueryCloseStatus( socket, &close_status, buffer, sizeof(buffer), &size ); + ok( err == ERROR_INVALID_OPERATION, "got %lu\n", err ); + ok( close_status == 0xdead, "got %u\n", close_status ); + ok( size == sizeof(buffer) + 1, "got %lu\n", size ); + + WaitForSingleObject( info.wait, INFINITE ); + + ok( info.buflen == sizeof(*ws_status), "got %u\n", info.buflen ); + ok( ws_status->eBufferType == WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE, "got %u\n", ws_status->eBufferType ); + ok( !ws_status->dwBytesTransferred, "got %lu\n", ws_status->dwBytesTransferred ); + + close_status = 0xdead; + size = sizeof(buffer) + 1; + err = pWinHttpWebSocketQueryCloseStatus( socket, &close_status, buffer, sizeof(buffer), &size ); + ok( err == ERROR_SUCCESS, "got %lu\n", err ); + ok( close_status == 1000, "got %u\n", close_status ); + ok( size <= sizeof(buffer), "got %lu\n", size ); + + err = pWinHttpWebSocketReceive( socket, buffer, sizeof(buffer), &size, &type ); + ok( err == ERROR_INVALID_OPERATION, "got %lu\n", err ); + + info.buflen = 0xdeadbeef; + setup_test( &info, winhttp_websocket_close, __LINE__ ); + err = pWinHttpWebSocketClose( socket, 1000, (void *)"success", sizeof("success") ); + ok( err == ERROR_SUCCESS, "got %lu\n", err ); + + WaitForSingleObject( info.wait, INFINITE ); + ok( !info.buflen, "got %u\n", info.buflen ); + + setup_test( &info, winhttp_close_handle, __LINE__ ); + + WinHttpCloseHandle( socket ); + WinHttpCloseHandle( request ); + WinHttpCloseHandle( connection ); + + if (unload) + { + status = WaitForSingleObject( event, 0 ); + ok( status == WAIT_TIMEOUT, "got %#lx\n", status ); + } + WinHttpCloseHandle( session ); + WaitForSingleObject( info.wait, INFINITE ); + end_test( &info, __LINE__ ); + + if (unload) + { + status = WaitForSingleObject( event, 2000 ); + ok( status == WAIT_OBJECT_0, "got %#lx\n", status ); } CloseHandle( event ); CloseHandle( info.wait ); @@ -639,7 +1491,7 @@ struct server_info }; static int server_socket; -static HANDLE server_socket_available, server_socket_done; +static HANDLE server_socket_available, server_socket_closed, server_socket_done; static DWORD CALLBACK server_thread(LPVOID param) { @@ -674,7 +1526,7 @@ static DWORD CALLBACK server_thread(LPVOID param) do { if (c == -1) c = accept(s, NULL, NULL); - + ResetEvent(server_socket_closed); memset(buffer, 0, sizeof buffer); for(i = 0; i < sizeof buffer - 1; i++) { @@ -701,6 +1553,7 @@ static DWORD CALLBACK server_thread(LPVOID param) } shutdown(c, 2); closesocket(c); + SetEvent(server_socket_closed); c = -1; } while (!last_request); @@ -716,30 +1569,30 @@ static void test_basic_request(int port, const WCHAR *verb, const WCHAR *path) BOOL ret; ses = WinHttpOpen(NULL, WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0); - ok(ses != NULL, "failed to open session %u\n", GetLastError()); + ok( ses != NULL, "failed to open session %lu\n", GetLastError() ); - con = WinHttpConnect(ses, localhostW, port, 0); - ok(con != NULL, "failed to open a connection %u\n", GetLastError()); + con = WinHttpConnect(ses, L"localhost", port, 0); + ok( con != NULL, "failed to open a connection %lu\n", GetLastError() ); req = WinHttpOpenRequest(con, verb, path, NULL, NULL, NULL, 0); - ok(req != NULL, "failed to open a request %u\n", GetLastError()); + ok( req != NULL, "failed to open a request %lu\n", GetLastError() ); ret = WinHttpSendRequest(req, NULL, 0, NULL, 0, 0, 0); - ok(ret, "failed to send request %u\n", GetLastError()); + ok( ret, "failed to send request %lu\n", GetLastError() ); ret = WinHttpReceiveResponse(req, NULL); - ok(ret, "failed to receive response %u\n", GetLastError()); + ok( ret, "failed to receive response %lu\n", GetLastError() ); status = 0xdeadbeef; size = sizeof(status); ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL); - ok(ret, "failed to query status code %u\n", GetLastError()); - ok(status == HTTP_STATUS_OK, "request failed unexpectedly %u\n", status); + ok( ret, "failed to query status code %lu\n", GetLastError()); + ok( status == HTTP_STATUS_OK, "request failed unexpectedly %lu\n", status ); count = 0; memset(buffer, 0, sizeof(buffer)); ret = WinHttpReadData(req, buffer, sizeof buffer, &count); - ok(ret, "failed to read data %u\n", GetLastError()); + ok( ret, "failed to read data %lu\n", GetLastError() ); ok(count == sizeof page1 - 1, "count was wrong\n"); ok(!memcmp(buffer, page1, sizeof page1), "http data wrong\n"); @@ -787,31 +1640,29 @@ static void open_async_request(int port, struct test_request *req, struct info * info->count = ARRAY_SIZE( open_socket_request_test ); } - req->session = WinHttpOpen( user_agent, 0, NULL, NULL, WINHTTP_FLAG_ASYNC ); - ok(req->session != NULL, "failed to open session %u\n", GetLastError()); + req->session = WinHttpOpen( L"winetest", 0, NULL, NULL, WINHTTP_FLAG_ASYNC ); + ok( req->session != NULL, "failed to open session %lu\n", GetLastError() ); WinHttpSetOption( req->session, WINHTTP_OPTION_CONTEXT_VALUE, &info, sizeof(struct info *) ); WinHttpSetStatusCallback( req->session, check_notification, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0 ); setup_test( info, winhttp_connect, __LINE__ ); - req->connection = WinHttpConnect( req->session, localhostW, port, 0 ); - ok(req->connection != NULL, "failed to open a connection %u\n", GetLastError()); + req->connection = WinHttpConnect( req->session, L"localhost", port, 0 ); + ok( req->connection != NULL, "failed to open a connection %lu\n", GetLastError() ); setup_test( info, winhttp_open_request, __LINE__ ); req->request = WinHttpOpenRequest( req->connection, NULL, path, NULL, NULL, NULL, 0 ); - ok(req->request != NULL, "failed to open a request %u\n", GetLastError()); + ok( req->request != NULL, "failed to open a request %lu\n", GetLastError() ); setup_test( info, winhttp_send_request, __LINE__ ); ret = WinHttpSendRequest( req->request, NULL, 0, NULL, 0, 0, 0 ); - ok(ret, "failed to send request %u\n", GetLastError()); + ok( ret, "failed to send request %lu\n", GetLastError() ); } static void open_socket_request(int port, struct test_request *req, struct info *info) { - static const WCHAR socketW[] = {'/','s','o','c','k','e','t',0}; - ResetEvent( server_socket_done ); - open_async_request( port, req, info, socketW, FALSE ); + open_async_request( port, req, info, L"/socket", FALSE ); WaitForSingleObject( server_socket_available, INFINITE ); } @@ -834,7 +1685,7 @@ static void server_send_reply(struct test_request *req, struct info *info, const info->index = 0; setup_test( info, winhttp_send_request, __LINE__ ); ret = WinHttpReceiveResponse( req->request, NULL ); - ok(ret, "failed to receive response %u\n", GetLastError()); + ok( ret, "failed to receive response %lu\n", GetLastError() ); WaitForSingleObject( info->wait, INFINITE ); end_test( info, __LINE__ ); @@ -865,8 +1716,6 @@ static const struct notification close_request_test[] = static const struct notification close_allow_connection_close_request_test[] = { - { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION, NF_ALLOW }, - { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED, NF_ALLOW }, { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING }, { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING }, { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL } @@ -890,11 +1739,11 @@ static void close_request(struct test_request *req, struct info *info, BOOL allo setup_test( info, winhttp_close_handle, __LINE__ ); ret = WinHttpCloseHandle( req->request ); - ok(ret, "WinHttpCloseHandle failed: %u\n", GetLastError()); + ok( ret, "WinHttpCloseHandle failed: %lu\n", GetLastError() ); ret = WinHttpCloseHandle( req->connection ); - ok(ret, "WinHttpCloseHandle failed: %u\n", GetLastError()); + ok( ret, "WinHttpCloseHandle failed: %lu\n", GetLastError() ); ret = WinHttpCloseHandle( req->session ); - ok(ret, "WinHttpCloseHandle failed: %u\n", GetLastError()); + ok( ret, "WinHttpCloseHandle failed: %lu\n", GetLastError() ); WaitForSingleObject( info->wait, INFINITE ); end_test( info, __LINE__ ); @@ -907,38 +1756,21 @@ static const struct notification read_test[] = { winhttp_read_data, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, NF_SIGNAL } }; -static const struct notification read_allow_close_test[] = -{ - { winhttp_read_data, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_ALLOW }, - { winhttp_read_data, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_ALLOW }, - { winhttp_read_data, WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION, NF_ALLOW }, - { winhttp_read_data, WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED, NF_ALLOW }, - { winhttp_read_data, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, NF_SIGNAL } -}; - -#define read_request_data(a,b,c,d) _read_request_data(a,b,c,d,__LINE__) -static void _read_request_data(struct test_request *req, struct info *info, const char *expected_data, BOOL closing_connection, unsigned line) +#define read_request_data(a,b,c) _read_request_data(a,b,c,__LINE__) +static void _read_request_data(struct test_request *req, struct info *info, const char *expected_data, unsigned line) { char buffer[1024]; DWORD len; BOOL ret; - if (closing_connection) - { - info->test = read_allow_close_test; - info->count = ARRAY_SIZE( read_allow_close_test ); - } - else - { - info->test = read_test; - info->count = ARRAY_SIZE( read_test ); - } + info->test = read_test; + info->count = ARRAY_SIZE( read_test ); info->index = 0; setup_test( info, winhttp_read_data, line ); memset(buffer, '?', sizeof(buffer)); ret = WinHttpReadData( req->request, buffer, sizeof(buffer), NULL ); - ok(ret, "failed to read data %u\n", GetLastError()); + ok( ret, "failed to read data %lu\n", GetLastError() ); WaitForSingleObject( info->wait, INFINITE ); @@ -951,8 +1783,6 @@ static void test_persistent_connection(int port) struct test_request req; struct info info; - static const WCHAR testW[] = {'/','t','e','s','t',0}; - trace("Testing persistent connection...\n"); info.wait = CreateEventW( NULL, FALSE, FALSE, NULL ); @@ -965,11 +1795,11 @@ static void test_persistent_connection(int port) "Content-Length: 1\r\n" "\r\n" "X" ); - read_request_data( &req, &info, "X", FALSE ); + read_request_data( &req, &info, "X" ); close_request( &req, &info, FALSE ); /* chunked connection test */ - open_async_request( port, &req, &info, testW, TRUE ); + open_async_request( port, &req, &info, L"/test", TRUE ); server_read_data( "GET /test HTTP/1.1\r\n" ); server_send_reply( &req, &info, "HTTP/1.1 200 OK\r\n" @@ -979,11 +1809,11 @@ static void test_persistent_connection(int port) "\r\n" "9\r\n123456789\r\n" "0\r\n\r\n" ); - read_request_data( &req, &info, "123456789", FALSE ); + read_request_data( &req, &info, "123456789" ); close_request( &req, &info, FALSE ); /* HTTP/1.1 connections are persistent by default, no additional header is needed */ - open_async_request( port, &req, &info, testW, TRUE ); + open_async_request( port, &req, &info, L"/test", TRUE ); server_read_data( "GET /test HTTP/1.1\r\n" ); server_send_reply( &req, &info, "HTTP/1.1 200 OK\r\n" @@ -991,10 +1821,10 @@ static void test_persistent_connection(int port) "Content-Length: 2\r\n" "\r\n" "xx" ); - read_request_data( &req, &info, "xx", FALSE ); + read_request_data( &req, &info, "xx" ); close_request( &req, &info, FALSE ); - open_async_request( port, &req, &info, testW, TRUE ); + open_async_request( port, &req, &info, L"/test", TRUE ); server_read_data( "GET /test HTTP/1.1\r\n" ); server_send_reply( &req, &info, "HTTP/1.1 200 OK\r\n" @@ -1003,34 +1833,308 @@ static void test_persistent_connection(int port) "Connection: close\r\n" "\r\n" "yy" ); + read_request_data( &req, &info, "yy" ); close_request( &req, &info, TRUE ); SetEvent( server_socket_done ); CloseHandle( info.wait ); + WaitForSingleObject( server_socket_closed, INFINITE ); +} + +struct test_recursion_context +{ + HANDLE request; + HANDLE wait; + LONG recursion_count, max_recursion_query, max_recursion_read; + BOOL read_from_callback; + BOOL have_sync_callback; + DWORD call_receive_response_status; + DWORD main_thread_id; + DWORD receive_response_thread_id; + BOOL headers_available; + DWORD total_len; + BYTE *send_buffer; +}; + +/* The limit is 128 before Win7 and 3 on newer Windows. */ +#define TEST_RECURSION_LIMIT 128 + +static void CALLBACK test_recursion_callback( HINTERNET handle, DWORD_PTR context_ptr, + DWORD status, void *buffer, DWORD buflen ) +{ + struct test_recursion_context *context = (struct test_recursion_context *)context_ptr; + DWORD err; + BOOL ret; + BYTE b; + + switch (status) + { + case WINHTTP_CALLBACK_STATUS_SENDING_REQUEST: + case WINHTTP_CALLBACK_STATUS_REQUEST_SENT: + case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE: + if (status == context->call_receive_response_status) + { + if (context->total_len) + { + ret = WinHttpWriteData( context->request, context->send_buffer, context->total_len, NULL ); + ok(ret, "failed.\n"); + } + else + { + context->receive_response_thread_id = GetCurrentThreadId(); + ret = WinHttpReceiveResponse( context->request, NULL ); + ok( ret, "failed to receive response, GetLastError() %lu\n", GetLastError() ); + } + } + break; + + case WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE: + trace("WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE thread %04lx.\n", GetCurrentThreadId()); + context->receive_response_thread_id = GetCurrentThreadId(); + ret = WinHttpReceiveResponse( context->request, NULL ); + ok( ret, "failed to receive response, GetLastError() %lu\n", GetLastError() ); + break; + + case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE: + if (context->call_receive_response_status != WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE) + ok( GetCurrentThreadId() != context->main_thread_id, + "expected callback to be called from the other thread, got main.\n" ); + context->headers_available = TRUE; + SetEvent( context->wait ); + break; + + case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE: + { + DWORD len; + + if (!context->read_from_callback) + { + SetEvent( context->wait ); + break; + } + + if (!*(DWORD *)buffer) + { + SetEvent( context->wait ); + break; + } + + ok( context->recursion_count < TEST_RECURSION_LIMIT, + "got %lu, thread %#lx\n", context->recursion_count, GetCurrentThreadId() ); + context->max_recursion_query = max( context->max_recursion_query, context->recursion_count ); + InterlockedIncrement( &context->recursion_count ); + b = 0xff; + len = 0xdeadbeef; + ret = WinHttpReadData( context->request, &b, 1, &len ); + err = GetLastError(); + ok( ret, "failed to read data, GetLastError() %lu\n", err ); + ok( err == ERROR_SUCCESS || err == ERROR_IO_PENDING, "got %lu\n", err ); + ok( b != 0xff, "got %#x.\n", b ); + ok( len == 1, "got %lu.\n", len ); + if (err == ERROR_SUCCESS) context->have_sync_callback = TRUE; + InterlockedDecrement( &context->recursion_count ); + break; + } + + case WINHTTP_CALLBACK_STATUS_READ_COMPLETE: + { + static DWORD len; + + if (!buflen) + { + SetEvent( context->wait ); + break; + } + ok( context->recursion_count < TEST_RECURSION_LIMIT, + "got %lu, thread %#lx\n", context->recursion_count, GetCurrentThreadId() ); + context->max_recursion_read = max( context->max_recursion_read, context->recursion_count ); + context->read_from_callback = TRUE; + InterlockedIncrement( &context->recursion_count ); + len = 0xdeadbeef; + /* Use static variable len here so write to it doesn't destroy the stack on old Windows which + * doesn't set the value at once. */ + ret = WinHttpQueryDataAvailable( context->request, &len ); + err = GetLastError(); + ok( ret, "failed to query data available, GetLastError() %lu\n", err ); + ok( err == ERROR_SUCCESS || err == ERROR_IO_PENDING, "got %lu\n", err ); + ok( len != 0xdeadbeef || broken( len == 0xdeadbeef ) /* Win7 */, "got %lu.\n", len ); + if (err == ERROR_SUCCESS) context->have_sync_callback = TRUE; + InterlockedDecrement( &context->recursion_count ); + break; + } + + case WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE: + if (!context->headers_available + && context->call_receive_response_status == WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE) + ok( GetCurrentThreadId() == context->receive_response_thread_id, + "expected callback to be called from the same thread, got %lx.\n", GetCurrentThreadId() ); + break; + } +} + +static void test_recursion(void) +{ + static DWORD request_callback_status_tests[] = + { + WINHTTP_CALLBACK_STATUS_SENDING_REQUEST, + WINHTTP_CALLBACK_STATUS_REQUEST_SENT, + }; + struct test_recursion_context context; + HANDLE session, connection, request; + DWORD size, status, err; + char buffer[1024]; + unsigned int i; + BOOL ret; + BYTE b; + + memset( &context, 0, sizeof(context) ); + + context.wait = CreateEventW( NULL, FALSE, FALSE, NULL ); + context.main_thread_id = GetCurrentThreadId(); + + session = WinHttpOpen( L"winetest", 0, NULL, NULL, WINHTTP_FLAG_ASYNC ); + ok( !!session, "failed to open session, GetLastError() %lu\n", GetLastError() ); + + WinHttpSetStatusCallback( session, test_recursion_callback, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0 ); + + connection = WinHttpConnect( session, L"test.winehq.org", 0, 0 ); + ok( !!connection, "failed to open a connection, GetLastError() %lu\n", GetLastError() ); + + request = WinHttpOpenRequest( connection, NULL, L"/tests/hello.html", NULL, NULL, NULL, 0 ); + ok( !!request, "failed to open a request, GetLastError() %lu\n", GetLastError() ); + + context.request = request; + + ret = WinHttpReceiveResponse( request, NULL ); + ok( ret, "failed to receive response, GetLastError() %lu\n", GetLastError() ); + + context.call_receive_response_status = WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE; + context.total_len = 1; + context.send_buffer = &b; + b = 0; + ret = WinHttpSendRequest( request, NULL, 0, NULL, 0, context.total_len, (DWORD_PTR)&context ); + err = GetLastError(); + if (!ret && (err == ERROR_WINHTTP_CANNOT_CONNECT || err == ERROR_WINHTTP_TIMEOUT)) + { + skip("Connection failed, skipping\n"); + WinHttpSetStatusCallback( session, NULL, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0 ); + WinHttpCloseHandle( request ); + WinHttpCloseHandle( connection ); + WinHttpCloseHandle( session ); + CloseHandle( context.wait ); + return; + } + ok( ret, "failed to send request, GetLastError() %lu\n", GetLastError() ); + + WaitForSingleObject( context.wait, INFINITE ); + context.total_len = 0; + context.send_buffer = NULL; + + size = sizeof(status); + ret = WinHttpQueryHeaders( request, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, + &status, &size, NULL ); + ok( ret, "request failed, GetLastError() %lu\n", GetLastError() ); + ok( status == 200, "request failed unexpectedly, status %lu\n", status ); + + ret = WinHttpQueryDataAvailable( request, NULL ); + ok( ret, "failed to query data available, GetLastError() %lu\n", GetLastError() ); + + WaitForSingleObject( context.wait, INFINITE ); + + ret = WinHttpReadData( request, &b, 1, NULL ); + ok( ret, "failed to read data, GetLastError() %lu\n", GetLastError() ); + + WaitForSingleObject( context.wait, INFINITE ); + if (context.have_sync_callback) + { + ok( context.max_recursion_query >= 2, "got %lu\n", context.max_recursion_query ); + ok( context.max_recursion_read >= 2, "got %lu\n", context.max_recursion_read ); + } + else skip( "no sync callbacks\n"); + + WinHttpCloseHandle( request ); + + for (i = 0; i < ARRAY_SIZE(request_callback_status_tests); ++i) + { + winetest_push_context( "i %u", i ); + + request = WinHttpOpenRequest( connection, NULL, L"/tests/hello.html", NULL, NULL, NULL, 0 ); + ok( !!request, "failed to open a request, GetLastError() %lu\n", GetLastError() ); + + context.request = request; + context.call_receive_response_status = request_callback_status_tests[i]; + context.headers_available = FALSE; + + ret = WinHttpSendRequest( request, NULL, 0, NULL, 0, 0, (DWORD_PTR)&context ); + err = GetLastError(); + if (!ret && (err == ERROR_WINHTTP_CANNOT_CONNECT || err == ERROR_WINHTTP_TIMEOUT)) + { + skip("Connection failed, skipping\n"); + WinHttpSetStatusCallback( session, NULL, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0 ); + WinHttpCloseHandle( request ); + WinHttpCloseHandle( connection ); + WinHttpCloseHandle( session ); + CloseHandle( context.wait ); + winetest_pop_context(); + return; + } + + WaitForSingleObject( context.wait, INFINITE ); + + ret = WinHttpReadData( request, buffer, sizeof(buffer), NULL ); + ok( ret, "failed to read data, GetLastError() %lu\n", GetLastError() ); + + WaitForSingleObject( context.wait, INFINITE ); + + WinHttpCloseHandle( request ); + winetest_pop_context(); + } + + WinHttpSetStatusCallback( session, NULL, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0 ); + WinHttpCloseHandle( connection ); + WinHttpCloseHandle( session ); + CloseHandle( context.wait ); } START_TEST (notification) { - static const WCHAR quitW[] = {'/','q','u','i','t',0}; + HMODULE mod = GetModuleHandleA( "winhttp.dll" ); struct server_info si; HANDLE thread; DWORD ret; - test_connection_cache(); - test_redirect(); + pWinHttpWebSocketClose = (void *)GetProcAddress( mod, "WinHttpWebSocketClose" ); + pWinHttpWebSocketCompleteUpgrade = (void *)GetProcAddress( mod, "WinHttpWebSocketCompleteUpgrade" ); + pWinHttpWebSocketQueryCloseStatus = (void *)GetProcAddress( mod, "WinHttpWebSocketQueryCloseStatus" ); + pWinHttpWebSocketReceive = (void *)GetProcAddress( mod, "WinHttpWebSocketReceive" ); + pWinHttpWebSocketSend = (void *)GetProcAddress( mod, "WinHttpWebSocketSend" ); + pWinHttpWebSocketShutdown = (void *)GetProcAddress( mod, "WinHttpWebSocketShutdown" ); + + test_connection_cache( FALSE ); + test_redirect( FALSE ); + winetest_push_context( "async" ); + test_connection_cache( TRUE ); + test_redirect( TRUE ); + winetest_pop_context(); test_async(); + test_websocket( FALSE ); + winetest_push_context( "secure" ); + test_websocket( TRUE ); + winetest_pop_context(); + test_recursion(); si.event = CreateEventW( NULL, 0, 0, NULL ); si.port = 7533; thread = CreateThread( NULL, 0, server_thread, &si, 0, NULL ); - ok(thread != NULL, "failed to create thread %u\n", GetLastError()); + ok( thread != NULL, "failed to create thread %lu\n", GetLastError() ); server_socket_available = CreateEventW( NULL, 0, 0, NULL ); + server_socket_closed = CreateEventW( NULL, 0, 0, NULL ); server_socket_done = CreateEventW( NULL, 0, 0, NULL ); ret = WaitForSingleObject( si.event, 10000 ); - ok(ret == WAIT_OBJECT_0, "failed to start winhttp test server %u\n", GetLastError()); + ok( ret == WAIT_OBJECT_0, "failed to start winhttp test server %lu\n", GetLastError() ); if (ret != WAIT_OBJECT_0) { CloseHandle(thread); @@ -1040,10 +2144,11 @@ START_TEST (notification) test_persistent_connection( si.port ); /* send the basic request again to shutdown the server thread */ - test_basic_request( si.port, NULL, quitW ); + test_basic_request( si.port, NULL, L"/quit" ); WaitForSingleObject( thread, 3000 ); CloseHandle( thread ); CloseHandle( server_socket_available ); CloseHandle( server_socket_done ); + CloseHandle( server_socket_closed ); } diff --git a/modules/rostests/winetests/winhttp/url.c b/modules/rostests/winetests/winhttp/url.c index 37a6e4a10b4..fadf8b850ca 100644 --- a/modules/rostests/winetests/winhttp/url.c +++ b/modules/rostests/winetests/winhttp/url.c @@ -33,80 +33,46 @@ static WCHAR username[] = {'u','s','e','r','n','a','m','e',0}; static WCHAR password[] = {'p','a','s','s','w','o','r','d',0}; static WCHAR about[] = {'/','s','i','t','e','/','a','b','o','u','t',0}; static WCHAR query[] = {'?','q','u','e','r','y',0}; -static WCHAR escape[] = {' ','!','"','#','$','%','&','\'','(',')','*','+',',','-','.','/',':',';','<','=','>','?','@','[','\\',']','^','_','`','{','|','}','~',0}; +static WCHAR escape[] = {' ','!','"','#','$','%','&','\'','(',')','*','+',',','-','.','/',':',';','<','=','>', + '?','@','[','\\',']','^','_','`','{','|','}','~',0}; static WCHAR escape2[] = {'\r',0x1f,' ','\n',0x7f,'\r','\n',0}; static WCHAR escape3[] = {'?','t','e','x','t','=',0xfb00,0}; static WCHAR escape4[] = {'/','t','e','x','t','=',0xfb00,0}; -static const WCHAR url1[] = - {'h','t','t','p',':','/','/','u','s','e','r','n','a','m','e',':','p','a','s','s','w','o','r','d', - '@','w','w','w','.','w','i','n','e','h','q','.','o','r','g','/','s','i','t','e','/','a','b','o','u','t','?','q','u','e','r','y',0}; -static const WCHAR url2[] = {'h','t','t','p',':','/','/','u','s','e','r','n','a','m','e',':',0}; -static const WCHAR url3[] = - {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g','/','s','i','t','e','/','a','b','o','u','t','?','q','u','e','r','y',0}; -static const WCHAR url4[] = {'h','t','t','p',':','/','/',0}; -static const WCHAR url5[] = - {'f','t','p',':','/','/','u','s','e','r','n','a','m','e',':','p','a','s','s','w','o','r','d', - '@','w','w','w','.','w','i','n','e','h','q','.','o','r','g',':','8','0','/','s','i','t','e','/','a','b','o','u','t','?','q','u','e','r','y',0}; -static const WCHAR url6[] = - {'h','t','t','p',':','/','/','u','s','e','r','n','a','m','e',':','p','a','s','s','w','o','r','d', - '@','w','w','w','.','w','i','n','e','h','q','.','o','r','g',':','4','2','/','s','i','t','e','/','a','b','o','u','t','?','q','u','e','r','y',0}; -static const WCHAR url7[] = - {'h','t','t','p',':','/','/','u','s','e','r','n','a','m','e',':','p','a','s','s','w','o','r','d', - '@','w','w','w','.','w','i','n','e','h','q','.','o','r','g','/','s','i','t','e','/','a','b','o','u','t', - '%','2','0','!','%','2','2','%','2','3','$','%','2','5','&','\'','(',')','*','+',',','-','.','/',':',';','%','3','C','=','%','3','E','?','@','%', - '5','B','%','5','C','%','5','D','%','5','E','_','%','6','0','%','7','B','%','7','C','%','7','D','%','7','E',0}; -static const WCHAR url8[] = - {'h','t','t','p',':','/','/','u','s','e','r','n','a','m','e',':','p','a','s','s','w','o','r','d', - '@','w','w','w','.','w','i','n','e','h','q','.','o','r','g',':','0','/','s','i','t','e','/','a','b','o','u','t','?','q','u','e','r','y',0}; -static const WCHAR url9[] = - {'h','t','t','p',':','/','/','u','s','e','r','n','a','m','e',':','p','a','s','s','w','o','r','d', - '@','w','w','w','.','w','i','n','e','h','q','.','o','r','g',':','8','0','/','s','i','t','e','/','a','b','o','u','t','?','q','u','e','r','y',0}; -static const WCHAR url10[] = - {'h','t','t','p','s',':','/','/','u','s','e','r','n','a','m','e',':','p','a','s','s','w','o','r','d', - '@','w','w','w','.','w','i','n','e','h','q','.','o','r','g',':','4','4','3','/','s','i','t','e','/','a','b','o','u','t','?','q','u','e','r','y',0}; -static const WCHAR url11[] = - {'h','t','t','p',':','/','/','e','x','a','m','p','l','e','.','n','e','t','/','p','a','t','h','?','v','a','r','1','=','e','x','a','m','p','l','e','@','e','x','a','m','p','l','e','.','c','o','m','&','v','a','r','2','=','x','&','v','a','r','3','=','y', 0}; -static const WCHAR url12[] = - {'h','t','t','p','s',':','/','/','t','o','o','l','s','.','g','o','o','g','l','e','.','c','o','m','/','s','e','r','v','i','c','e','/','u','p','d','a','t','e','2','?','w','=','3',':','B','x','D','H','o','W','y','8','e','z','M',0}; -static const WCHAR url13[] = - {'h','t','t','p',':','/','/','w','i','n','e','h','q','.','o',' ','g','/','p','a','t','h',' ','w','i','t','h',' ','s','p','a','c','e','s',0}; -static const WCHAR url14[] = {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g','/','t','e','s','t',0}; -static const WCHAR url15[] = {'h','t','t','p',':','/','/','w','i','n','e','h','q','.','o','r','g',':','6','5','5','3','6',0}; -static const WCHAR url16[] = {'h','t','t','p',':','/','/','w','i','n','e','h','q','.','o','r','g',':','0',0}; -static const WCHAR url17[] = {'h','t','t','p',':','/','/','w','i','n','e','h','q','.','o','r','g',':',0}; -static const WCHAR url18[] = - {'h','t','t','p',':','/','/','%','0','D','%','1','F','%','2','0','%','0','A','%','7','F','%','0','D','%','0','A',0}; -static const WCHAR url19[] = - {'h','t','t','p',':','/','/','?','t','e','x','t','=',0xfb00,0}; -static const WCHAR url20[] = - {'h','t','t','p',':','/','/','/','t','e','x','t','=',0xfb00,0}; -static const WCHAR url21[] = - {'h','t','t','p','s',':','/','/','n','b','a','2','k','1','9','-','w','s','.','2','k','s','p','o','r','t','s','.','c','o','m',':','1','9','1','3','3', - '/','n','b','a','/','v','4','/','A','c','c','o','u','n','t','s','/','g','e','t','_','a','c','c','o','u','n','t','?','x','=','3','7','8','9','5','2', - '6','7','7','5','2','6','5','6','6','3','8','7','6',0}; +static const WCHAR url1[] = L"http://username:password@www.winehq.org/site/about?query"; +static const WCHAR url2[] = L"http://username:"; +static const WCHAR url3[] = L"http://www.winehq.org/site/about?query"; +static const WCHAR url4[] = L"http://"; +static const WCHAR url5[] = L"ftp://username:password@www.winehq.org:80/site/about?query"; +static const WCHAR url6[] = L"http://username:password@www.winehq.org:42/site/about?query"; +static const WCHAR url7[] = L"http://username:password@www.winehq.org/site/about%20!%22%23$%25&'()" + "*+,-./:;%3C=%3E?@%5B%5C%5D%5E_%60%7B%7C%7D%7E"; +static const WCHAR url8[] = L"http://username:password@www.winehq.org:0/site/about?query"; +static const WCHAR url9[] = L"http://username:password@www.winehq.org:80/site/about?query"; +static const WCHAR url10[] = L"https://username:password@www.winehq.org:443/site/about?query"; +static const WCHAR url11[] = L"http://example.net/path?var1=example@example.com&var2=x&var3=y"; +static const WCHAR url12[] = L"https://tools.google.com/service/update2?w=3:BxDHoWy8ezM"; +static const WCHAR url13[] = L"http://winehq.o g/path with spaces"; +static const WCHAR url14[] = L"http://www.winehq.org/test"; +static const WCHAR url15[] = L"http://winehq.org:65536"; +static const WCHAR url16[] = L"http://winehq.org:0"; +static const WCHAR url17[] = L"http://winehq.org:"; +static const WCHAR url18[] = L"http://%0D%1F%20%0A%7F%0D%0A"; +static const WCHAR url19[] = L"http://?text=\xfb00"; +static const WCHAR url20[] = L"http:///text=\xfb00"; +static const WCHAR url21[] = L"https://nba2k19-ws.2ksports.com:19133/nba/v4/Accounts/get_account?x=3789526775265663876"; +static const WCHAR url22[] = L"http://winehq.org:/"; -static const WCHAR url_k1[] = - {'h','t','t','p',':','/','/','u','s','e','r','n','a','m','e',':','p','a','s','s','w','o','r','d', - '@','w','w','w','.','w','i','n','e','h','q','.','o','r','g','/','s','i','t','e','/','a','b','o','u','t',0}; -static const WCHAR url_k2[] = - {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g',0}; -static const WCHAR url_k3[] = - {'h','t','t','p','s',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g','/','p','o','s','t','?',0}; -static const WCHAR url_k4[] = - {'H','T','T','P',':','w','w','w','.','w','i','n','e','h','q','.','o','r','g',0}; -static const WCHAR url_k5[] = - {'h','t','t','p',':','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g',0}; -static const WCHAR url_k6[] = - {'w','w','w','.','w','i','n','e','h','q','.','o','r','g',0}; -static const WCHAR url_k7[] = - {'w','w','w',0}; -static const WCHAR url_k8[] = - {'h','t','t','p',0}; -static const WCHAR url_k9[] = - {'h','t','t','p',':','/','/','w','i','n','e','h','q','?',0}; -static const WCHAR url_k10[] = - {'h','t','t','p',':','/','/','w','i','n','e','h','q','/','p','o','s','t',';','a',0}; +static const WCHAR url_k1[] = L"http://username:password@www.winehq.org/site/about"; +static const WCHAR url_k2[] = L"http://www.winehq.org"; +static const WCHAR url_k3[] = L"https://www.winehq.org/post?"; +static const WCHAR url_k4[] = L"HTTP:www.winehq.org"; +static const WCHAR url_k5[] = L"http:/www.winehq.org"; +static const WCHAR url_k6[] = L"www.winehq.org"; +static const WCHAR url_k7[] = L"www"; +static const WCHAR url_k8[] = L"http"; +static const WCHAR url_k9[] = L"http://winehq?"; +static const WCHAR url_k10[] = L"http://winehq/post;a"; static void fill_url_components( URL_COMPONENTS *uc ) { @@ -139,31 +105,31 @@ static void WinHttpCreateUrl_test( void ) SetLastError( 0xdeadbeef ); ret = WinHttpCreateUrl( NULL, 0, NULL, &len ); ok( !ret, "expected failure\n" ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER got %u\n", GetLastError() ); - ok( len == ~0u, "expected len ~0u got %u\n", len ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER got %lu\n", GetLastError() ); + ok( len == ~0u, "expected len ~0u got %lu\n", len ); /* zero'ed components */ memset( &uc, 0, sizeof(URL_COMPONENTS) ); SetLastError( 0xdeadbeef ); ret = WinHttpCreateUrl( &uc, 0, NULL, &len ); ok( !ret, "expected failure\n" ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER got %u\n", GetLastError() ); - ok( len == ~0u, "expected len ~0u got %u\n", len ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER got %lu\n", GetLastError() ); + ok( len == ~0u, "expected len ~0u got %lu\n", len ); /* valid components, NULL url, NULL length */ fill_url_components( &uc ); SetLastError( 0xdeadbeef ); ret = WinHttpCreateUrl( &uc, 0, NULL, NULL ); ok( !ret, "expected failure\n" ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER got %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER got %lu\n", GetLastError() ); /* valid components, NULL url, insufficient length */ len = 0; SetLastError( 0xdeadbeef ); ret = WinHttpCreateUrl( &uc, 0, NULL, &len ); ok( !ret, "expected failure\n" ); - ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "expected ERROR_INSUFFICIENT_BUFFER got %u\n", GetLastError() ); - ok( len == 57, "expected len 57 got %u\n", len ); + ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "expected ERROR_INSUFFICIENT_BUFFER got %lu\n", GetLastError() ); + ok( len == 57, "expected len 57 got %lu\n", len ); /* valid components, NULL url, sufficient length */ SetLastError( 0xdeadbeef ); @@ -172,8 +138,8 @@ static void WinHttpCreateUrl_test( void ) err = GetLastError(); ok( !ret, "expected failure\n" ); ok( err == ERROR_INVALID_PARAMETER || broken(err == ERROR_INSUFFICIENT_BUFFER) /* < win7 */, - "expected ERROR_INVALID_PARAMETER got %u\n", GetLastError() ); - ok( len == 256 || broken(len == 57) /* < win7 */, "expected len 256 got %u\n", len ); + "expected ERROR_INVALID_PARAMETER got %lu\n", GetLastError() ); + ok( len == 256 || broken(len == 57) /* < win7 */, "expected len 256 got %lu\n", len ); /* correct size, NULL url */ fill_url_components( &uc ); @@ -182,8 +148,8 @@ static void WinHttpCreateUrl_test( void ) err = GetLastError(); ok( !ret, "expected failure\n" ); ok( err == ERROR_INVALID_PARAMETER || broken(err == ERROR_INSUFFICIENT_BUFFER) /* < win7 */, - "expected ERROR_INVALID_PARAMETER got %u\n", GetLastError() ); - ok( len == 256 || broken(len == 57) /* < win7 */, "expected len 256 got %u\n", len ); + "expected ERROR_INVALID_PARAMETER got %lu\n", GetLastError() ); + ok( len == 256 || broken(len == 57) /* < win7 */, "expected len 256 got %lu\n", len ); /* valid components, allocated url, short length */ SetLastError( 0xdeadbeef ); @@ -192,8 +158,8 @@ static void WinHttpCreateUrl_test( void ) len = 2; ret = WinHttpCreateUrl( &uc, 0, url, &len ); ok( !ret, "expected failure\n" ); - ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "expected ERROR_INSUFFICIENT_BUFFER got %u\n", GetLastError() ); - ok( len == 57, "expected len 57 got %u\n", len ); + ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "expected ERROR_INSUFFICIENT_BUFFER got %lu\n", GetLastError() ); + ok( len == 57, "expected len 57 got %lu\n", len ); /* allocated url, NULL scheme */ SetLastError( 0xdeadbeef ); @@ -203,8 +169,8 @@ static void WinHttpCreateUrl_test( void ) ret = WinHttpCreateUrl( &uc, 0, url, &len ); ok( ret, "expected success\n" ); ok( GetLastError() == ERROR_SUCCESS || broken(GetLastError() == 0xdeadbeef) /* < win7 */, - "expected ERROR_SUCCESS got %u\n", GetLastError() ); - ok( len == 56, "expected len 56 got %u\n", len ); + "expected ERROR_SUCCESS got %lu\n", GetLastError() ); + ok( len == 56, "expected len 56 got %lu\n", len ); ok( !lstrcmpW( url, url1 ), "url doesn't match\n" ); /* allocated url, 0 scheme */ @@ -214,7 +180,7 @@ static void WinHttpCreateUrl_test( void ) len = 256; ret = WinHttpCreateUrl( &uc, 0, url, &len ); ok( ret, "expected success\n" ); - ok( len == 56, "expected len 56 got %u\n", len ); + ok( len == 56, "expected len 56 got %lu\n", len ); /* valid components, allocated url */ fill_url_components( &uc ); @@ -222,7 +188,7 @@ static void WinHttpCreateUrl_test( void ) len = 256; ret = WinHttpCreateUrl( &uc, 0, url, &len ); ok( ret, "expected success\n" ); - ok( len == 56, "expected len 56 got %d\n", len ); + ok( len == 56, "expected len 56 got %lu\n", len ); ok( !lstrcmpW( url, url1 ), "url doesn't match\n" ); /* valid username, NULL password */ @@ -240,7 +206,7 @@ static void WinHttpCreateUrl_test( void ) len = 256; ret = WinHttpCreateUrl( &uc, 0, url, &len ); ok( ret, "expected success\n" ); - ok( len == 56, "expected len 56 got %u\n", len ); + ok( len == 56, "expected len 56 got %lu\n", len ); ok( !lstrcmpW( url, url2 ), "url doesn't match\n" ); /* valid password, NULL username */ @@ -251,7 +217,7 @@ static void WinHttpCreateUrl_test( void ) len = 256; ret = WinHttpCreateUrl( &uc, 0, url, &len ); ok( !ret, "expected failure\n" ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER got %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER got %lu\n", GetLastError() ); /* valid password, empty username */ fill_url_components( &uc ); @@ -269,7 +235,7 @@ static void WinHttpCreateUrl_test( void ) len = 256; ret = WinHttpCreateUrl( &uc, 0, url, &len ); ok( ret, "expected success\n" ); - ok( len == 38, "expected len 38 got %u\n", len ); + ok( len == 38, "expected len 38 got %lu\n", len ); ok( !lstrcmpW( url, url3 ), "url doesn't match\n" ); /* empty username, empty password */ @@ -280,7 +246,7 @@ static void WinHttpCreateUrl_test( void ) len = 256; ret = WinHttpCreateUrl( &uc, 0, url, &len ); ok( ret, "expected success\n" ); - ok( len == 56, "expected len 56 got %u\n", len ); + ok( len == 56, "expected len 56 got %lu\n", len ); ok( !lstrcmpW( url, url4 ), "url doesn't match\n" ); /* nScheme has lower precedence than lpszScheme */ @@ -291,7 +257,7 @@ static void WinHttpCreateUrl_test( void ) len = 256; ret = WinHttpCreateUrl( &uc, 0, url, &len ); ok( ret, "expected success\n" ); - ok( len == lstrlenW( url5 ), "expected len %d got %u\n", lstrlenW( url5 ) + 1, len ); + ok( len == lstrlenW( url5 ), "expected len %d got %lu\n", lstrlenW( url5 ) + 1, len ); ok( !lstrcmpW( url, url5 ), "url doesn't match\n" ); /* non-standard port */ @@ -302,7 +268,7 @@ static void WinHttpCreateUrl_test( void ) len = 256; ret = WinHttpCreateUrl( &uc, 0, url, &len ); ok( ret, "expected success\n" ); - ok( len == 59, "expected len 59 got %u\n", len ); + ok( len == 59, "expected len 59 got %lu\n", len ); ok( !lstrcmpW( url, url6 ), "url doesn't match\n" ); /* escape extra info */ @@ -313,7 +279,7 @@ static void WinHttpCreateUrl_test( void ) len = 256; ret = WinHttpCreateUrl( &uc, ICU_ESCAPE, url, &len ); ok( ret, "expected success\n" ); - ok( len == 113, "expected len 113 got %u\n", len ); + ok( len == 113, "expected len 113 got %lu\n", len ); ok( !lstrcmpW( url, url7 ), "url doesn't match %s\n", wine_dbgstr_w(url) ); /* escape extra info */ @@ -325,7 +291,7 @@ static void WinHttpCreateUrl_test( void ) len = 256; ret = WinHttpCreateUrl( &uc, ICU_ESCAPE, url, &len ); ok( ret, "expected success\n" ); - ok( len == lstrlenW(url18), "expected len %u got %u\n", lstrlenW(url18), len ); + ok( len == lstrlenW(url18), "expected len %u got %lu\n", lstrlenW(url18), len ); ok( !lstrcmpW( url, url18 ), "url doesn't match\n" ); /* extra info with Unicode characters */ @@ -338,8 +304,8 @@ static void WinHttpCreateUrl_test( void ) SetLastError( 0xdeadbeef ); ret = WinHttpCreateUrl( &uc, ICU_ESCAPE, url, &len ); err = GetLastError(); - ok( !ret, "expected failure\n" ); - ok( err == ERROR_INVALID_PARAMETER, "got %u\n", err ); + ok( !ret || GetACP() == CP_UTF8, "expected failure\n" ); + ok( err == ERROR_INVALID_PARAMETER || (!err && GetACP() == CP_UTF8), "got %lu\n", err ); /* extra info with Unicode characters, no ICU_ESCAPE */ memset( &uc, 0, sizeof(uc) ); @@ -352,7 +318,7 @@ static void WinHttpCreateUrl_test( void ) ok( ret || broken(!ret) /* < win7 */, "expected success\n" ); if (ret) { - ok( len == lstrlenW(url19), "expected len %u got %u\n", lstrlenW(url19), len ); + ok( len == lstrlenW(url19), "expected len %u got %lu\n", lstrlenW(url19), len ); ok( !lstrcmpW( url, url19 ), "url doesn't match %s\n", wine_dbgstr_w(url) ); } @@ -365,7 +331,7 @@ static void WinHttpCreateUrl_test( void ) len = 256; ret = WinHttpCreateUrl( &uc, ICU_ESCAPE, url, &len ); ok( ret, "expected success\n" ); - ok( len == lstrlenW(url18), "expected len %u got %u\n", lstrlenW(url18), len ); + ok( len == lstrlenW(url18), "expected len %u got %lu\n", lstrlenW(url18), len ); ok( !lstrcmpW( url, url18 ), "url doesn't match\n" ); /* path with Unicode characters */ @@ -378,8 +344,8 @@ static void WinHttpCreateUrl_test( void ) SetLastError( 0xdeadbeef ); ret = WinHttpCreateUrl( &uc, ICU_ESCAPE, url, &len ); err = GetLastError(); - ok( !ret, "expected failure\n" ); - ok( err == ERROR_INVALID_PARAMETER, "got %u\n", err ); + ok( !ret || GetACP() == CP_UTF8, "expected failure\n" ); + ok( err == ERROR_INVALID_PARAMETER || (!err && GetACP() == CP_UTF8), "got %lu\n", err ); /* path with Unicode characters, no ICU_ESCAPE */ memset( &uc, 0, sizeof(uc) ); @@ -392,7 +358,7 @@ static void WinHttpCreateUrl_test( void ) ok( ret || broken(!ret) /* < win7 */, "expected success\n" ); if (ret) { - ok( len == lstrlenW(url20), "expected len %u got %u\n", lstrlenW(url20), len ); + ok( len == lstrlenW(url20), "expected len %u got %lu\n", lstrlenW(url20), len ); ok( !lstrcmpW( url, url20 ), "url doesn't match %s\n", wine_dbgstr_w(url) ); } @@ -406,7 +372,7 @@ static void WinHttpCreateUrl_test( void ) len = 256; ret = WinHttpCreateUrl( &uc, 0, url, &len ); ok( ret, "expected success\n" ); - ok( len == 58, "expected len 58 got %u\n", len ); + ok( len == 58, "expected len 58 got %lu\n", len ); ok( !lstrcmpW( url, url8 ), "url doesn't match\n" ); HeapFree( GetProcessHeap(), 0, url ); @@ -427,10 +393,6 @@ static void reset_url_components( URL_COMPONENTS *uc ) static void WinHttpCrackUrl_test( void ) { - static const WCHAR hostnameW[] = - {'w','i','n','e','h','q','.','o',' ','g',0}; - static const WCHAR pathW[] = - {'/','p','a','t','h','%','2','0','w','i','t','h','%','2','0','s','p','a','c','e','s',0}; URL_COMPONENTSW uc; WCHAR scheme[20], user[20], pass[20], host[40], path[80], extra[40]; DWORD error; @@ -456,21 +418,21 @@ static void WinHttpCrackUrl_test( void ) uc.dwExtraInfoLength = 20; ret = WinHttpCrackUrl( url1, 0, 0, &uc ); - ok( ret, "WinHttpCrackUrl failed le=%u\n", GetLastError() ); + ok( ret, "WinHttpCrackUrl failed le = %lu\n", GetLastError() ); ok( uc.nScheme == INTERNET_SCHEME_HTTP, "unexpected scheme: %u\n", uc.nScheme ); ok( !memcmp( uc.lpszScheme, http, sizeof(http) ), "unexpected scheme: %s\n", wine_dbgstr_w(uc.lpszScheme) ); - ok( uc.dwSchemeLength == 4, "unexpected scheme length: %u\n", uc.dwSchemeLength ); + ok( uc.dwSchemeLength == 4, "unexpected scheme length: %lu\n", uc.dwSchemeLength ); ok( !memcmp( uc.lpszUserName, username, sizeof(username) ), "unexpected username: %s\n", wine_dbgstr_w(uc.lpszUserName) ); - ok( uc.dwUserNameLength == 8, "unexpected username length: %u\n", uc.dwUserNameLength ); + ok( uc.dwUserNameLength == 8, "unexpected username length: %lu\n", uc.dwUserNameLength ); ok( !memcmp( uc.lpszPassword, password, sizeof(password) ), "unexpected password: %s\n", wine_dbgstr_w(uc.lpszPassword) ); - ok( uc.dwPasswordLength == 8, "unexpected password length: %u\n", uc.dwPasswordLength ); + ok( uc.dwPasswordLength == 8, "unexpected password length: %lu\n", uc.dwPasswordLength ); ok( !memcmp( uc.lpszHostName, winehq, sizeof(winehq) ), "unexpected hostname: %s\n", wine_dbgstr_w(uc.lpszHostName) ); - ok( uc.dwHostNameLength == 14, "unexpected hostname length: %u\n", uc.dwHostNameLength ); + ok( uc.dwHostNameLength == 14, "unexpected hostname length: %lu\n", uc.dwHostNameLength ); ok( uc.nPort == 80, "unexpected port: %u\n", uc.nPort ); ok( !memcmp( uc.lpszUrlPath, about, sizeof(about) ), "unexpected path: %s\n", wine_dbgstr_w(uc.lpszUrlPath) ); - ok( uc.dwUrlPathLength == 11, "unexpected path length: %u\n", uc.dwUrlPathLength ); + ok( uc.dwUrlPathLength == 11, "unexpected path length: %lu\n", uc.dwUrlPathLength ); ok( !memcmp( uc.lpszExtraInfo, query, sizeof(query) ), "unexpected extra info: %s\n", wine_dbgstr_w(uc.lpszExtraInfo) ); - ok( uc.dwExtraInfoLength == 6, "unexpected extra info length: %u\n", uc.dwExtraInfoLength ); + ok( uc.dwExtraInfoLength == 6, "unexpected extra info length: %lu\n", uc.dwExtraInfoLength ); /* buffers of insufficient length */ uc.dwSchemeLength = 1; @@ -480,19 +442,19 @@ static void WinHttpCrackUrl_test( void ) ret = WinHttpCrackUrl( url1, 0, 0, &uc ); error = GetLastError(); ok( !ret, "WinHttpCrackUrl succeeded\n" ); - ok( error == ERROR_INSUFFICIENT_BUFFER, "got %u, expected ERROR_INSUFFICIENT_BUFFER\n", error ); - ok( uc.dwSchemeLength == 5, "unexpected scheme length: %u\n", uc.dwSchemeLength ); - ok( uc.dwHostNameLength == 15, "unexpected hostname length: %u\n", uc.dwHostNameLength ); - ok( uc.dwUrlPathLength == 11, "unexpected path length: %u\n", uc.dwUrlPathLength ); + ok( error == ERROR_INSUFFICIENT_BUFFER, "got %lu, expected ERROR_INSUFFICIENT_BUFFER\n", error ); + ok( uc.dwSchemeLength == 5, "unexpected scheme length: %lu\n", uc.dwSchemeLength ); + ok( uc.dwHostNameLength == 15, "unexpected hostname length: %lu\n", uc.dwHostNameLength ); + ok( uc.dwUrlPathLength == 11, "unexpected path length: %lu\n", uc.dwUrlPathLength ); /* no buffers */ reset_url_components( &uc ); SetLastError( 0xdeadbeef ); ret = WinHttpCrackUrl( url_k1, 0, 0, &uc); error = GetLastError(); - ok( ret, "WinHttpCrackUrl failed le=%u\n", error ); + ok( ret, "WinHttpCrackUrl failed le = %lu\n", error ); ok( error == ERROR_SUCCESS || broken(error == ERROR_INVALID_PARAMETER) /* < win7 */, - "got %u, expected ERROR_SUCCESS\n", error ); + "got %lu, expected ERROR_SUCCESS\n", error ); ok( uc.nScheme == INTERNET_SCHEME_HTTP, "unexpected scheme\n" ); ok( uc.lpszScheme == url_k1,"unexpected scheme\n" ); ok( uc.dwSchemeLength == 4, "unexpected scheme length\n" ); @@ -512,7 +474,7 @@ static void WinHttpCrackUrl_test( void ) uc.dwSchemeLength = uc.dwHostNameLength = uc.dwUserNameLength = 1; uc.dwPasswordLength = uc.dwUrlPathLength = uc.dwExtraInfoLength = 1; ret = WinHttpCrackUrl( url_k2, 0, 0,&uc); - ok( ret, "WinHttpCrackUrl failed le=%u\n", GetLastError() ); + ok( ret, "WinHttpCrackUrl failed le = %lu\n", GetLastError() ); ok( uc.nScheme == INTERNET_SCHEME_HTTP, "unexpected scheme\n" ); ok( uc.lpszScheme == url_k2, "unexpected scheme\n" ); ok( uc.dwSchemeLength == 4, "unexpected scheme length\n" ); @@ -530,7 +492,7 @@ static void WinHttpCrackUrl_test( void ) reset_url_components( &uc ); ret = WinHttpCrackUrl( url_k3, 0, 0, &uc ); - ok( ret, "WinHttpCrackUrl failed le=%u\n", GetLastError() ); + ok( ret, "WinHttpCrackUrl failed le = %lu\n", GetLastError() ); ok( uc.nScheme == INTERNET_SCHEME_HTTPS, "unexpected scheme\n" ); ok( uc.lpszScheme == url_k3, "unexpected scheme\n" ); ok( uc.dwSchemeLength == 5, "unexpected scheme length\n" ); @@ -552,80 +514,80 @@ static void WinHttpCrackUrl_test( void ) ret = WinHttpCrackUrl( url_k4, 0, 0, &uc ); ok( !ret, "WinHttpCrackUrl succeeded\n" ); error = GetLastError(); - ok( error == ERROR_WINHTTP_INVALID_URL, "got %u\n", error ); + ok( error == ERROR_WINHTTP_INVALID_URL, "got %lu\n", error ); reset_url_components( &uc ); SetLastError( 0xdeadbeef ); ret = WinHttpCrackUrl( url_k5, 0, 0, &uc ); ok( !ret, "WinHttpCrackUrl succeeded\n" ); error = GetLastError(); - ok( error == ERROR_WINHTTP_INVALID_URL, "got %u\n", error ); + ok( error == ERROR_WINHTTP_INVALID_URL, "got %lu\n", error ); reset_url_components( &uc ); SetLastError( 0xdeadbeef ); ret = WinHttpCrackUrl( url_k6, 0, 0, &uc ); ok( !ret, "WinHttpCrackUrl succeeded\n" ); error = GetLastError(); - ok( error == ERROR_WINHTTP_UNRECOGNIZED_SCHEME, "got %u\n", error ); + ok( error == ERROR_WINHTTP_UNRECOGNIZED_SCHEME, "got %lu\n", error ); reset_url_components( &uc ); SetLastError( 0xdeadbeef ); ret = WinHttpCrackUrl( url_k7, 0, 0, &uc ); ok( !ret, "WinHttpCrackUrl succeeded\n" ); error = GetLastError(); - ok( error == ERROR_WINHTTP_UNRECOGNIZED_SCHEME, "got %u\n", error ); + ok( error == ERROR_WINHTTP_UNRECOGNIZED_SCHEME, "got %lu\n", error ); reset_url_components( &uc ); SetLastError( 0xdeadbeef ); ret = WinHttpCrackUrl( url_k8, 0, 0, &uc ); error = GetLastError(); ok( !ret, "WinHttpCrackUrl succeeded\n" ); - ok( error == ERROR_WINHTTP_UNRECOGNIZED_SCHEME, "got %u\n", error ); + ok( error == ERROR_WINHTTP_UNRECOGNIZED_SCHEME, "got %lu\n", error ); reset_url_components( &uc ); ret = WinHttpCrackUrl( url_k9, 0, 0, &uc ); - ok( ret, "WinHttpCrackUrl failed le=%u\n", GetLastError() ); + ok( ret, "WinHttpCrackUrl failed le = %lu\n", GetLastError() ); ok( uc.lpszUrlPath == url_k9 + 14 || broken(uc.lpszUrlPath == url_k9 + 13) /* win8 */, "unexpected path: %s\n", wine_dbgstr_w(uc.lpszUrlPath) ); - ok( uc.dwUrlPathLength == 0, "unexpected path length: %u\n", uc.dwUrlPathLength ); + ok( uc.dwUrlPathLength == 0, "unexpected path length: %lu\n", uc.dwUrlPathLength ); ok( uc.lpszExtraInfo == url_k9 + 14 || broken(uc.lpszExtraInfo == url_k9 + 13) /* win8 */, "unexpected extra info: %s\n", wine_dbgstr_w(uc.lpszExtraInfo) ); ok( uc.dwExtraInfoLength == 0 || broken(uc.dwExtraInfoLength == 1) /* win8 */, - "unexpected extra info length: %u\n", uc.dwExtraInfoLength ); + "unexpected extra info length: %lu\n", uc.dwExtraInfoLength ); reset_url_components( &uc ); ret = WinHttpCrackUrl( url_k10, 0, 0, &uc ); - ok( ret, "WinHttpCrackUrl failed le=%u\n", GetLastError() ); + ok( ret, "WinHttpCrackUrl failed le = %lu\n", GetLastError() ); ok( uc.lpszUrlPath == url_k10 + 13, "unexpected path: %s\n", wine_dbgstr_w(uc.lpszUrlPath) ); - ok( uc.dwUrlPathLength == 7, "unexpected path length: %u\n", uc.dwUrlPathLength ); + ok( uc.dwUrlPathLength == 7, "unexpected path length: %lu\n", uc.dwUrlPathLength ); ok( uc.lpszExtraInfo == url_k10 + 20, "unexpected extra info: %s\n", wine_dbgstr_w(uc.lpszExtraInfo) ); - ok( uc.dwExtraInfoLength == 0, "unexpected extra info length: %u\n", uc.dwExtraInfoLength ); + ok( uc.dwExtraInfoLength == 0, "unexpected extra info length: %lu\n", uc.dwExtraInfoLength ); reset_url_components( &uc ); SetLastError( 0xdeadbeef ); ret = WinHttpCrackUrl( url4, 0, 0, &uc ); error = GetLastError(); ok( !ret, "WinHttpCrackUrl succeeded\n" ); - ok( error == ERROR_WINHTTP_INVALID_URL, "got %u\n", error ); + ok( error == ERROR_WINHTTP_INVALID_URL, "got %lu\n", error ); reset_url_components( &uc ); SetLastError( 0xdeadbeef ); ret = WinHttpCrackUrl( empty, 0, 0, &uc ); error = GetLastError(); ok( !ret, "WinHttpCrackUrl succeeded\n" ); - ok( error == ERROR_WINHTTP_UNRECOGNIZED_SCHEME, "got %u\n", error ); + ok( error == ERROR_WINHTTP_UNRECOGNIZED_SCHEME, "got %lu\n", error ); SetLastError( 0xdeadbeef ); ret = WinHttpCrackUrl( url1, 0, 0, NULL ); error = GetLastError(); ok( !ret, "WinHttpCrackUrl succeeded\n" ); - ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + ok( error == ERROR_INVALID_PARAMETER, "got %lu\n", error ); SetLastError( 0xdeadbeef ); ret = WinHttpCrackUrl( NULL, 0, 0, &uc ); error = GetLastError(); ok( !ret, "WinHttpCrackUrl succeeded\n" ); - ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + ok( error == ERROR_INVALID_PARAMETER, "got %lu\n", error ); /* decoding without buffers */ reset_url_components( &uc ); @@ -633,7 +595,7 @@ static void WinHttpCrackUrl_test( void ) ret = WinHttpCrackUrl( url7, 0, ICU_DECODE, &uc ); error = GetLastError(); ok( !ret, "WinHttpCrackUrl succeeded\n" ); - ok( error == ERROR_INVALID_PARAMETER, "got %u, expected ERROR_INVALID_PARAMETER\n", error ); + ok( error == ERROR_INVALID_PARAMETER, "got %lu, expected ERROR_INVALID_PARAMETER\n", error ); /* decoding with buffers */ uc.lpszScheme = scheme; @@ -652,11 +614,11 @@ static void WinHttpCrackUrl_test( void ) path[0] = 0; ret = WinHttpCrackUrl( url7, 0, ICU_DECODE, &uc ); - ok( ret, "WinHttpCrackUrl failed %u\n", GetLastError() ); + ok( ret, "WinHttpCrackUrl failed %lu\n", GetLastError() ); ok( !memcmp( uc.lpszUrlPath + 11, escape, 21 * sizeof(WCHAR) ), "unexpected path\n" ); - ok( uc.dwUrlPathLength == 32, "unexpected path length %u\n", uc.dwUrlPathLength ); + ok( uc.dwUrlPathLength == 32, "unexpected path length %lu\n", uc.dwUrlPathLength ); ok( !memcmp( uc.lpszExtraInfo, escape + 21, 12 * sizeof(WCHAR) ), "unexpected extra info\n" ); - ok( uc.dwExtraInfoLength == 12, "unexpected extra info length %u\n", uc.dwExtraInfoLength ); + ok( uc.dwExtraInfoLength == 12, "unexpected extra info length %lu\n", uc.dwExtraInfoLength ); /* Urls with specified port numbers */ /* decoding with buffers */ @@ -676,25 +638,25 @@ static void WinHttpCrackUrl_test( void ) path[0] = 0; ret = WinHttpCrackUrl( url6, 0, 0, &uc ); - ok( ret, "WinHttpCrackUrl failed le=%u\n", GetLastError() ); + ok( ret, "WinHttpCrackUrl failed le = %lu\n", GetLastError() ); ok( !memcmp( uc.lpszHostName, winehq, sizeof(winehq) ), "unexpected host name: %s\n", wine_dbgstr_w(uc.lpszHostName) ); - ok( uc.dwHostNameLength == 14, "unexpected host name length: %d\n", uc.dwHostNameLength ); + ok( uc.dwHostNameLength == 14, "unexpected host name length: %lu\n", uc.dwHostNameLength ); ok( uc.nPort == 42, "unexpected port: %u\n", uc.nPort ); /* decoding without buffers */ reset_url_components( &uc ); ret = WinHttpCrackUrl( url8, 0, 0, &uc ); - ok( ret, "WinHttpCrackUrl failed le=%u\n", GetLastError() ); + ok( ret, "WinHttpCrackUrl failed le = %lu\n", GetLastError() ); ok( uc.nPort == 0, "unexpected port: %u\n", uc.nPort ); reset_url_components( &uc ); ret = WinHttpCrackUrl( url9, 0, 0, &uc ); - ok( ret, "WinHttpCrackUrl failed le=%u\n", GetLastError() ); + ok( ret, "WinHttpCrackUrl failed le = %lu\n", GetLastError() ); ok( uc.nPort == 80, "unexpected port: %u\n", uc.nPort ); reset_url_components( &uc ); ret = WinHttpCrackUrl( url10, 0, 0, &uc ); - ok( ret, "WinHttpCrackUrl failed le=%u\n", GetLastError() ); + ok( ret, "WinHttpCrackUrl failed le = %lu\n", GetLastError() ); ok( uc.nPort == 443, "unexpected port: %u\n", uc.nPort ); reset_url_components( &uc ); @@ -702,18 +664,18 @@ static void WinHttpCrackUrl_test( void ) ret = WinHttpCrackUrl( empty, 0, 0, &uc ); error = GetLastError(); ok( !ret, "WinHttpCrackUrl succeeded\n" ); - ok( error == ERROR_WINHTTP_UNRECOGNIZED_SCHEME, "got %u, expected ERROR_WINHTTP_UNRECOGNIZED_SCHEME\n", error ); + ok( error == ERROR_WINHTTP_UNRECOGNIZED_SCHEME, "got %lu, expected ERROR_WINHTTP_UNRECOGNIZED_SCHEME\n", error ); reset_url_components( &uc ); SetLastError( 0xdeadbeef ); ret = WinHttpCrackUrl( http, 0, 0, &uc ); error = GetLastError(); ok( !ret, "WinHttpCrackUrl succeeded\n" ); - ok( error == ERROR_WINHTTP_UNRECOGNIZED_SCHEME, "got %u, expected ERROR_WINHTTP_UNRECOGNIZED_SCHEME\n", error ); + ok( error == ERROR_WINHTTP_UNRECOGNIZED_SCHEME, "got %lu, expected ERROR_WINHTTP_UNRECOGNIZED_SCHEME\n", error ); reset_url_components( &uc ); ret = WinHttpCrackUrl( url11, 0, 0, &uc); - ok( ret, "WinHttpCrackUrl failed le=%u\n", GetLastError() ); + ok( ret, "WinHttpCrackUrl failed le = %lu\n", GetLastError() ); ok( uc.nScheme == INTERNET_SCHEME_HTTP, "unexpected scheme\n" ); ok( uc.lpszScheme == url11,"unexpected scheme\n" ); ok( uc.dwSchemeLength == 4, "unexpected scheme length\n" ); @@ -741,7 +703,7 @@ static void WinHttpCrackUrl_test( void ) uc.dwExtraInfoLength = 0; uc.nPort = 0; ret = WinHttpCrackUrl( url12, 0, ICU_DECODE, &uc ); - ok( ret, "WinHttpCrackUrl failed le=%u\n", GetLastError() ); + ok( ret, "WinHttpCrackUrl failed le = %lu\n", GetLastError() ); uc.lpszScheme = scheme; uc.dwSchemeLength = 20; @@ -757,10 +719,10 @@ static void WinHttpCrackUrl_test( void ) uc.dwExtraInfoLength = 0; uc.nPort = 0; ret = WinHttpCrackUrl( url13, 0, ICU_ESCAPE|ICU_DECODE, &uc ); - ok( ret, "WinHttpCrackUrl failed le=%u\n", GetLastError() ); - ok( !lstrcmpW( uc.lpszHostName, hostnameW ), "unexpected host name\n" ); - ok( !lstrcmpW( uc.lpszUrlPath, pathW ), "unexpected path\n" ); - ok( uc.dwUrlPathLength == lstrlenW(pathW), "got %u\n", uc.dwUrlPathLength ); + ok( ret, "WinHttpCrackUrl failed le = %lu\n", GetLastError() ); + ok( !lstrcmpW( uc.lpszHostName, L"winehq.o g" ), "unexpected host name\n" ); + ok( !lstrcmpW( uc.lpszUrlPath, L"/path%20with%20spaces" ), "unexpected path\n" ); + ok( uc.dwUrlPathLength == lstrlenW(L"/path%20with%20spaces"), "got %lu\n", uc.dwUrlPathLength ); uc.dwStructSize = sizeof(uc); uc.lpszScheme = NULL; @@ -778,21 +740,21 @@ static void WinHttpCrackUrl_test( void ) uc.lpszExtraInfo = NULL; uc.dwExtraInfoLength = ~0u; ret = WinHttpCrackUrl( url14, 0, 0, &uc ); - ok( ret, "WinHttpCrackUrl failed le=%u\n", GetLastError() ); + ok( ret, "WinHttpCrackUrl failed le = %lu\n", GetLastError() ); ok( !uc.lpszScheme, "unexpected scheme %s\n", wine_dbgstr_w(uc.lpszScheme) ); - ok( !uc.dwSchemeLength, "unexpected length %u\n", uc.dwSchemeLength ); + ok( !uc.dwSchemeLength, "unexpected length %lu\n", uc.dwSchemeLength ); ok( uc.nScheme == INTERNET_SCHEME_HTTP, "unexpected scheme %u\n", uc.nScheme ); ok( !lstrcmpW( uc.lpszHostName, url14 + 7 ), "unexpected hostname %s\n", wine_dbgstr_w(uc.lpszHostName) ); - ok( uc.dwHostNameLength == 14, "unexpected length %u\n", uc.dwHostNameLength ); + ok( uc.dwHostNameLength == 14, "unexpected length %lu\n", uc.dwHostNameLength ); ok( uc.nPort == 80, "unexpected port %u\n", uc.nPort ); ok( !uc.lpszUserName, "unexpected username\n" ); - ok( !uc.dwUserNameLength, "unexpected length %u\n", uc.dwUserNameLength ); + ok( !uc.dwUserNameLength, "unexpected length %lu\n", uc.dwUserNameLength ); ok( !uc.lpszPassword, "unexpected password\n" ); - ok( !uc.dwPasswordLength, "unexpected length %u\n", uc.dwPasswordLength ); + ok( !uc.dwPasswordLength, "unexpected length %lu\n", uc.dwPasswordLength ); ok( !lstrcmpW( uc.lpszUrlPath, url14 + 21 ), "unexpected path %s\n", wine_dbgstr_w(uc.lpszUrlPath) ); - ok( uc.dwUrlPathLength == 5, "unexpected length %u\n", uc.dwUrlPathLength ); + ok( uc.dwUrlPathLength == 5, "unexpected length %lu\n", uc.dwUrlPathLength ); ok( !uc.lpszExtraInfo[0], "unexpected extra info %s\n", wine_dbgstr_w(uc.lpszExtraInfo) ); - ok( uc.dwExtraInfoLength == 0, "unexpected length %u\n", uc.dwExtraInfoLength ); + ok( uc.dwExtraInfoLength == 0, "unexpected length %lu\n", uc.dwExtraInfoLength ); uc.dwStructSize = sizeof(uc); uc.lpszScheme = scheme; @@ -813,40 +775,46 @@ static void WinHttpCrackUrl_test( void ) ret = WinHttpCrackUrl( url14, 0, 0, &uc ); error = GetLastError(); ok( !ret, "WinHttpCrackUrl succeeded\n" ); - ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + ok( error == ERROR_INVALID_PARAMETER, "got %lu\n", error ); ok( !lstrcmpW( uc.lpszScheme, http ), "unexpected scheme %s\n", wine_dbgstr_w(uc.lpszScheme) ); - ok( !uc.dwSchemeLength, "unexpected length %u\n", uc.dwSchemeLength ); + ok( !uc.dwSchemeLength, "unexpected length %lu\n", uc.dwSchemeLength ); ok( uc.nScheme == 0, "unexpected scheme %u\n", uc.nScheme ); ok( !uc.lpszHostName, "unexpected hostname %s\n", wine_dbgstr_w(uc.lpszHostName) ); - ok( uc.dwHostNameLength == 0, "unexpected length %u\n", uc.dwHostNameLength ); + ok( uc.dwHostNameLength == 0, "unexpected length %lu\n", uc.dwHostNameLength ); ok( uc.nPort == 0, "unexpected port %u\n", uc.nPort ); ok( !uc.lpszUserName, "unexpected username\n" ); - ok( uc.dwUserNameLength == ~0u, "unexpected length %u\n", uc.dwUserNameLength ); + ok( uc.dwUserNameLength == ~0u, "unexpected length %lu\n", uc.dwUserNameLength ); ok( !uc.lpszPassword, "unexpected password\n" ); - ok( uc.dwPasswordLength == ~0u, "unexpected length %u\n", uc.dwPasswordLength ); + ok( uc.dwPasswordLength == ~0u, "unexpected length %lu\n", uc.dwPasswordLength ); ok( !uc.lpszUrlPath, "unexpected path %s\n", wine_dbgstr_w(uc.lpszUrlPath) ); - ok( uc.dwUrlPathLength == 0, "unexpected length %u\n", uc.dwUrlPathLength ); + ok( uc.dwUrlPathLength == 0, "unexpected length %lu\n", uc.dwUrlPathLength ); ok( !uc.lpszExtraInfo, "unexpected extra info %s\n", wine_dbgstr_w(uc.lpszExtraInfo) ); - ok( uc.dwExtraInfoLength == 0, "unexpected length %u\n", uc.dwExtraInfoLength ); + ok( uc.dwExtraInfoLength == 0, "unexpected length %lu\n", uc.dwExtraInfoLength ); reset_url_components( &uc ); SetLastError( 0xdeadbeef ); ret = WinHttpCrackUrl( url15, 0, 0, &uc ); error = GetLastError(); ok( !ret, "WinHttpCrackUrl succeeded\n" ); - ok( error == ERROR_WINHTTP_INVALID_URL, "got %u\n", error ); + ok( error == ERROR_WINHTTP_INVALID_URL, "got %lu\n", error ); reset_url_components( &uc ); uc.nPort = 1; ret = WinHttpCrackUrl( url16, 0, 0, &uc ); - ok( ret, "got %u\n", GetLastError() ); + ok( ret, "got %lu\n", GetLastError() ); ok( !uc.nPort, "got %u\n", uc.nPort ); reset_url_components( &uc ); uc.nPort = 1; ret = WinHttpCrackUrl( url17, 0, 0, &uc ); - ok( ret, "got %u\n", GetLastError() ); - todo_wine ok( uc.nPort == 80, "got %u\n", uc.nPort ); + ok( ret, "got %lu\n", GetLastError() ); + ok( uc.nPort == 80, "got %u\n", uc.nPort ); + + reset_url_components( &uc ); + uc.nPort = 1; + ret = WinHttpCrackUrl( url22, 0, 0, &uc ); + ok( ret, "got %lu\n", GetLastError() ); + ok( uc.nPort == 80, "got %u\n", uc.nPort ); memset( &uc, 0, sizeof(uc) ); uc.dwStructSize = sizeof(uc); @@ -857,9 +825,9 @@ static void WinHttpCrackUrl_test( void ) uc.lpszUrlPath = path; uc.dwUrlPathLength = ARRAY_SIZE(path); ret = WinHttpCrackUrl( url21, 0, 0, &uc ); - ok( ret, "got %u\n", GetLastError() ); + ok( ret, "got %lu\n", GetLastError() ); ok( !lstrcmpW( uc.lpszUrlPath, url21 + 37 ), "unexpected path %s\n", wine_dbgstr_w(uc.lpszUrlPath) ); - ok( uc.dwUrlPathLength == 50, "unexpected length %u\n", uc.dwUrlPathLength ); + ok( uc.dwUrlPathLength == 50, "unexpected length %lu\n", uc.dwUrlPathLength ); } START_TEST(url) diff --git a/modules/rostests/winetests/winhttp/winhttp.c b/modules/rostests/winetests/winhttp/winhttp.c index 5655432f73b..93322b7a236 100644 --- a/modules/rostests/winetests/winhttp/winhttp.c +++ b/modules/rostests/winetests/winhttp/winhttp.c @@ -27,37 +27,20 @@ #include #include #include -#include #include #include #include #include "wine/test.h" -#include "wine/heap.h" DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); -static const WCHAR test_useragent[] = - {'W','i','n','e',' ','R','e','g','r','e','s','s','i','o','n',' ','T','e','s','t',0}; -static const WCHAR test_winehq[] = {'t','e','s','t','.','w','i','n','e','h','q','.','o','r','g',0}; -static const WCHAR test_winehq_https[] = {'h','t','t','p','s',':','/','/','t','e','s','t','.','w','i','n','e','h','q','.','o','r','g',':','4','4','3',0}; -static const WCHAR localhostW[] = {'l','o','c','a','l','h','o','s','t',0}; - -static WCHAR *a2w(const char *str) -{ - int len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); - WCHAR *ret = heap_alloc(len * sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len); - return ret; -} - -static int strcmp_wa(const WCHAR *str1, const char *stra) -{ - WCHAR *str2 = a2w(stra); - int r = lstrcmpW(str1, str2); - heap_free(str2); - return r; -} +static DWORD (WINAPI *pWinHttpWebSocketClose)(HINTERNET,USHORT,void*,DWORD); +static HINTERNET (WINAPI *pWinHttpWebSocketCompleteUpgrade)(HINTERNET,DWORD_PTR); +static DWORD (WINAPI *pWinHttpWebSocketQueryCloseStatus)(HINTERNET,USHORT*,void*,DWORD,DWORD*); +static DWORD (WINAPI *pWinHttpWebSocketReceive)(HINTERNET,void*,DWORD,DWORD*,WINHTTP_WEB_SOCKET_BUFFER_TYPE*); +static DWORD (WINAPI *pWinHttpWebSocketSend)(HINTERNET,WINHTTP_WEB_SOCKET_BUFFER_TYPE,void*,DWORD); +static DWORD (WINAPI *pWinHttpWebSocketShutdown)(HINTERNET,USHORT,void*,DWORD); static BOOL proxy_active(void) { @@ -67,8 +50,8 @@ static BOOL proxy_active(void) SetLastError(0xdeadbeef); if (WinHttpGetDefaultProxyConfiguration(&proxy_info)) { - ok(GetLastError() == ERROR_SUCCESS || broken(GetLastError() == 0xdeadbeef) /* < win7 */, - "got %u\n", GetLastError()); + ok( GetLastError() == ERROR_SUCCESS || broken(GetLastError() == 0xdeadbeef) /* < win7 */, + "got %lu\n", GetLastError() ); active = (proxy_info.lpszProxy != NULL); if (active) GlobalFree(proxy_info.lpszProxy); @@ -88,93 +71,99 @@ static void test_WinHttpQueryOption(void) DWORD feature, size; SetLastError(0xdeadbeef); - session = WinHttpOpen(test_useragent, 0, 0, 0, 0); - ok(session != NULL, "WinHttpOpen failed to open session, error %u\n", GetLastError()); + session = WinHttpOpen(L"winetest", 0, 0, 0, 0); + ok( session != NULL, "WinHttpOpen failed to open session, error %lu\n", GetLastError() ); SetLastError(0xdeadbeef); ret = WinHttpQueryOption(session, WINHTTP_OPTION_REDIRECT_POLICY, NULL, NULL); - ok(!ret, "should fail to set redirect policy %u\n", GetLastError()); - ok(GetLastError() == ERROR_INVALID_PARAMETER, - "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); + ok( !ret, "should fail to set redirect policy %lu\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %lu\n", GetLastError() ); size = 0xdeadbeef; SetLastError(0xdeadbeef); ret = WinHttpQueryOption(session, WINHTTP_OPTION_REDIRECT_POLICY, NULL, &size); ok(!ret, "should fail to query option\n"); - ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, - "expected ERROR_INSUFFICIENT_BUFFER, got %u\n", GetLastError()); - ok(size == 4, "expected 4, got %u\n", size); + ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "expected ERROR_INSUFFICIENT_BUFFER, got %lu\n", GetLastError() ); + ok( size == 4, "expected 4, got %lu\n", size ); feature = 0xdeadbeef; size = sizeof(feature) - 1; SetLastError(0xdeadbeef); ret = WinHttpQueryOption(session, WINHTTP_OPTION_REDIRECT_POLICY, &feature, &size); ok(!ret, "should fail to query option\n"); - ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, - "expected ERROR_INSUFFICIENT_BUFFER, got %u\n", GetLastError()); - ok(size == 4, "expected 4, got %u\n", size); + ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "expected ERROR_INSUFFICIENT_BUFFER, got %lu\n", GetLastError() ); + ok( size == 4, "expected 4, got %lu\n", size ); + + feature = 0xdeadbeef; + size = sizeof(feature) + 1; + SetLastError(0xdeadbeef); + ret = WinHttpQueryOption(session, WINHTTP_OPTION_WORKER_THREAD_COUNT, &feature, &size); + ok(ret, "failed to query option %lu\n", GetLastError()); + ok(GetLastError() == ERROR_SUCCESS, "got %lu\n", GetLastError()); + ok(size == sizeof(feature), "WinHttpQueryOption should set the size: %lu\n", size); + ok(feature == 0, "got unexpected WINHTTP_OPTION_WORKER_THREAD_COUNT %#lx\n", feature); feature = 0xdeadbeef; size = sizeof(feature) + 1; SetLastError(0xdeadbeef); ret = WinHttpQueryOption(session, WINHTTP_OPTION_REDIRECT_POLICY, &feature, &size); - ok(ret, "failed to query option %u\n", GetLastError()); + ok(ret, "failed to query option %lu\n", GetLastError()); ok(GetLastError() == ERROR_SUCCESS || broken(GetLastError() == 0xdeadbeef) /* < win7 */, - "got %u\n", GetLastError()); - ok(size == sizeof(feature), "WinHttpQueryOption should set the size: %u\n", size); + "got %lu\n", GetLastError()); + ok(size == sizeof(feature), "WinHttpQueryOption should set the size: %lu\n", size); ok(feature == WINHTTP_OPTION_REDIRECT_POLICY_DISALLOW_HTTPS_TO_HTTP, - "expected WINHTTP_OPTION_REDIRECT_POLICY_DISALLOW_HTTPS_TO_HTTP, got %#x\n", feature); + "expected WINHTTP_OPTION_REDIRECT_POLICY_DISALLOW_HTTPS_TO_HTTP, got %#lx\n", feature); SetLastError(0xdeadbeef); ret = WinHttpSetOption(session, WINHTTP_OPTION_REDIRECT_POLICY, NULL, sizeof(feature)); - ok(!ret, "should fail to set redirect policy %u\n", GetLastError()); + ok(!ret, "should fail to set redirect policy %lu\n", GetLastError()); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); + "expected ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); feature = WINHTTP_OPTION_REDIRECT_POLICY_ALWAYS; SetLastError(0xdeadbeef); ret = WinHttpSetOption(session, WINHTTP_OPTION_REDIRECT_POLICY, &feature, sizeof(feature) - 1); - ok(!ret, "should fail to set redirect policy %u\n", GetLastError()); + ok(!ret, "should fail to set redirect policy %lu\n", GetLastError()); ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, - "expected ERROR_INSUFFICIENT_BUFFER, got %u\n", GetLastError()); + "expected ERROR_INSUFFICIENT_BUFFER, got %lu\n", GetLastError()); feature = WINHTTP_OPTION_REDIRECT_POLICY_ALWAYS; SetLastError(0xdeadbeef); ret = WinHttpSetOption(session, WINHTTP_OPTION_REDIRECT_POLICY, &feature, sizeof(feature) + 1); - ok(!ret, "should fail to set redirect policy %u\n", GetLastError()); + ok(!ret, "should fail to set redirect policy %lu\n", GetLastError()); ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, - "expected ERROR_INSUFFICIENT_BUFFER, got %u\n", GetLastError()); + "expected ERROR_INSUFFICIENT_BUFFER, got %lu\n", GetLastError()); feature = WINHTTP_OPTION_REDIRECT_POLICY_ALWAYS; SetLastError(0xdeadbeef); ret = WinHttpSetOption(session, WINHTTP_OPTION_REDIRECT_POLICY, &feature, sizeof(feature)); - ok(ret, "failed to set redirect policy %u\n", GetLastError()); + ok(ret, "failed to set redirect policy %lu\n", GetLastError()); feature = 0xdeadbeef; size = sizeof(feature); SetLastError(0xdeadbeef); ret = WinHttpQueryOption(session, WINHTTP_OPTION_REDIRECT_POLICY, &feature, &size); - ok(ret, "failed to query option %u\n", GetLastError()); + ok(ret, "failed to query option %lu\n", GetLastError()); ok(feature == WINHTTP_OPTION_REDIRECT_POLICY_ALWAYS, - "expected WINHTTP_OPTION_REDIRECT_POLICY_ALWAYS, got %#x\n", feature); + "expected WINHTTP_OPTION_REDIRECT_POLICY_ALWAYS, got %#lx\n", feature); feature = WINHTTP_DISABLE_COOKIES; SetLastError(0xdeadbeef); ret = WinHttpSetOption(session, WINHTTP_OPTION_DISABLE_FEATURE, &feature, sizeof(feature)); ok(!ret, "should fail to set disable feature for a session\n"); ok(GetLastError() == ERROR_WINHTTP_INCORRECT_HANDLE_TYPE, - "expected ERROR_WINHTTP_INCORRECT_HANDLE_TYPE, got %u\n", GetLastError()); + "expected ERROR_WINHTTP_INCORRECT_HANDLE_TYPE, got %lu\n", GetLastError()); SetLastError(0xdeadbeef); - connection = WinHttpConnect(session, test_winehq, INTERNET_DEFAULT_HTTP_PORT, 0); - ok(connection != NULL, "WinHttpConnect failed to open a connection, error: %u\n", GetLastError()); + connection = WinHttpConnect(session, L"test.winehq.org", INTERNET_DEFAULT_HTTP_PORT, 0); + ok(connection != NULL, "WinHttpConnect failed to open a connection, error: %lu\n", GetLastError()); feature = WINHTTP_DISABLE_COOKIES; SetLastError(0xdeadbeef); ret = WinHttpSetOption(connection, WINHTTP_OPTION_DISABLE_FEATURE, &feature, sizeof(feature)); ok(!ret, "should fail to set disable feature for a connection\n"); ok(GetLastError() == ERROR_WINHTTP_INCORRECT_HANDLE_TYPE, - "expected ERROR_WINHTTP_INCORRECT_HANDLE_TYPE, got %u\n", GetLastError()); + "expected ERROR_WINHTTP_INCORRECT_HANDLE_TYPE, got %lu\n", GetLastError()); SetLastError(0xdeadbeef); request = WinHttpOpenRequest(connection, NULL, NULL, NULL, WINHTTP_NO_REFERER, @@ -185,86 +174,104 @@ static void test_WinHttpQueryOption(void) goto done; } + feature = 0xdeadbeef; + size = sizeof(feature); + SetLastError(0xdeadbeef); + ret = WinHttpQueryOption(connection, WINHTTP_OPTION_WORKER_THREAD_COUNT, &feature, &size); + ok(ret, "query WINHTTP_OPTION_WORKER_THREAD_COUNT failed for a request\n"); + ok(GetLastError() == ERROR_SUCCESS, "got unexpected error %lu\n", GetLastError()); + ok(size == sizeof(feature), "WinHttpQueryOption should set the size: %lu\n", size); + ok(feature == 0, "got unexpected WINHTTP_OPTION_WORKER_THREAD_COUNT %#lx\n", feature); + + feature = 0xdeadbeef; + size = sizeof(feature); + SetLastError(0xdeadbeef); + ret = WinHttpQueryOption(request, WINHTTP_OPTION_WORKER_THREAD_COUNT, &feature, &size); + ok(ret, "query WINHTTP_OPTION_WORKER_THREAD_COUNT failed for a request\n"); + ok(GetLastError() == ERROR_SUCCESS, "got unexpected error %lu\n", GetLastError()); + ok(size == sizeof(feature), "WinHttpQueryOption should set the size: %lu\n", size); + ok(feature == 0, "got unexpected WINHTTP_OPTION_WORKER_THREAD_COUNT %#lx\n", feature); + feature = 0xdeadbeef; size = sizeof(feature); SetLastError(0xdeadbeef); ret = WinHttpQueryOption(request, WINHTTP_OPTION_DISABLE_FEATURE, &feature, &size); ok(!ret, "should fail to query disable feature for a request\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); + "expected ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); feature = 0; size = sizeof(feature); SetLastError(0xdeadbeef); ret = WinHttpSetOption(request, WINHTTP_OPTION_DISABLE_FEATURE, &feature, sizeof(feature)); - ok(ret, "failed to set feature %u\n", GetLastError()); + ok(ret, "failed to set feature %lu\n", GetLastError()); feature = 0xffffffff; size = sizeof(feature); SetLastError(0xdeadbeef); ret = WinHttpSetOption(request, WINHTTP_OPTION_DISABLE_FEATURE, &feature, sizeof(feature)); - ok(ret, "failed to set feature %u\n", GetLastError()); + ok(ret, "failed to set feature %lu\n", GetLastError()); feature = WINHTTP_DISABLE_COOKIES; size = sizeof(feature); SetLastError(0xdeadbeef); ret = WinHttpSetOption(request, WINHTTP_OPTION_DISABLE_FEATURE, &feature, sizeof(feature)); - ok(ret, "failed to set feature %u\n", GetLastError()); + ok(ret, "failed to set feature %lu\n", GetLastError()); size = 0; SetLastError(0xdeadbeef); ret = WinHttpQueryOption(request, WINHTTP_OPTION_DISABLE_FEATURE, NULL, &size); ok(!ret, "should fail to query disable feature for a request\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); + "expected ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); feature = 0xdeadbeef; size = sizeof(feature); SetLastError(0xdeadbeef); ret = WinHttpQueryOption(request, WINHTTP_OPTION_ENABLE_FEATURE, &feature, &size); ok(!ret, "should fail to query enabled features for a request\n"); - ok(feature == 0xdeadbeef, "expect feature 0xdeadbeef, got %u\n", feature); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); + ok(feature == 0xdeadbeef, "expect feature 0xdeadbeef, got %#lx\n", feature); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); feature = WINHTTP_ENABLE_SSL_REVOCATION; SetLastError(0xdeadbeef); ret = WinHttpSetOption(request, WINHTTP_OPTION_ENABLE_FEATURE, 0, sizeof(feature)); ok(!ret, "should fail to enable WINHTTP_ENABLE_SSL_REVOCATION with invalid parameters\n"); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = WinHttpSetOption(request, WINHTTP_OPTION_ENABLE_FEATURE, &feature, 0); ok(!ret, "should fail to enable WINHTTP_ENABLE_SSL_REVOCATION with invalid parameters\n"); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = WinHttpSetOption(request, WINHTTP_OPTION_ENABLE_FEATURE, &feature, sizeof(feature)); ok(ret, "failed to set feature\n"); ok(GetLastError() == NO_ERROR || broken(GetLastError() == 0xdeadbeef), /* Doesn't set error code on Vista or older */ - "expected NO_ERROR, got %u\n", GetLastError()); + "expected NO_ERROR, got %lu\n", GetLastError()); feature = 0xdeadbeef; SetLastError(0xdeadbeef); ret = WinHttpSetOption(request, WINHTTP_OPTION_ENABLE_FEATURE, &feature, sizeof(feature)); ok(!ret, "should fail to enable WINHTTP_ENABLE_SSL_REVOCATION with invalid parameters\n"); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); feature = 6; size = sizeof(feature); ret = WinHttpSetOption(request, WINHTTP_OPTION_CONNECT_RETRIES, &feature, sizeof(feature)); - ok(ret, "failed to set WINHTTP_OPTION_CONNECT_RETRIES %u\n", GetLastError()); + ok(ret, "failed to set WINHTTP_OPTION_CONNECT_RETRIES %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = WinHttpCloseHandle(request); - ok(ret, "WinHttpCloseHandle failed on closing request: %u\n", GetLastError()); + ok(ret, "WinHttpCloseHandle failed on closing request: %lu\n", GetLastError()); done: SetLastError(0xdeadbeef); ret = WinHttpCloseHandle(connection); - ok(ret, "WinHttpCloseHandle failed on closing connection: %u\n", GetLastError()); + ok(ret, "WinHttpCloseHandle failed on closing connection: %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = WinHttpCloseHandle(session); - ok(ret, "WinHttpCloseHandle failed on closing session: %u\n", GetLastError()); + ok(ret, "WinHttpCloseHandle failed on closing session: %lu\n", GetLastError()); } static void test_WinHttpOpenRequest (void) @@ -274,25 +281,25 @@ static void test_WinHttpOpenRequest (void) DWORD err; SetLastError(0xdeadbeef); - session = WinHttpOpen(test_useragent, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + session = WinHttpOpen(L"winetest", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); err = GetLastError(); ok(session != NULL, "WinHttpOpen failed to open session.\n"); - ok(err == ERROR_SUCCESS, "got %u\n", err); + ok(err == ERROR_SUCCESS, "got %lu\n", err); /* Test with a bad server name */ SetLastError(0xdeadbeef); connection = WinHttpConnect(session, NULL, INTERNET_DEFAULT_HTTP_PORT, 0); err = GetLastError(); ok (connection == NULL, "WinHttpConnect succeeded in opening connection to NULL server argument.\n"); - ok(err == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %u.\n", err); + ok(err == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %lu.\n", err); /* Test with a valid server name */ SetLastError(0xdeadbeef); - connection = WinHttpConnect (session, test_winehq, INTERNET_DEFAULT_HTTP_PORT, 0); + connection = WinHttpConnect (session, L"test.winehq.org", INTERNET_DEFAULT_HTTP_PORT, 0); err = GetLastError(); - ok(connection != NULL, "WinHttpConnect failed to open a connection, error: %u.\n", err); - ok(err == ERROR_SUCCESS || broken(err == WSAEINVAL) /* < win7 */, "got %u\n", err); + ok(connection != NULL, "WinHttpConnect failed to open a connection, error: %lu.\n", err); + ok(err == ERROR_SUCCESS || broken(err == WSAEINVAL) /* < win7 */, "got %lu\n", err); SetLastError(0xdeadbeef); request = WinHttpOpenRequest(connection, NULL, NULL, NULL, WINHTTP_NO_REFERER, @@ -303,8 +310,8 @@ static void test_WinHttpOpenRequest (void) skip("Network unreachable, skipping.\n"); goto done; } - ok(request != NULL, "WinHttpOpenrequest failed to open a request, error: %u.\n", err); - ok(err == ERROR_SUCCESS, "got %u\n", err); + ok(request != NULL, "WinHttpOpenrequest failed to open a request, error: %lu.\n", err); + ok(err == ERROR_SUCCESS, "got %lu\n", err); SetLastError(0xdeadbeef); ret = WinHttpSendRequest(request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, NULL, 0, 0, 0); @@ -314,14 +321,14 @@ static void test_WinHttpOpenRequest (void) skip("Connection failed, skipping.\n"); goto done; } - ok(ret, "WinHttpSendRequest failed: %u\n", err); - ok(err == ERROR_SUCCESS, "got %u\n", err); + ok(ret, "WinHttpSendRequest failed: %lu\n", err); + ok(err == ERROR_SUCCESS, "got %lu\n", err); SetLastError(0xdeadbeef); ret = WinHttpCloseHandle(request); err = GetLastError(); - ok(ret, "WinHttpCloseHandle failed on closing request, got %u.\n", err); - ok(err == ERROR_SUCCESS, "got %u\n", err); + ok(ret, "WinHttpCloseHandle failed on closing request, got %lu.\n", err); + ok(err == ERROR_SUCCESS, "got %lu\n", err); done: ret = WinHttpCloseHandle(connection); @@ -333,28 +340,27 @@ static void test_WinHttpOpenRequest (void) static void test_empty_headers_param(void) { - static const WCHAR empty[] = {0}; HINTERNET ses, con, req; DWORD err; BOOL ret; - ses = WinHttpOpen(test_useragent, 0, NULL, NULL, 0); - ok(ses != NULL, "failed to open session %u\n", GetLastError()); + ses = WinHttpOpen(L"winetest", 0, NULL, NULL, 0); + ok(ses != NULL, "failed to open session %lu\n", GetLastError()); - con = WinHttpConnect(ses, test_winehq, 80, 0); - ok(con != NULL, "failed to open a connection %u\n", GetLastError()); + con = WinHttpConnect(ses, L"test.winehq.org", 80, 0); + ok(con != NULL, "failed to open a connection %lu\n", GetLastError()); req = WinHttpOpenRequest(con, NULL, NULL, NULL, NULL, NULL, 0); - ok(req != NULL, "failed to open a request %u\n", GetLastError()); + ok(req != NULL, "failed to open a request %lu\n", GetLastError()); - ret = WinHttpSendRequest(req, empty, 0, NULL, 0, 0, 0); + ret = WinHttpSendRequest(req, L"", 0, NULL, 0, 0, 0); err = GetLastError(); if (!ret && (err == ERROR_WINHTTP_CANNOT_CONNECT || err == ERROR_WINHTTP_TIMEOUT)) { skip("connection failed, skipping\n"); goto done; } - ok(ret, "failed to send request %u\n", GetLastError()); + ok(ret, "failed to send request %lu\n", GetLastError()); done: WinHttpCloseHandle(req); @@ -364,12 +370,8 @@ static void test_empty_headers_param(void) static void test_WinHttpSendRequest (void) { - static const WCHAR content_type[] = - {'C','o','n','t','e','n','t','-','T','y','p','e',':',' ','a','p','p','l','i','c','a','t','i','o','n', - '/','x','-','w','w','w','-','f','o','r','m','-','u','r','l','e','n','c','o','d','e','d',0}; - static const WCHAR test_file[] = {'t','e','s','t','s','/','p','o','s','t','.','p','h','p',0}; - static const WCHAR postW[] = {'P','O','S','T',0}; - static CHAR post_data[] = "mode=Test"; + static const WCHAR content_type[] = L"Content-Type: application/x-www-form-urlencoded"; + static char post_data[] = "mode=Test"; static const char test_post[] = "mode => Test\0\n"; HINTERNET session, request, connection; DWORD header_len, optional_len, total_len, bytes_rw, size, err, disable, len; @@ -383,39 +385,39 @@ static void test_WinHttpSendRequest (void) total_len = optional_len = sizeof(post_data); memset(buffer, 0xff, sizeof(buffer)); - session = WinHttpOpen(test_useragent, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + session = WinHttpOpen(L"winetest", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); ok(session != NULL, "WinHttpOpen failed to open session.\n"); - connection = WinHttpConnect (session, test_winehq, INTERNET_DEFAULT_HTTP_PORT, 0); - ok(connection != NULL, "WinHttpConnect failed to open a connection, error: %u.\n", GetLastError()); + connection = WinHttpConnect (session, L"test.winehq.org", INTERNET_DEFAULT_HTTP_PORT, 0); + ok(connection != NULL, "WinHttpConnect failed to open a connection, error: %lu\n", GetLastError()); - request = WinHttpOpenRequest(connection, postW, test_file, NULL, WINHTTP_NO_REFERER, + request = WinHttpOpenRequest(connection, L"POST", L"tests/post.php", NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_BYPASS_PROXY_CACHE); if (request == NULL && GetLastError() == ERROR_WINHTTP_NAME_NOT_RESOLVED) { skip("Network unreachable, skipping.\n"); goto done; } - ok(request != NULL, "WinHttpOpenrequest failed to open a request, error: %u.\n", GetLastError()); + ok(request != NULL, "WinHttpOpenrequest failed to open a request, error: %lu\n", GetLastError()); if (!request) goto done; method[0] = 0; len = sizeof(method); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_REQUEST_METHOD, NULL, method, &len, NULL); - ok(ret, "got %u\n", GetLastError()); - ok(len == lstrlenW(postW) * sizeof(WCHAR), "got %u\n", len); - ok(!lstrcmpW(method, postW), "got %s\n", wine_dbgstr_w(method)); + ok(ret, "got %lu\n", GetLastError()); + ok(len == lstrlenW(L"POST") * sizeof(WCHAR), "got %lu\n", len); + ok(!lstrcmpW(method, L"POST"), "got %s\n", wine_dbgstr_w(method)); context = 0xdeadbeef; ret = WinHttpSetOption(request, WINHTTP_OPTION_CONTEXT_VALUE, &context, sizeof(context)); - ok(ret, "WinHttpSetOption failed: %u\n", GetLastError()); + ok(ret, "WinHttpSetOption failed: %lu\n", GetLastError()); /* writing more data than promised by the content-length header causes an error when the connection - is resued, so disable keep-alive */ + is reused, so disable keep-alive */ disable = WINHTTP_DISABLE_KEEP_ALIVE; ret = WinHttpSetOption(request, WINHTTP_OPTION_DISABLE_FEATURE, &disable, sizeof(disable)); - ok(ret, "WinHttpSetOption failed: %u\n", GetLastError()); + ok(ret, "WinHttpSetOption failed: %lu\n", GetLastError()); context++; ret = WinHttpSendRequest(request, content_type, header_len, post_data, optional_len, total_len, context); @@ -425,13 +427,13 @@ static void test_WinHttpSendRequest (void) skip("connection failed, skipping\n"); goto done; } - ok(ret == TRUE, "WinHttpSendRequest failed: %u\n", GetLastError()); + ok(ret == TRUE, "WinHttpSendRequest failed: %lu\n", GetLastError()); context = 0; size = sizeof(context); ret = WinHttpQueryOption(request, WINHTTP_OPTION_CONTEXT_VALUE, &context, &size); - ok(ret, "WinHttpQueryOption failed: %u\n", GetLastError()); - ok(context == 0xdeadbef0, "expected 0xdeadbef0, got %lx\n", context); + ok(ret, "WinHttpQueryOption failed: %lu\n", GetLastError()); + ok(context == 0xdeadbef0, "expected 0xdeadbef0, got %#Ix\n", context); for (i = 3; post_data[i]; i++) { @@ -440,12 +442,12 @@ static void test_WinHttpSendRequest (void) ret = WinHttpWriteData(request, &post_data[i], 1, &bytes_rw); if (ret) { - ok(GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS got %u.\n", GetLastError()); - ok(bytes_rw == 1, "WinHttpWriteData failed, wrote %u bytes instead of 1 byte.\n", bytes_rw); + ok(GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS got %lu\n", GetLastError()); + ok(bytes_rw == 1, "WinHttpWriteData failed, wrote %lu bytes instead of 1 byte\n", bytes_rw); } else /* Since we already passed all optional data in WinHttpSendRequest Win7 fails our WinHttpWriteData call */ { - ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER got %u.\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER got %lu\n", GetLastError()); ok(bytes_rw == -1, "Expected bytes_rw to remain unchanged.\n"); } } @@ -453,22 +455,22 @@ static void test_WinHttpSendRequest (void) SetLastError(0xdeadbeef); ret = WinHttpReceiveResponse(request, NULL); ok(GetLastError() == ERROR_SUCCESS || broken(GetLastError() == ERROR_NO_TOKEN) /* < win7 */, - "Expected ERROR_SUCCESS got %u.\n", GetLastError()); - ok(ret == TRUE, "WinHttpReceiveResponse failed: %u.\n", GetLastError()); + "Expected ERROR_SUCCESS got %lu\n", GetLastError()); + ok(ret == TRUE, "WinHttpReceiveResponse failed: %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_ORIG_URI, NULL, NULL, &len, NULL); - ok(!ret && GetLastError() == ERROR_WINHTTP_HEADER_NOT_FOUND, "got %u\n", GetLastError()); + ok(!ret && GetLastError() == ERROR_WINHTTP_HEADER_NOT_FOUND, "got %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_MAX + 1, NULL, NULL, &len, NULL); - ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %u\n", GetLastError()); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %lu\n", GetLastError()); bytes_rw = -1; ret = WinHttpReadData(request, buffer, sizeof(buffer) - 1, &bytes_rw); - ok(ret == TRUE, "WinHttpReadData failed: %u.\n", GetLastError()); + ok(ret == TRUE, "WinHttpReadData failed: %lu\n", GetLastError()); - ok(bytes_rw == sizeof(test_post) - 1, "Read %u bytes\n", bytes_rw); + ok(bytes_rw == sizeof(test_post) - 1, "Read %lu bytes\n", bytes_rw); ok(!memcmp(buffer, test_post, sizeof(test_post) - 1), "Data read did not match.\n"); done: @@ -480,13 +482,45 @@ static void test_WinHttpSendRequest (void) ok(ret == TRUE, "WinHttpCloseHandle failed on closing session, got %d.\n", ret); } +static void test_connect_error(void) +{ + static const WCHAR content_type[] = L"Content-Type: application/x-www-form-urlencoded"; + DWORD header_len, optional_len, total_len, err, t1, t2; + HINTERNET session, request, connection; + static char post_data[] = "mode=Test"; + BOOL ret; + + header_len = ~0u; + total_len = optional_len = sizeof(post_data); + + session = WinHttpOpen(L"winetest", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); + ok(!!session, "WinHttpOpen failed to open session.\n"); + + connection = WinHttpConnect (session, L"127.0.0.1", 12345, 0); + ok(!!connection, "WinHttpConnect failed to open a connection, error %lu.\n", GetLastError()); + + request = WinHttpOpenRequest(connection, L"POST", L"tests/post.php", NULL, WINHTTP_NO_REFERER, + WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_BYPASS_PROXY_CACHE); + ok(!!request, "WinHttpOpenrequest failed to open a request, error: %lu\n", GetLastError()); + + t1 = GetTickCount(); + ret = WinHttpSendRequest(request, content_type, header_len, post_data, optional_len, total_len, 0); + t2 = GetTickCount(); + err = GetLastError(); + ok(!ret, "WinHttpSendRequest() succeeded.\n"); + ok(err == ERROR_WINHTTP_CANNOT_CONNECT, "Got unexpected err %lu.\n", err); + ok(t2 - t1 < 5000, "Unexpected connect failure delay %lums.\n", t2 - t1); + + WinHttpCloseHandle(request); + WinHttpCloseHandle(connection); + WinHttpCloseHandle(session); +} + static void test_WinHttpTimeFromSystemTime(void) { BOOL ret; static const SYSTEMTIME time = {2008, 7, 1, 28, 10, 5, 52, 0}; - static const WCHAR expected_string[] = - {'M','o','n',',',' ','2','8',' ','J','u','l',' ','2','0','0','8',' ', - '1','0',':','0','5',':','5','2',' ','G','M','T',0}; WCHAR time_string[WINHTTP_TIME_FORMAT_BUFSIZE+1]; DWORD err; @@ -494,20 +528,20 @@ static void test_WinHttpTimeFromSystemTime(void) ret = WinHttpTimeFromSystemTime(&time, NULL); err = GetLastError(); ok(!ret, "WinHttpTimeFromSystemTime succeeded\n"); - ok(err == ERROR_INVALID_PARAMETER, "got %u\n", err); + ok(err == ERROR_INVALID_PARAMETER, "got %lu\n", err); SetLastError(0xdeadbeef); ret = WinHttpTimeFromSystemTime(NULL, time_string); err = GetLastError(); ok(!ret, "WinHttpTimeFromSystemTime succeeded\n"); - ok(err == ERROR_INVALID_PARAMETER, "got %u\n", err); + ok(err == ERROR_INVALID_PARAMETER, "got %lu\n", err); SetLastError(0xdeadbeef); ret = WinHttpTimeFromSystemTime(&time, time_string); err = GetLastError(); - ok(ret, "WinHttpTimeFromSystemTime failed: %u\n", err); - ok(err == ERROR_SUCCESS || broken(err == 0xdeadbeef) /* < win7 */, "got %u\n", err); - ok(memcmp(time_string, expected_string, sizeof(expected_string)) == 0, + ok(ret, "WinHttpTimeFromSystemTime failed: %lu\n", err); + ok(err == ERROR_SUCCESS || broken(err == 0xdeadbeef) /* < win7 */, "got %lu\n", err); + ok(!memcmp(time_string, L"Mon, 28 Jul 2008 10:05:52 GMT", sizeof(L"Mon, 28 Jul 2008 10:05:52 GMT")), "Time string returned did not match expected time string.\n"); } @@ -516,147 +550,114 @@ static void test_WinHttpTimeToSystemTime(void) BOOL ret; SYSTEMTIME time; static const SYSTEMTIME expected_time = {2008, 7, 1, 28, 10, 5, 52, 0}; - static const WCHAR time_string1[] = - {'M','o','n',',',' ','2','8',' ','J','u','l',' ','2','0','0','8',' ', - + '1','0',':','0','5',':','5','2',' ','G','M','T','\n',0}; - static const WCHAR time_string2[] = - {' ','m','o','n',' ','2','8',' ','j','u','l',' ','2','0','0','8',' ', - '1','0',' ','0','5',' ','5','2','\n',0}; DWORD err; SetLastError(0xdeadbeef); - ret = WinHttpTimeToSystemTime(time_string1, NULL); + ret = WinHttpTimeToSystemTime(L"Mon, 28 Jul 2008 10:05:52 GMT\n", NULL); err = GetLastError(); ok(!ret, "WinHttpTimeToSystemTime succeeded\n"); - ok(err == ERROR_INVALID_PARAMETER, "got %u\n", err); + ok(err == ERROR_INVALID_PARAMETER, "got %lu\n", err); SetLastError(0xdeadbeef); ret = WinHttpTimeToSystemTime(NULL, &time); err = GetLastError(); ok(!ret, "WinHttpTimeToSystemTime succeeded\n"); - ok(err == ERROR_INVALID_PARAMETER, "got %u\n", err); + ok(err == ERROR_INVALID_PARAMETER, "got %lu\n", err); SetLastError(0xdeadbeef); - ret = WinHttpTimeToSystemTime(time_string1, &time); + ret = WinHttpTimeToSystemTime(L"Mon, 28 Jul 2008 10:05:52 GMT\n", &time); err = GetLastError(); - ok(ret, "WinHttpTimeToSystemTime failed: %u\n", err); - ok(err == ERROR_SUCCESS || broken(err == 0xdeadbeef) /* < win7 */, "got %u\n", err); + ok(ret, "WinHttpTimeToSystemTime failed: %lu\n", err); + ok(err == ERROR_SUCCESS || broken(err == 0xdeadbeef) /* < win7 */, "got %lu\n", err); ok(memcmp(&time, &expected_time, sizeof(SYSTEMTIME)) == 0, "Returned SYSTEMTIME structure did not match expected SYSTEMTIME structure.\n"); SetLastError(0xdeadbeef); - ret = WinHttpTimeToSystemTime(time_string2, &time); + ret = WinHttpTimeToSystemTime(L" mon 28 jul 2008 10 05 52\n", &time); err = GetLastError(); - ok(ret, "WinHttpTimeToSystemTime failed: %u\n", err); - ok(err == ERROR_SUCCESS || broken(err == 0xdeadbeef) /* < win7 */, "got %u\n", err); + ok(ret, "WinHttpTimeToSystemTime failed: %lu\n", err); + ok(err == ERROR_SUCCESS || broken(err == 0xdeadbeef) /* < win7 */, "got %lu\n", err); ok(memcmp(&time, &expected_time, sizeof(SYSTEMTIME)) == 0, "Returned SYSTEMTIME structure did not match expected SYSTEMTIME structure.\n"); } static void test_WinHttpAddHeaders(void) { + static const WCHAR test_header_begin[] = + {'P','O','S','T',' ','/','p','o','s','t','t','e','s','t','.','p','h','p',' ','H','T','T','P','/','1'}; HINTERNET session, request, connection; BOOL ret, reverse; WCHAR buffer[MAX_PATH]; WCHAR check_buffer[MAX_PATH]; DWORD err, index, len, oldlen; - static const WCHAR test_file[] = {'/','p','o','s','t','t','e','s','t','.','p','h','p',0}; - static const WCHAR test_verb[] = {'P','O','S','T',0}; - static const WCHAR test_header_begin[] = - {'P','O','S','T',' ','/','p','o','s','t','t','e','s','t','.','p','h','p',' ','H','T','T','P','/','1'}; - static const WCHAR full_path_test_header_begin[] = - {'P','O','S','T',' ','h','t','t','p',':','/','/','t','e','s','t','.','w','i','n','e','h','q','.','o','r','g',':','8','0', - '/','p','o','s','t','t','e','s','t','.','p','h','p',' ','H','T','T','P','/','1'}; - static const WCHAR test_header_end[] = {'\r','\n','\r','\n',0}; - static const WCHAR test_header_name[] = {'W','a','r','n','i','n','g',0}; - static const WCHAR test_header_name2[] = {'n','a','m','e',0}; - static const WCHAR test_header_name3[] = {'a',0}; - static const WCHAR test_header_range[] = {'R','a','n','g','e',0}; - static const WCHAR test_header_range_bytes[] = {'R','a','n','g','e',':',' ','b','y','t','e','s','=','0','-','7','7','3','\r','\n',0}; - static const WCHAR test_header_bytes[] = {'b','y','t','e','s','=','0','-','7','7','3',0}; - - static const WCHAR test_flag_coalesce[] = {'t','e','s','t','2',',',' ','t','e','s','t','4',0}; - static const WCHAR test_flag_coalesce_reverse[] = {'t','e','s','t','3',',',' ','t','e','s','t','4',0}; - static const WCHAR test_flag_coalesce_comma[] = - {'t','e','s','t','2',',',' ','t','e','s','t','4',',',' ','t','e','s','t','5',0}; - static const WCHAR test_flag_coalesce_comma_reverse[] = - {'t','e','s','t','3',',',' ','t','e','s','t','4',',',' ','t','e','s','t','5',0}; - static const WCHAR test_flag_coalesce_semicolon[] = - {'t','e','s','t','2',',',' ','t','e','s','t','4',',',' ','t','e','s','t','5',';',' ','t','e','s','t','6',0}; - static const WCHAR test_flag_coalesce_semicolon_reverse[] = - {'t','e','s','t','3',',',' ','t','e','s','t','4',',',' ','t','e','s','t','5',';',' ','t','e','s','t','6',0}; - - static const WCHAR field[] = {'f','i','e','l','d',0}; - static const WCHAR value[] = {'v','a','l','u','e',' ',0}; - static const WCHAR value_nospace[] = {'v','a','l','u','e',0}; - static const WCHAR empty[] = {0}; - static const WCHAR test_headers[][14] = - { - {'W','a','r','n','i','n','g',':','t','e','s','t','1',0}, - {'W','a','r','n','i','n','g',':','t','e','s','t','2',0}, - {'W','a','r','n','i','n','g',':','t','e','s','t','3',0}, - {'W','a','r','n','i','n','g',':','t','e','s','t','4',0}, - {'W','a','r','n','i','n','g',':','t','e','s','t','5',0}, - {'W','a','r','n','i','n','g',':','t','e','s','t','6',0}, - {'W','a','r','n','i','n','g',':','t','e','s','t','7',0}, - {0}, - {':',0}, - {'a',':',0}, - {':','b',0}, - {'c','d',0}, - {' ','e',' ',':','f',0}, - {'f','i','e','l','d',':',' ','v','a','l','u','e',' ',0}, - {'n','a','m','e',':',' ','v','a','l','u','e',0}, - {'n','a','m','e',':',0} - }; + { + L"Warning:test1", + L"Warning:test2", + L"Warning:test3", + L"Warning:test4", + L"Warning:test5", + L"Warning:test6", + L"Warning:test7", + L"", + L":", + L"a:", + L":b", + L"cd", + L" e :f", + L"field: value ", + L"name: value", + L"name:", + L"g : value", + }; static const WCHAR test_indices[][6] = - { - {'t','e','s','t','1',0}, - {'t','e','s','t','2',0}, - {'t','e','s','t','3',0}, - {'t','e','s','t','4',0} - }; + { + L"test1", + L"test2", + L"test3", + L"test4", + }; - session = WinHttpOpen(test_useragent, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + session = WinHttpOpen(L"winetest", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); ok(session != NULL, "WinHttpOpen failed to open session.\n"); - connection = WinHttpConnect (session, test_winehq, INTERNET_DEFAULT_HTTP_PORT, 0); - ok(connection != NULL, "WinHttpConnect failed to open a connection, error: %u.\n", GetLastError()); + connection = WinHttpConnect (session, L"test.winehq.org", INTERNET_DEFAULT_HTTP_PORT, 0); + ok(connection != NULL, "WinHttpConnect failed to open a connection, error: %lu\n", GetLastError()); - request = WinHttpOpenRequest(connection, test_verb, test_file, NULL, WINHTTP_NO_REFERER, + request = WinHttpOpenRequest(connection, L"POST", L"/posttest.php", NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0); if (request == NULL && GetLastError() == ERROR_WINHTTP_NAME_NOT_RESOLVED) { skip("Network unreachable, skipping.\n"); goto done; } - ok(request != NULL, "WinHttpOpenRequest failed to open a request, error: %u.\n", GetLastError()); + ok(request != NULL, "WinHttpOpenRequest failed to open a request, error: %lu\n", GetLastError()); index = 0; len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, - test_header_name, buffer, &len, &index); + L"Warning", buffer, &len, &index); ok(ret == FALSE, "WinHttpQueryHeaders unexpectedly succeeded, found 'Warning' header.\n"); SetLastError(0xdeadbeef); ret = WinHttpAddRequestHeaders(request, test_headers[0], -1L, WINHTTP_ADDREQ_FLAG_ADD); err = GetLastError(); - ok(ret, "WinHttpAddRequestHeaders failed to add new header, got %d with error %u.\n", ret, err); - ok(err == ERROR_SUCCESS || broken(err == 0xdeadbeef) /* < win7 */, "got %u\n", err); + ok(ret, "WinHttpAddRequestHeaders failed to add new header, got %d with error %lu\n", ret, err); + ok(err == ERROR_SUCCESS || broken(err == 0xdeadbeef) /* < win7 */, "got %lu\n", err); index = 0; len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, - test_header_name, buffer, &len, &index); - ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + L"Warning", buffer, &len, &index); + ok(ret == TRUE, "WinHttpQueryHeaders failed: %lu\n", GetLastError()); ok(index == 1, "WinHttpQueryHeaders failed: header index not incremented\n"); - ok(memcmp(buffer, test_indices[0], sizeof(test_indices[0])) == 0, "WinHttpQueryHeaders failed: incorrect string returned\n"); - ok(len == 5*sizeof(WCHAR), "WinHttpQueryHeaders failed: invalid length returned, expected 5, got %d\n", len); + ok(!memcmp(buffer, test_indices[0], sizeof(test_indices[0])), + "WinHttpQueryHeaders failed: incorrect string returned\n"); + ok(len == 5 * sizeof(WCHAR), "WinHttpQueryHeaders failed: invalid length returned, expected 5, got %lu\n", len); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, - test_header_name, buffer, &len, &index); + L"Warning", buffer, &len, &index); ok(ret == FALSE, "WinHttpQueryHeaders unexpectedly succeeded, second index should not exist.\n"); /* Try to fetch the header info with a buffer that's big enough to fit the @@ -667,21 +668,21 @@ static void test_WinHttpAddHeaders(void) memset(check_buffer, 0xab, sizeof(check_buffer)); memcpy(buffer, check_buffer, sizeof(buffer)); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, - test_header_name, buffer, &len, &index); + L"Warning", buffer, &len, &index); ok(ret == FALSE, "WinHttpQueryHeaders unexpectedly succeeded with a buffer that's too small.\n"); ok(memcmp(buffer, check_buffer, sizeof(buffer)) == 0, "WinHttpQueryHeaders failed, modified the buffer when it should not have.\n"); - ok(len == 6*sizeof(WCHAR), "WinHttpQueryHeaders returned invalid length, expected 12, got %d\n", len); + ok(len == 6 * sizeof(WCHAR), "WinHttpQueryHeaders returned invalid length, expected 12, got %lu\n", len); /* Try with a NULL buffer */ index = 0; len = sizeof(buffer); SetLastError(0xdeadbeef); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_RAW_HEADERS_CRLF | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, - test_header_name, NULL, &len, &index); + L"Warning", NULL, &len, &index); ok(ret == FALSE, "WinHttpQueryHeaders unexpectedly succeeded.\n"); - ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Expected ERROR_INSUFFICIENT_BUFFER, got %u\n", GetLastError()); - ok(len > 40, "WinHttpQueryHeaders returned invalid length: expected greater than 40, got %d\n", len); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Expected ERROR_INSUFFICIENT_BUFFER, got %lu\n", GetLastError()); + ok(len > 40, "WinHttpQueryHeaders returned invalid length: expected greater than 40, got %lu\n", len); ok(index == 0, "WinHttpQueryHeaders incorrectly incremented header index.\n"); /* Try with a NULL buffer and a length that's too small */ @@ -689,22 +690,22 @@ static void test_WinHttpAddHeaders(void) len = 10; SetLastError(0xdeadbeef); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_RAW_HEADERS_CRLF | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, - test_header_name, NULL, &len, &index); + L"Warning", NULL, &len, &index); ok(ret == FALSE, "WinHttpQueryHeaders unexpectedly succeeded.\n"); ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, - "WinHttpQueryHeaders set incorrect error: expected ERROR_INSUFFICENT_BUFFER, got %u\n", GetLastError()); - ok(len > 40, "WinHttpQueryHeaders returned invalid length: expected greater than 40, got %d\n", len); + "WinHttpQueryHeaders set incorrect error: expected ERROR_INSUFFICIENT_BUFFER, got %lu\n", GetLastError()); + ok(len > 40, "WinHttpQueryHeaders returned invalid length: expected greater than 40, got %lu\n", len); ok(index == 0, "WinHttpQueryHeaders incorrectly incremented header index.\n"); index = 0; len = 0; SetLastError(0xdeadbeef); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_RAW_HEADERS_CRLF | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, - test_header_name, NULL, &len, &index); + L"Warning", NULL, &len, &index); ok(ret == FALSE, "WinHttpQueryHeaders unexpectedly succeeded.\n"); ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, - "WinHttpQueryHeaders set incorrect error: expected ERROR_INSUFFICIENT_BUFFER, got %u\n", GetLastError()); - ok(len > 40, "WinHttpQueryHeaders returned invalid length: expected greater than 40, got %d\n", len); + "WinHttpQueryHeaders set incorrect error: expected ERROR_INSUFFICIENT_BUFFER, got %lu\n", GetLastError()); + ok(len > 40, "WinHttpQueryHeaders returned invalid length: expected greater than 40, got %lu\n", len); ok(index == 0, "WinHttpQueryHeaders failed: index was incremented.\n"); /* valid query */ @@ -713,15 +714,14 @@ static void test_WinHttpAddHeaders(void) len = sizeof(buffer); memset(buffer, 0xff, sizeof(buffer)); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_RAW_HEADERS_CRLF | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, - test_header_name, buffer, &len, &index); + L"Warning", buffer, &len, &index); ok(ret == TRUE, "WinHttpQueryHeaders failed: got %d\n", ret); ok(len + sizeof(WCHAR) <= oldlen, "WinHttpQueryHeaders resulting length longer than advertized.\n"); - ok((len < sizeof(buffer) - sizeof(WCHAR)) && buffer[len / sizeof(WCHAR)] == 0, "WinHttpQueryHeaders did not append NULL terminator\n"); + ok((len < sizeof(buffer) - sizeof(WCHAR)) && !buffer[len / sizeof(WCHAR)], + "WinHttpQueryHeaders did not append NULL terminator\n"); ok(len == lstrlenW(buffer) * sizeof(WCHAR), "WinHttpQueryHeaders returned incorrect length.\n"); - ok(memcmp(buffer, test_header_begin, sizeof(test_header_begin)) == 0 || - memcmp(buffer, full_path_test_header_begin, sizeof(full_path_test_header_begin)) == 0, - "WinHttpQueryHeaders returned invalid beginning of header string.\n"); - ok(memcmp(buffer + lstrlenW(buffer) - 4, test_header_end, sizeof(test_header_end)) == 0, + ok(!memcmp(buffer, test_header_begin, sizeof(test_header_begin)), "invalid beginning of header string.\n"); + ok(!memcmp(buffer + lstrlenW(buffer) - 4, L"\r\n\r\n", sizeof(L"\r\n\r\n")), "WinHttpQueryHeaders returned invalid end of header string.\n"); ok(index == 0, "WinHttpQueryHeaders incremented header index.\n"); @@ -729,11 +729,11 @@ static void test_WinHttpAddHeaders(void) len = 0; SetLastError(0xdeadbeef); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_RAW_HEADERS | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, - test_header_name, NULL, &len, &index); + L"Warning", NULL, &len, &index); ok(ret == FALSE, "WinHttpQueryHeaders unexpectedly succeeded.\n"); ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, - "WinHttpQueryHeaders set incorrect error: expected ERROR_INSUFFICIENT_BUFFER, got %u\n", GetLastError()); - ok(len > 40, "WinHttpQueryHeaders returned invalid length: expected greater than 40, got %d\n", len); + "WinHttpQueryHeaders set incorrect error: expected ERROR_INSUFFICIENT_BUFFER, got %lu\n", GetLastError()); + ok(len > 40, "WinHttpQueryHeaders returned invalid length: expected greater than 40, got %lu\n", len); ok(index == 0, "WinHttpQueryHeaders failed: index was incremented.\n"); oldlen = len; @@ -741,14 +741,12 @@ static void test_WinHttpAddHeaders(void) len = sizeof(buffer); memset(buffer, 0xff, sizeof(buffer)); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_RAW_HEADERS | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, - test_header_name, buffer, &len, &index); - ok(ret == TRUE, "WinHttpQueryHeaders failed %u\n", GetLastError()); + L"Warning", buffer, &len, &index); + ok(ret == TRUE, "WinHttpQueryHeaders failed %lu\n", GetLastError()); ok(len + sizeof(WCHAR) <= oldlen, "resulting length longer than advertized\n"); ok((len < sizeof(buffer) - sizeof(WCHAR)) && !buffer[len / sizeof(WCHAR)] && !buffer[len / sizeof(WCHAR) - 1], "no double NULL terminator\n"); - ok(memcmp(buffer, test_header_begin, sizeof(test_header_begin)) == 0 || - memcmp(buffer, full_path_test_header_begin, sizeof(full_path_test_header_begin)) == 0, - "invalid beginning of header string.\n"); + ok(!memcmp(buffer, test_header_begin, sizeof(test_header_begin)), "invalid beginning of header string.\n"); ok(index == 0, "header index was incremented\n"); /* tests for more indices */ @@ -758,15 +756,15 @@ static void test_WinHttpAddHeaders(void) index = 0; len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, - test_header_name, buffer, &len, &index); - ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + L"Warning", buffer, &len, &index); + ok(ret == TRUE, "WinHttpQueryHeaders failed: %lu\n", GetLastError()); ok(index == 1, "WinHttpQueryHeaders failed to increment index.\n"); ok(memcmp(buffer, test_indices[0], sizeof(test_indices[0])) == 0, "WinHttpQueryHeaders returned incorrect string.\n"); len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, - test_header_name, buffer, &len, &index); - ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + L"Warning", buffer, &len, &index); + ok(ret == TRUE, "WinHttpQueryHeaders failed: %lu\n", GetLastError()); ok(index == 2, "WinHttpQueryHeaders failed to increment index.\n"); ok(memcmp(buffer, test_indices[1], sizeof(test_indices[1])) == 0, "WinHttpQueryHeaders returned incorrect string.\n"); @@ -776,18 +774,20 @@ static void test_WinHttpAddHeaders(void) index = 0; len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, - test_header_name, buffer, &len, &index); - ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + L"Warning", buffer, &len, &index); + ok(ret == TRUE, "WinHttpQueryHeaders failed: %lu\n", GetLastError()); ok(index == 1, "WinHttpQueryHeaders failed to increment index.\n"); reverse = (memcmp(buffer, test_indices[1], sizeof(test_indices[1])) != 0); /* Win7 returns values in reverse order of adding */ - ok(memcmp(buffer, test_indices[reverse ? 2 : 1], sizeof(test_indices[reverse ? 2 : 1])) == 0, "WinHttpQueryHeaders returned incorrect string.\n"); + ok(!memcmp(buffer, test_indices[reverse ? 2 : 1], sizeof(test_indices[reverse ? 2 : 1])), + "WinHttpQueryHeaders returned incorrect string.\n"); len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, - test_header_name, buffer, &len, &index); - ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + L"Warning", buffer, &len, &index); + ok(ret == TRUE, "WinHttpQueryHeaders failed: %lu\n", GetLastError()); ok(index == 2, "WinHttpQueryHeaders failed to increment index.\n"); - ok(memcmp(buffer, test_indices[reverse ? 1 : 2], sizeof(test_indices[reverse ? 1 : 2])) == 0, "WinHttpQueryHeaders returned incorrect string.\n"); + ok(!memcmp(buffer, test_indices[reverse ? 1 : 2], sizeof(test_indices[reverse ? 1 : 2])), + "WinHttpQueryHeaders returned incorrect string.\n"); /* add if new flag */ ret = WinHttpAddRequestHeaders(request, test_headers[3], -1L, WINHTTP_ADDREQ_FLAG_ADD_IF_NEW); @@ -796,21 +796,23 @@ static void test_WinHttpAddHeaders(void) index = 0; len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, - test_header_name, buffer, &len, &index); - ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + L"Warning", buffer, &len, &index); + ok(ret == TRUE, "WinHttpQueryHeaders failed: %lu\n", GetLastError()); ok(index == 1, "WinHttpQueryHeaders failed to increment index.\n"); - ok(memcmp(buffer, test_indices[reverse ? 2 : 1], sizeof(test_indices[reverse ? 2 : 1])) == 0, "WinHttpQueryHeaders returned incorrect string.\n"); + ok(!memcmp(buffer, test_indices[reverse ? 2 : 1], sizeof(test_indices[reverse ? 2 : 1])), + "WinHttpQueryHeaders returned incorrect string.\n"); len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, - test_header_name, buffer, &len, &index); - ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + L"Warning", buffer, &len, &index); + ok(ret == TRUE, "WinHttpQueryHeaders failed: %lu\n", GetLastError()); ok(index == 2, "WinHttpQueryHeaders failed to increment index.\n"); - ok(memcmp(buffer, test_indices[reverse ? 1 : 2], sizeof(test_indices[reverse ? 1 : 2])) == 0, "WinHttpQueryHeaders returned incorrect string.\n"); + ok(!memcmp(buffer, test_indices[reverse ? 1 : 2], sizeof(test_indices[reverse ? 1 : 2])), + "WinHttpQueryHeaders returned incorrect string.\n"); len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, - test_header_name, buffer, &len, &index); + L"Warning", buffer, &len, &index); ok(ret == FALSE, "WinHttpQueryHeaders succeeded unexpectedly, found third header.\n"); /* coalesce flag */ @@ -820,22 +822,24 @@ static void test_WinHttpAddHeaders(void) index = 0; len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, - test_header_name, buffer, &len, &index); - ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + L"Warning", buffer, &len, &index); + ok(ret == TRUE, "WinHttpQueryHeaders failed: %lu\n", GetLastError()); ok(index == 1, "WinHttpQueryHeaders failed to increment index.\n"); - ok(memcmp(buffer, reverse ? test_flag_coalesce_reverse : test_flag_coalesce, - reverse ? sizeof(test_flag_coalesce_reverse) : sizeof(test_flag_coalesce)) == 0, "WinHttpQueryHeaders returned incorrect string.\n"); + ok(!memcmp(buffer, reverse ? L"test3, test4" : L"test2, test4", + reverse ? sizeof(L"test3, test4") : sizeof(L"test2, test4")), + "WinHttpQueryHeaders returned incorrect string.\n"); len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, - test_header_name, buffer, &len, &index); - ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + L"Warning", buffer, &len, &index); + ok(ret == TRUE, "WinHttpQueryHeaders failed: %lu\n", GetLastError()); ok(index == 2, "WinHttpQueryHeaders failed to increment index.\n"); - ok(memcmp(buffer, test_indices[reverse ? 1 : 2], sizeof(test_indices[reverse ? 1 : 2])) == 0, "WinHttpQueryHeaders returned incorrect string.\n"); + ok(!memcmp(buffer, test_indices[reverse ? 1 : 2], sizeof(test_indices[reverse ? 1 : 2])), + "WinHttpQueryHeaders returned incorrect string.\n"); len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, - test_header_name, buffer, &len, &index); + L"Warning", buffer, &len, &index); ok(ret == FALSE, "WinHttpQueryHeaders succeeded unexpectedly, found third header.\n"); /* coalesce with comma flag */ @@ -845,23 +849,25 @@ static void test_WinHttpAddHeaders(void) index = 0; len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, - test_header_name, buffer, &len, &index); - ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + L"Warning", buffer, &len, &index); + ok(ret == TRUE, "WinHttpQueryHeaders failed: %lu\n", GetLastError()); ok(index == 1, "WinHttpQueryHeaders failed to increment index.\n"); - ok(memcmp(buffer, reverse ? test_flag_coalesce_comma_reverse : test_flag_coalesce_comma, - reverse ? sizeof(test_flag_coalesce_comma_reverse) : sizeof(test_flag_coalesce_comma)) == 0, + + ok(!memcmp(buffer, reverse ? L"test3, test4, test5" : L"test2, test4, test5", + reverse ? sizeof(L"test3, test4, test5") : sizeof(L"test2, test4, test5")), "WinHttpQueryHeaders returned incorrect string.\n"); len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, - test_header_name, buffer, &len, &index); - ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + L"Warning", buffer, &len, &index); + ok(ret == TRUE, "WinHttpQueryHeaders failed: %lu\n", GetLastError()); ok(index == 2, "WinHttpQueryHeaders failed to increment index.\n"); - ok(memcmp(buffer, test_indices[reverse ? 1 : 2], sizeof(test_indices[reverse ? 1 : 2])) == 0, "WinHttpQueryHeaders returned incorrect string.\n"); + ok(!memcmp(buffer, test_indices[reverse ? 1 : 2], sizeof(test_indices[reverse ? 1 : 2])), + "WinHttpQueryHeaders returned incorrect string.\n"); len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, - test_header_name, buffer, &len, &index); + L"Warning", buffer, &len, &index); ok(ret == FALSE, "WinHttpQueryHeaders succeeded unexpectedly, found third header.\n"); @@ -872,23 +878,25 @@ static void test_WinHttpAddHeaders(void) index = 0; len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, - test_header_name, buffer, &len, &index); - ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + L"Warning", buffer, &len, &index); + ok(ret == TRUE, "WinHttpQueryHeaders failed: %lu\n", GetLastError()); ok(index == 1, "WinHttpQueryHeaders failed to increment index.\n"); - ok(memcmp(buffer, reverse ? test_flag_coalesce_semicolon_reverse : test_flag_coalesce_semicolon, - reverse ? sizeof(test_flag_coalesce_semicolon_reverse) : sizeof(test_flag_coalesce_semicolon)) == 0, - "WinHttpQueryHeaders returned incorrect string.\n"); + + ok(!memcmp(buffer, reverse ? L"test3, test4, test5; test6" : L"test2, test4, test5; test6", + reverse ? sizeof(L"test3, test4, test5; test6") : sizeof(L"test2, test4, test5; test6")), + "WinHttpQueryHeaders returned incorrect string.\n"); len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, - test_header_name, buffer, &len, &index); - ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + L"Warning", buffer, &len, &index); + ok(ret == TRUE, "WinHttpQueryHeaders failed: %lu\n", GetLastError()); ok(index == 2, "WinHttpQueryHeaders failed to increment index.\n"); - ok(memcmp(buffer, test_indices[reverse ? 1 : 2], sizeof(test_indices[reverse ? 1 : 2])) == 0, "WinHttpQueryHeaders returned incorrect string.\n"); + ok(!memcmp(buffer, test_indices[reverse ? 1 : 2], sizeof(test_indices[reverse ? 1 : 2])), + "WinHttpQueryHeaders returned incorrect string.\n"); len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, - test_header_name, buffer, &len, &index); + L"Warning", buffer, &len, &index); ok(ret == FALSE, "WinHttpQueryHeaders succeeded unexpectedly, found third header.\n"); /* add and replace flags */ @@ -898,21 +906,23 @@ static void test_WinHttpAddHeaders(void) index = 0; len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, - test_header_name, buffer, &len, &index); - ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + L"Warning", buffer, &len, &index); + ok(ret == TRUE, "WinHttpQueryHeaders failed: %lu\n", GetLastError()); ok(index == 1, "WinHttpQueryHeaders failed to increment index.\n"); - ok(memcmp(buffer, test_indices[reverse ? 3 : 2], sizeof(test_indices[reverse ? 3 : 2])) == 0, "WinHttpQueryHeaders returned incorrect string.\n"); + ok(!memcmp(buffer, test_indices[reverse ? 3 : 2], sizeof(test_indices[reverse ? 3 : 2])), + "WinHttpQueryHeaders returned incorrect string.\n"); len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, - test_header_name, buffer, &len, &index); - ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + L"Warning", buffer, &len, &index); + ok(ret == TRUE, "WinHttpQueryHeaders failed: %lu\n", GetLastError()); ok(index == 2, "WinHttpQueryHeaders failed to increment index.\n"); - ok(memcmp(buffer, test_indices[reverse ? 1 : 3], sizeof(test_indices[reverse ? 1 : 3])) == 0, "WinHttpQueryHeaders returned incorrect string.\n"); + ok(!memcmp(buffer, test_indices[reverse ? 1 : 3], sizeof(test_indices[reverse ? 1 : 3])), + "WinHttpQueryHeaders returned incorrect string.\n"); len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, - test_header_name, buffer, &len, &index); + L"Warning", buffer, &len, &index); ok(ret == FALSE, "WinHttpQueryHeaders succeeded unexpectedly, found third header.\n"); ret = WinHttpAddRequestHeaders(request, test_headers[8], ~0u, WINHTTP_ADDREQ_FLAG_ADD); @@ -925,9 +935,9 @@ static void test_WinHttpAddHeaders(void) memset(buffer, 0xff, sizeof(buffer)); len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, - test_header_name3, buffer, &len, &index); - ok(ret, "WinHttpQueryHeaders failed: %u\n", GetLastError()); - ok(!memcmp(buffer, empty, sizeof(empty)), "unexpected result\n"); + L"a", buffer, &len, &index); + ok(ret, "WinHttpQueryHeaders failed: %lu\n", GetLastError()); + ok(!memcmp(buffer, L"", sizeof(L"")), "unexpected result\n"); ret = WinHttpAddRequestHeaders(request, test_headers[10], ~0u, WINHTTP_ADDREQ_FLAG_ADD); ok(!ret, "WinHttpAddRequestHeaders failed\n"); @@ -941,79 +951,82 @@ static void test_WinHttpAddHeaders(void) ret = WinHttpAddRequestHeaders(request, test_headers[13], ~0u, WINHTTP_ADDREQ_FLAG_ADD); ok(ret, "WinHttpAddRequestHeaders failed\n"); + ret = WinHttpAddRequestHeaders(request, test_headers[16], ~0u, WINHTTP_ADDREQ_FLAG_ADD); + ok(!ret, "adding %s succeeded.\n", debugstr_w(test_headers[16])); + index = 0; buffer[0] = 0; len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, - field, buffer, &len, &index); - ok(ret, "WinHttpQueryHeaders failed: %u\n", GetLastError()); - ok(!memcmp(buffer, value, sizeof(value)) || ! memcmp(buffer, value_nospace, sizeof(value_nospace)), "unexpected result\n"); + L"field", buffer, &len, &index); + ok(ret, "WinHttpQueryHeaders failed: %lu\n", GetLastError()); + ok(!memcmp(buffer, L"value ", sizeof(L"value ")) || !memcmp(buffer, L"value", sizeof(L"value")), + "unexpected result\n"); SetLastError(0xdeadbeef); - ret = WinHttpAddRequestHeaders(request, test_header_range_bytes, 0, + ret = WinHttpAddRequestHeaders(request, L"Range: bytes=0-773\r\n", 0, WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE); err = GetLastError(); ok(!ret, "unexpected success\n"); - ok(err == ERROR_INVALID_PARAMETER, "got %u\n", err); + ok(err == ERROR_INVALID_PARAMETER, "got %lu\n", err); - ret = WinHttpAddRequestHeaders(request, test_header_range_bytes, ~0u, + ret = WinHttpAddRequestHeaders(request, L"Range: bytes=0-773\r\n", ~0u, WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE); - ok(ret, "failed to add header: %u\n", GetLastError()); + ok(ret, "failed to add header: %lu\n", GetLastError()); index = 0; len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, - test_header_range, buffer, &len, &index); - ok(ret, "failed to get range header %u\n", GetLastError()); - ok(!memcmp(buffer, test_header_bytes, sizeof(test_header_bytes)), "incorrect string returned\n"); - ok(len == lstrlenW(test_header_bytes) * sizeof(WCHAR), "wrong length %u\n", len); - ok(index == 1, "wrong index %u\n", index); - + L"Range", buffer, &len, &index); + ok(ret, "failed to get range header %lu\n", GetLastError()); + ok(!memcmp(buffer, L"bytes=0-773", sizeof(L"bytes=0-773")), "incorrect string returned\n"); + ok(len == lstrlenW(L"bytes=0-773") * sizeof(WCHAR), "wrong length %lu\n", len); + ok(index == 1, "wrong index %lu\n", index); index = 0; len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, - test_header_name2, buffer, &len, &index); + L"name", buffer, &len, &index); ok(!ret, "unexpected success\n"); SetLastError(0xdeadbeef); ret = WinHttpAddRequestHeaders(request, test_headers[14], ~0u, WINHTTP_ADDREQ_FLAG_REPLACE); err = GetLastError(); ok(!ret, "unexpected success\n"); - ok(err == ERROR_WINHTTP_HEADER_NOT_FOUND, "got %u\n", err); + ok(err == ERROR_WINHTTP_HEADER_NOT_FOUND, "got %lu\n", err); ret = WinHttpAddRequestHeaders(request, test_headers[14], ~0u, WINHTTP_ADDREQ_FLAG_ADD); - ok(ret, "got %u\n", GetLastError()); + ok(ret, "got %lu\n", GetLastError()); index = 0; len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, - test_header_name2, buffer, &len, &index); - ok(ret, "got %u\n", GetLastError()); - ok(index == 1, "wrong index %u\n", index); - ok(!memcmp(buffer, value_nospace, sizeof(value_nospace)), "incorrect string\n"); + L"name", buffer, &len, &index); + ok(ret, "got %lu\n", GetLastError()); + ok(index == 1, "wrong index %lu\n", index); + ok(!memcmp(buffer, L"value", sizeof(L"value")), "incorrect string\n"); ret = WinHttpAddRequestHeaders(request, test_headers[15], ~0u, WINHTTP_ADDREQ_FLAG_REPLACE); - ok(ret, "got %u\n", GetLastError()); + ok(ret, "got %lu\n", GetLastError()); index = 0; len = sizeof(buffer); SetLastError(0xdeadbeef); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, - test_header_name2, buffer, &len, &index); + L"name", buffer, &len, &index); err = GetLastError(); ok(!ret, "unexpected success\n"); - ok(err == ERROR_WINHTTP_HEADER_NOT_FOUND, "got %u\n", err); + ok(err == ERROR_WINHTTP_HEADER_NOT_FOUND, "got %lu\n", err); ret = WinHttpAddRequestHeaders(request, test_headers[14], -1L, 0); - ok(ret, "got %u\n", GetLastError()); + ok(ret, "got %lu\n", GetLastError()); index = 0; len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, - test_header_name2, buffer, &len, &index); - ok(ret, "got %u\n", GetLastError()); - ok(index == 1, "wrong index %u\n", index); - ok(!memcmp(buffer, value_nospace, sizeof(value_nospace)), "incorrect string\n"); + L"name", buffer, &len, &index); + ok(ret, "got %lu\n", GetLastError()); + ok(index == 1, "wrong index %lu\n", index); + ok(!memcmp(buffer, L"value", sizeof(L"value")), "incorrect string\n"); ret = WinHttpCloseHandle(request); ok(ret == TRUE, "WinHttpCloseHandle failed on closing request, got %d.\n", ret); @@ -1055,30 +1068,37 @@ static void test_secure_connection(void) WINHTTP_CERTIFICATE_INFO info; char buffer[32]; - ses = WinHttpOpen(test_useragent, 0, NULL, NULL, 0); - ok(ses != NULL, "failed to open session %u\n", GetLastError()); + ses = WinHttpOpen(L"winetest", 0, NULL, NULL, 0); + ok(ses != NULL, "failed to open session %lu\n", GetLastError()); policy = WINHTTP_OPTION_REDIRECT_POLICY_ALWAYS; ret = WinHttpSetOption(ses, WINHTTP_OPTION_REDIRECT_POLICY, &policy, sizeof(policy)); - ok(ret, "failed to set redirect policy %u\n", GetLastError()); + ok(ret, "failed to set redirect policy %lu\n", GetLastError()); protocols = WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2; ret = WinHttpSetOption(ses, WINHTTP_OPTION_SECURE_PROTOCOLS, &protocols, sizeof(protocols)); err = GetLastError(); - ok(ret || err == ERROR_INVALID_PARAMETER /* < win7 */, "failed to set protocols %u\n", err); + ok(ret || err == ERROR_INVALID_PARAMETER /* < win7 */, "failed to set protocols %lu\n", err); - con = WinHttpConnect(ses, test_winehq, 443, 0); - ok(con != NULL, "failed to open a connection %u\n", GetLastError()); + con = WinHttpConnect(ses, L"test.winehq.org", 443, 0); + ok(con != NULL, "failed to open a connection %lu\n", GetLastError()); + + SetLastError( 0xdeadbeef ); + protocols = WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2; + ret = WinHttpSetOption(con, WINHTTP_OPTION_SECURE_PROTOCOLS, &protocols, sizeof(protocols)); + err = GetLastError(); + ok(!ret, "unexpected success\n"); + ok(err == ERROR_WINHTTP_INCORRECT_HANDLE_TYPE, "got %lu\n", err); /* try without setting WINHTTP_FLAG_SECURE */ req = WinHttpOpenRequest(con, NULL, NULL, NULL, NULL, NULL, 0); - ok(req != NULL, "failed to open a request %u\n", GetLastError()); + ok(req != NULL, "failed to open a request %lu\n", GetLastError()); ret = WinHttpSetOption(req, WINHTTP_OPTION_CLIENT_CERT_CONTEXT, WINHTTP_NO_CLIENT_CERT_CONTEXT, 0); err = GetLastError(); ok(!ret, "unexpected success\n"); ok(err == ERROR_WINHTTP_INCORRECT_HANDLE_STATE || broken(err == ERROR_INVALID_PARAMETER) /* winxp */, - "setting client cert context returned %u\n", err); + "setting client cert context returned %lu\n", err); ret = WinHttpSendRequest(req, NULL, 0, NULL, 0, 0, 0); err = GetLastError(); @@ -1087,31 +1107,31 @@ static void test_secure_connection(void) skip("Connection failed, skipping.\n"); goto cleanup; } - ok(ret, "failed to send request %u\n", GetLastError()); + ok(ret, "failed to send request %lu\n", GetLastError()); ret = WinHttpReceiveResponse(req, NULL); - ok(ret, "failed to receive response %u\n", GetLastError()); + ok(ret, "failed to receive response %lu\n", GetLastError()); status = 0xdeadbeef; size = sizeof(status); ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL); - ok(ret, "header query failed %u\n", GetLastError()); - ok(status == HTTP_STATUS_BAD_REQUEST, "got %u\n", status); + ok(ret, "header query failed %lu\n", GetLastError()); + ok(status == HTTP_STATUS_BAD_REQUEST, "got %lu\n", status); WinHttpCloseHandle(req); req = WinHttpOpenRequest(con, NULL, NULL, NULL, NULL, NULL, WINHTTP_FLAG_SECURE); - ok(req != NULL, "failed to open a request %u\n", GetLastError()); + ok(req != NULL, "failed to open a request %lu\n", GetLastError()); flags = 0xdeadbeef; size = sizeof(flags); ret = WinHttpQueryOption(req, WINHTTP_OPTION_SECURITY_FLAGS, &flags, &size); - ok(ret, "failed to query security flags %u\n", GetLastError()); - ok(!flags, "got %08x\n", flags); + ok(ret, "failed to query security flags %lu\n", GetLastError()); + ok(!flags, "got %#lx\n", flags); flags = SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE; ret = WinHttpSetOption(req, WINHTTP_OPTION_SECURITY_FLAGS, &flags, sizeof(flags)); - ok(ret, "failed to set security flags %u\n", GetLastError()); + ok(ret, "failed to set security flags %lu\n", GetLastError()); flags = SECURITY_FLAG_SECURE; ret = WinHttpSetOption(req, WINHTTP_OPTION_SECURITY_FLAGS, &flags, sizeof(flags)); @@ -1124,15 +1144,15 @@ static void test_secure_connection(void) flags = SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID | SECURITY_FLAG_IGNORE_CERT_CN_INVALID; ret = WinHttpSetOption(req, WINHTTP_OPTION_SECURITY_FLAGS, &flags, sizeof(flags)); - ok(ret, "failed to set security flags %u\n", GetLastError()); + ok(ret, "failed to set security flags %lu\n", GetLastError()); flags = 0; ret = WinHttpSetOption(req, WINHTTP_OPTION_SECURITY_FLAGS, &flags, sizeof(flags)); - ok(ret, "failed to set security flags %u\n", GetLastError()); + ok(ret, "failed to set security flags %lu\n", GetLastError()); ret = WinHttpSetOption(req, WINHTTP_OPTION_CLIENT_CERT_CONTEXT, WINHTTP_NO_CLIENT_CERT_CONTEXT, 0); err = GetLastError(); - ok(ret || broken(!ret && err == ERROR_INVALID_PARAMETER) /* winxp */, "failed to set client cert context %u\n", err); + ok(ret || broken(!ret && err == ERROR_INVALID_PARAMETER) /* winxp */, "failed to set client cert context %lu\n", err); WinHttpSetStatusCallback(req, cert_error, WINHTTP_CALLBACK_STATUS_SECURE_FAILURE, 0); @@ -1144,20 +1164,20 @@ static void test_secure_connection(void) skip("secure connection failed, skipping remaining secure tests\n"); goto cleanup; } - ok(ret, "failed to send request %u\n", GetLastError()); + ok(ret, "failed to send request %lu\n", GetLastError()); size = sizeof(cert); ret = WinHttpQueryOption(req, WINHTTP_OPTION_SERVER_CERT_CONTEXT, &cert, &size ); - ok(ret, "failed to retrieve certificate context %u\n", GetLastError()); + ok(ret, "failed to retrieve certificate context %lu\n", GetLastError()); if (ret) CertFreeCertificateContext(cert); size = sizeof(bitness); ret = WinHttpQueryOption(req, WINHTTP_OPTION_SECURITY_KEY_BITNESS, &bitness, &size ); - ok(ret, "failed to retrieve key bitness %u\n", GetLastError()); + ok(ret, "failed to retrieve key bitness %lu\n", GetLastError()); size = sizeof(info); ret = WinHttpQueryOption(req, WINHTTP_OPTION_SECURITY_CERTIFICATE_STRUCT, &info, &size ); - ok(ret, "failed to retrieve certificate info %u\n", GetLastError()); + ok(ret, "failed to retrieve certificate info %lu\n", GetLastError()); if (ret) { @@ -1166,7 +1186,7 @@ static void test_secure_connection(void) trace("lpszProtocolName %s\n", wine_dbgstr_w(info.lpszProtocolName)); trace("lpszSignatureAlgName %s\n", wine_dbgstr_w(info.lpszSignatureAlgName)); trace("lpszEncryptionAlgName %s\n", wine_dbgstr_w(info.lpszEncryptionAlgName)); - trace("dwKeySize %u\n", info.dwKeySize); + trace("dwKeySize %lu\n", info.dwKeySize); LocalFree( info.lpszSubjectInfo ); LocalFree( info.lpszIssuerInfo ); } @@ -1177,18 +1197,18 @@ static void test_secure_connection(void) skip("connection error, skipping remaining secure tests\n"); goto cleanup; } - ok(ret, "failed to receive response %u\n", GetLastError()); + ok(ret, "failed to receive response %lu\n", GetLastError()); available_size = 0; ret = WinHttpQueryDataAvailable(req, &available_size); - ok(ret, "failed to query available data %u\n", GetLastError()); - ok(available_size > 2014, "available_size = %u\n", available_size); + ok(ret, "failed to query available data %lu\n", GetLastError()); + ok(available_size > 2014, "available_size = %lu\n", available_size); status = 0xdeadbeef; size = sizeof(status); ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL); - ok(ret, "failed unexpectedly %u\n", GetLastError()); - ok(status == HTTP_STATUS_OK, "request failed unexpectedly %u\n", status); + ok(ret, "failed unexpectedly %lu\n", GetLastError()); + ok(status == HTTP_STATUS_OK, "request failed unexpectedly %lu\n", status); size = 0; ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_RAW_HEADERS_CRLF, NULL, NULL, &size, NULL); @@ -1199,18 +1219,18 @@ static void test_secure_connection(void) { size = 0; ret = WinHttpReadData(req, buffer, sizeof(buffer), &size); - ok(ret == TRUE, "WinHttpReadData failed: %u.\n", GetLastError()); + ok(ret == TRUE, "WinHttpReadData failed: %lu\n", GetLastError()); if (!size) break; read_size += size; if (read_size <= 32) ok(!memcmp(buffer, data_start, sizeof(data_start)-1), "not expected: %.32s\n", buffer); } - ok(read_size >= available_size, "read_size = %u, available_size = %u\n", read_size, available_size); + ok(read_size >= available_size, "read_size = %lu, available_size = %lu\n", read_size, available_size); size = sizeof(cert); ret = WinHttpQueryOption(req, WINHTTP_OPTION_SERVER_CERT_CONTEXT, &cert, &size); - ok(ret, "failed to retrieve certificate context %u\n", GetLastError()); + ok(ret, "failed to retrieve certificate context %lu\n", GetLastError()); if (ret) CertFreeCertificateContext(cert); cleanup: @@ -1221,20 +1241,19 @@ cleanup: static void test_request_parameter_defaults(void) { - static const WCHAR empty[] = {0}; HINTERNET ses, con, req; DWORD size, status, error; WCHAR *version; BOOL ret; - ses = WinHttpOpen(test_useragent, 0, NULL, NULL, 0); - ok(ses != NULL, "failed to open session %u\n", GetLastError()); + ses = WinHttpOpen(L"winetest", 0, NULL, NULL, 0); + ok(ses != NULL, "failed to open session %lu\n", GetLastError()); - con = WinHttpConnect(ses, test_winehq, 0, 0); - ok(con != NULL, "failed to open a connection %u\n", GetLastError()); + con = WinHttpConnect(ses, L"test.winehq.org", 0, 0); + ok(con != NULL, "failed to open a connection %lu\n", GetLastError()); req = WinHttpOpenRequest(con, NULL, NULL, NULL, NULL, NULL, 0); - ok(req != NULL, "failed to open a request %u\n", GetLastError()); + ok(req != NULL, "failed to open a request %lu\n", GetLastError()); ret = WinHttpSendRequest(req, NULL, 0, NULL, 0, 0, 0); error = GetLastError(); @@ -1243,21 +1262,21 @@ static void test_request_parameter_defaults(void) skip("connection failed, skipping\n"); goto done; } - ok(ret, "failed to send request %u\n", GetLastError()); + ok(ret, "failed to send request %lu\n", GetLastError()); ret = WinHttpReceiveResponse(req, NULL); - ok(ret, "failed to receive response %u\n", GetLastError()); + ok(ret, "failed to receive response %lu\n", GetLastError()); status = 0xdeadbeef; size = sizeof(status); ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL); - ok(ret, "failed unexpectedly %u\n", GetLastError()); - ok(status == HTTP_STATUS_OK, "request failed unexpectedly %u\n", status); + ok(ret, "failed unexpectedly %lu\n", GetLastError()); + ok(status == HTTP_STATUS_OK, "request failed unexpectedly %lu\n", status); WinHttpCloseHandle(req); - req = WinHttpOpenRequest(con, empty, empty, empty, NULL, NULL, 0); - ok(req != NULL, "failed to open a request %u\n", GetLastError()); + req = WinHttpOpenRequest(con, L"", L"", L"", NULL, NULL, 0); + ok(req != NULL, "failed to open a request %lu\n", GetLastError()); ret = WinHttpSendRequest(req, NULL, 0, NULL, 0, 0, 0); error = GetLastError(); @@ -1266,29 +1285,29 @@ static void test_request_parameter_defaults(void) skip("connection failed, skipping\n"); goto done; } - ok(ret, "failed to send request %u\n", GetLastError()); + ok(ret, "failed to send request %lu\n", GetLastError()); ret = WinHttpReceiveResponse(req, NULL); - ok(ret, "failed to receive response %u\n", GetLastError()); + ok(ret, "failed to receive response %lu\n", GetLastError()); size = 0; SetLastError(0xdeadbeef); ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_VERSION, NULL, NULL, &size, NULL); error = GetLastError(); ok(!ret, "succeeded unexpectedly\n"); - ok(error == ERROR_INSUFFICIENT_BUFFER, "expected ERROR_INSUFFICIENT_BUFFER, got %u\n", error); + ok(error == ERROR_INSUFFICIENT_BUFFER, "expected ERROR_INSUFFICIENT_BUFFER, got %lu\n", error); version = HeapAlloc(GetProcessHeap(), 0, size); ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_VERSION, NULL, version, &size, NULL); - ok(ret, "failed unexpectedly %u\n", GetLastError()); - ok(lstrlenW(version) == size / sizeof(WCHAR), "unexpected size %u\n", size); + ok(ret, "failed unexpectedly %lu\n", GetLastError()); + ok(lstrlenW(version) == size / sizeof(WCHAR), "unexpected size %lu\n", size); HeapFree(GetProcessHeap(), 0, version); status = 0xdeadbeef; size = sizeof(status); ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL); - ok(ret, "failed unexpectedly %u\n", GetLastError()); - ok(status == HTTP_STATUS_OK, "request failed unexpectedly %u\n", status); + ok(ret, "failed unexpectedly %lu\n", GetLastError()); + ok(status == HTTP_STATUS_OK, "request failed unexpectedly %lu\n", status); done: WinHttpCloseHandle(req); @@ -1394,7 +1413,7 @@ static void test_set_default_proxy_config(void) SetLastError(0xdeadbeef); ret = WinHttpSetDefaultProxyConfiguration(NULL); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, - "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "expected ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); } /* test with invalid access type */ @@ -1403,7 +1422,7 @@ static void test_set_default_proxy_config(void) SetLastError(0xdeadbeef); ret = WinHttpSetDefaultProxyConfiguration(&info); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, - "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "expected ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); /* at a minimum, the proxy server must be set */ info.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY; @@ -1411,12 +1430,12 @@ static void test_set_default_proxy_config(void) SetLastError(0xdeadbeef); ret = WinHttpSetDefaultProxyConfiguration(&info); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, - "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "expected ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); info.lpszProxyBypass = normalString; SetLastError(0xdeadbeef); ret = WinHttpSetDefaultProxyConfiguration(&info); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, - "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "expected ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); /* the proxy server can't have wide characters */ info.lpszProxy = wideString; @@ -1427,7 +1446,7 @@ static void test_set_default_proxy_config(void) else ok((!ret && GetLastError() == ERROR_INVALID_PARAMETER) || broken(ret), /* Earlier winhttp versions on W2K/XP */ - "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "expected ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); info.lpszProxy = normalString; SetLastError(0xdeadbeef); @@ -1436,9 +1455,9 @@ static void test_set_default_proxy_config(void) skip("couldn't set default proxy configuration: access denied\n"); else { - ok(ret, "WinHttpSetDefaultProxyConfiguration failed: %u\n", GetLastError()); - ok(GetLastError() == ERROR_SUCCESS || broken(GetLastError() == 0xdeadbeef) /* < win7 */, - "got %u\n", GetLastError()); + ok(ret, "WinHttpSetDefaultProxyConfiguration failed: %lu\n", GetLastError()); + ok(GetLastError() == ERROR_SUCCESS || broken(GetLastError() == 0xdeadbeef) /* < win7 */, + "got %lu\n", GetLastError()); } set_default_proxy_reg_value( saved_proxy_settings, len, type ); } @@ -1449,489 +1468,489 @@ static void test_timeouts(void) DWORD value, size; HINTERNET ses, req, con; - ses = WinHttpOpen(test_useragent, 0, NULL, NULL, 0); - ok(ses != NULL, "failed to open session %u\n", GetLastError()); + ses = WinHttpOpen(L"winetest", 0, NULL, NULL, 0); + ok(ses != NULL, "failed to open session %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = WinHttpSetTimeouts(ses, -2, 0, 0, 0); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, - "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); + "expected ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = WinHttpSetTimeouts(ses, 0, -2, 0, 0); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, - "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); + "expected ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = WinHttpSetTimeouts(ses, 0, 0, -2, 0); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, - "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); + "expected ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = WinHttpSetTimeouts(ses, 0, 0, 0, -2); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, - "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); + "expected ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = WinHttpSetTimeouts(ses, -1, -1, -1, -1); - ok(ret, "%u\n", GetLastError()); + ok(ret, "%lu\n", GetLastError()); ok(GetLastError() == ERROR_SUCCESS || broken(GetLastError() == 0xdeadbeef) /* < win7 */, - "expected ERROR_SUCCESS, got %u\n", GetLastError()); + "expected ERROR_SUCCESS, got %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = WinHttpSetTimeouts(ses, 0, 0, 0, 0); - ok(ret, "%u\n", GetLastError()); + ok(ret, "%lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = WinHttpSetTimeouts(ses, 0x0123, 0x4567, 0x89ab, 0xcdef); - ok(ret, "%u\n", GetLastError()); + ok(ret, "%lu\n", GetLastError()); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(ses, WINHTTP_OPTION_RESOLVE_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0x0123, "Expected 0x0123, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0x0123, "Expected 0x0123, got %lu\n", value); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(ses, WINHTTP_OPTION_CONNECT_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0x4567, "Expected 0x4567, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0x4567, "Expected 0x4567, got %lu\n", value); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(ses, WINHTTP_OPTION_SEND_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0x89ab, "Expected 0x89ab, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0x89ab, "Expected 0x89ab, got %lu\n", value); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(ses, WINHTTP_OPTION_RECEIVE_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0xcdef, "Expected 0xcdef, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0xcdef, "Expected 0xcdef, got %lu\n", value); SetLastError(0xdeadbeef); value = 0; ret = WinHttpSetOption(ses, WINHTTP_OPTION_RESOLVE_TIMEOUT, &value, sizeof(value)); - ok(ret, "%u\n", GetLastError()); + ok(ret, "%lu\n", GetLastError()); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(ses, WINHTTP_OPTION_RESOLVE_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0, "Expected 0, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0, "Expected 0, got %lu\n", value); SetLastError(0xdeadbeef); value = 0; ret = WinHttpSetOption(ses, WINHTTP_OPTION_CONNECT_TIMEOUT, &value, sizeof(value)); - ok(ret, "%u\n", GetLastError()); + ok(ret, "%lu\n", GetLastError()); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(ses, WINHTTP_OPTION_CONNECT_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0, "Expected 0, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0, "Expected 0, got %lu\n", value); SetLastError(0xdeadbeef); value = 0; ret = WinHttpSetOption(ses, WINHTTP_OPTION_SEND_TIMEOUT, &value, sizeof(value)); - ok(ret, "%u\n", GetLastError()); + ok(ret, "%lu\n", GetLastError()); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(ses, WINHTTP_OPTION_SEND_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0, "Expected 0, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0, "Expected 0, got %lu\n", value); SetLastError(0xdeadbeef); value = 0; ret = WinHttpSetOption(ses, WINHTTP_OPTION_RECEIVE_TIMEOUT, &value, sizeof(value)); - ok(ret, "%u\n", GetLastError()); + ok(ret, "%lu\n", GetLastError()); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(ses, WINHTTP_OPTION_RECEIVE_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0, "Expected 0, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0, "Expected 0, got %lu\n", value); SetLastError(0xdeadbeef); value = 0xbeefdead; ret = WinHttpSetOption(ses, WINHTTP_OPTION_RESOLVE_TIMEOUT, &value, sizeof(value)); - ok(ret, "%u\n", GetLastError()); + ok(ret, "%lu\n", GetLastError()); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(ses, WINHTTP_OPTION_RESOLVE_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0xbeefdead, "Expected 0xbeefdead, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0xbeefdead, "Expected 0xbeefdead, got %lu\n", value); SetLastError(0xdeadbeef); value = 0xbeefdead; ret = WinHttpSetOption(ses, WINHTTP_OPTION_CONNECT_TIMEOUT, &value, sizeof(value)); - ok(ret, "%u\n", GetLastError()); + ok(ret, "%lu\n", GetLastError()); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(ses, WINHTTP_OPTION_CONNECT_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0xbeefdead, "Expected 0xbeefdead, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0xbeefdead, "Expected 0xbeefdead, got %lu\n", value); SetLastError(0xdeadbeef); value = 0xbeefdead; ret = WinHttpSetOption(ses, WINHTTP_OPTION_SEND_TIMEOUT, &value, sizeof(value)); - ok(ret, "%u\n", GetLastError()); + ok(ret, "%lu\n", GetLastError()); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(ses, WINHTTP_OPTION_SEND_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0xbeefdead, "Expected 0xbeefdead, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0xbeefdead, "Expected 0xbeefdead, got %lu\n", value); SetLastError(0xdeadbeef); value = 0xbeefdead; ret = WinHttpSetOption(ses, WINHTTP_OPTION_RECEIVE_TIMEOUT, &value, sizeof(value)); - ok(ret, "%u\n", GetLastError()); + ok(ret, "%lu\n", GetLastError()); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(ses, WINHTTP_OPTION_RECEIVE_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0xbeefdead, "Expected 0xbeefdead, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0xbeefdead, "Expected 0xbeefdead, got %lu\n", value); - con = WinHttpConnect(ses, test_winehq, 0, 0); - ok(con != NULL, "failed to open a connection %u\n", GetLastError()); + con = WinHttpConnect(ses, L"test.winehq.org", 0, 0); + ok(con != NULL, "failed to open a connection %lu\n", GetLastError()); /* Timeout values should match the last one set for session */ SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(con, WINHTTP_OPTION_RESOLVE_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0xbeefdead, "Expected 0xbeefdead, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0xbeefdead, "Expected 0xbeefdead, got %lu\n", value); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(con, WINHTTP_OPTION_CONNECT_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0xbeefdead, "Expected 0xbeefdead, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0xbeefdead, "Expected 0xbeefdead, got %lu\n", value); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(con, WINHTTP_OPTION_SEND_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0xbeefdead, "Expected 0xbeefdead, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0xbeefdead, "Expected 0xbeefdead, got %lu\n", value); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(con, WINHTTP_OPTION_RECEIVE_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0xbeefdead, "Expected 0xbeefdead, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0xbeefdead, "Expected 0xbeefdead, got %lu\n", value); SetLastError(0xdeadbeef); ret = WinHttpSetTimeouts(con, -2, 0, 0, 0); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, - "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); + "expected ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = WinHttpSetTimeouts(con, 0, -2, 0, 0); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, - "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); + "expected ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = WinHttpSetTimeouts(con, 0, 0, -2, 0); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, - "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); + "expected ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = WinHttpSetTimeouts(con, 0, 0, 0, -2); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, - "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); + "expected ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = WinHttpSetTimeouts(con, -1, -1, -1, -1); ok(!ret && GetLastError() == ERROR_WINHTTP_INCORRECT_HANDLE_TYPE, - "expected ERROR_WINHTTP_INVALID_TYPE, got %u\n", GetLastError()); + "expected ERROR_WINHTTP_INVALID_TYPE, got %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = WinHttpSetTimeouts(con, 0, 0, 0, 0); ok(!ret && GetLastError() == ERROR_WINHTTP_INCORRECT_HANDLE_TYPE, - "expected ERROR_WINHTTP_INVALID_TYPE, got %u\n", GetLastError()); + "expected ERROR_WINHTTP_INVALID_TYPE, got %lu\n", GetLastError()); SetLastError(0xdeadbeef); value = 0; ret = WinHttpSetOption(con, WINHTTP_OPTION_RESOLVE_TIMEOUT, &value, sizeof(value)); ok(!ret && GetLastError() == ERROR_WINHTTP_INCORRECT_HANDLE_TYPE, - "expected ERROR_WINHTTP_INVALID_TYPE, got %u\n", GetLastError()); + "expected ERROR_WINHTTP_INVALID_TYPE, got %lu\n", GetLastError()); SetLastError(0xdeadbeef); value = 0; ret = WinHttpSetOption(con, WINHTTP_OPTION_CONNECT_TIMEOUT, &value, sizeof(value)); ok(!ret && GetLastError() == ERROR_WINHTTP_INCORRECT_HANDLE_TYPE, - "expected ERROR_WINHTTP_INVALID_TYPE, got %u\n", GetLastError()); + "expected ERROR_WINHTTP_INVALID_TYPE, got %lu\n", GetLastError()); SetLastError(0xdeadbeef); value = 0; ret = WinHttpSetOption(con, WINHTTP_OPTION_SEND_TIMEOUT, &value, sizeof(value)); ok(!ret && GetLastError() == ERROR_WINHTTP_INCORRECT_HANDLE_TYPE, - "expected ERROR_WINHTTP_INVALID_TYPE, got %u\n", GetLastError()); + "expected ERROR_WINHTTP_INVALID_TYPE, got %lu\n", GetLastError()); SetLastError(0xdeadbeef); value = 0; ret = WinHttpSetOption(con, WINHTTP_OPTION_RECEIVE_TIMEOUT, &value, sizeof(value)); ok(!ret && GetLastError() == ERROR_WINHTTP_INCORRECT_HANDLE_TYPE, - "expected ERROR_WINHTTP_INVALID_TYPE, got %u\n", GetLastError()); + "expected ERROR_WINHTTP_INVALID_TYPE, got %lu\n", GetLastError()); /* Changing timeout values for session should affect the values for connection */ SetLastError(0xdeadbeef); value = 0xdead; ret = WinHttpSetOption(ses, WINHTTP_OPTION_RESOLVE_TIMEOUT, &value, sizeof(value)); - ok(ret, "%u\n", GetLastError()); + ok(ret, "%lu\n", GetLastError()); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(con, WINHTTP_OPTION_RESOLVE_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0xdead, "Expected 0xdead, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0xdead, "Expected 0xdead, got %lu\n", value); SetLastError(0xdeadbeef); value = 0xdead; ret = WinHttpSetOption(ses, WINHTTP_OPTION_CONNECT_TIMEOUT, &value, sizeof(value)); - ok(ret, "%u\n", GetLastError()); + ok(ret, "%lu\n", GetLastError()); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(con, WINHTTP_OPTION_CONNECT_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0xdead, "Expected 0xdead, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0xdead, "Expected 0xdead, got %lu\n", value); SetLastError(0xdeadbeef); value = 0xdead; ret = WinHttpSetOption(ses, WINHTTP_OPTION_SEND_TIMEOUT, &value, sizeof(value)); - ok(ret, "%u\n", GetLastError()); + ok(ret, "%lu\n", GetLastError()); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(con, WINHTTP_OPTION_SEND_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0xdead, "Expected 0xdead, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0xdead, "Expected 0xdead, got %lu\n", value); SetLastError(0xdeadbeef); value = 0xdead; ret = WinHttpSetOption(ses, WINHTTP_OPTION_RECEIVE_TIMEOUT, &value, sizeof(value)); - ok(ret, "%u\n", GetLastError()); + ok(ret, "%lu\n", GetLastError()); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(con, WINHTTP_OPTION_RECEIVE_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0xdead, "Expected 0xdead, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0xdead, "Expected 0xdead, got %lu\n", value); req = WinHttpOpenRequest(con, NULL, NULL, NULL, NULL, NULL, 0); - ok(req != NULL, "failed to open a request %u\n", GetLastError()); + ok(req != NULL, "failed to open a request %lu\n", GetLastError()); /* Timeout values should match the last one set for session */ SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(req, WINHTTP_OPTION_RESOLVE_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0xdead, "Expected 0xdead, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0xdead, "Expected 0xdead, got %lu\n", value); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(req, WINHTTP_OPTION_CONNECT_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0xdead, "Expected 0xdead, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0xdead, "Expected 0xdead, got %lu\n", value); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(req, WINHTTP_OPTION_SEND_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0xdead, "Expected 0xdead, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0xdead, "Expected 0xdead, got %lu\n", value); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(req, WINHTTP_OPTION_RECEIVE_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0xdead, "Expected 0xdead, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0xdead, "Expected 0xdead, got %lu\n", value); SetLastError(0xdeadbeef); ret = WinHttpSetTimeouts(req, -2, 0, 0, 0); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, - "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); + "expected ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = WinHttpSetTimeouts(req, 0, -2, 0, 0); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, - "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); + "expected ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = WinHttpSetTimeouts(req, 0, 0, -2, 0); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, - "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); + "expected ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = WinHttpSetTimeouts(req, 0, 0, 0, -2); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, - "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); + "expected ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = WinHttpSetTimeouts(req, -1, -1, -1, -1); - ok(ret, "%u\n", GetLastError()); + ok(ret, "%lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = WinHttpSetTimeouts(req, 0, 0, 0, 0); - ok(ret, "%u\n", GetLastError()); + ok(ret, "%lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = WinHttpSetTimeouts(req, 0xcdef, 0x89ab, 0x4567, 0x0123); - ok(ret, "%u\n", GetLastError()); + ok(ret, "%lu\n", GetLastError()); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(req, WINHTTP_OPTION_RESOLVE_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0xcdef, "Expected 0xcdef, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0xcdef, "Expected 0xcdef, got %lu\n", value); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(req, WINHTTP_OPTION_CONNECT_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0x89ab, "Expected 0x89ab, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0x89ab, "Expected 0x89ab, got %lu\n", value); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(req, WINHTTP_OPTION_SEND_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0x4567, "Expected 0x4567, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0x4567, "Expected 0x4567, got %lu\n", value); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(req, WINHTTP_OPTION_RECEIVE_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0x0123, "Expected 0x0123, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0x0123, "Expected 0x0123, got %lu\n", value); SetLastError(0xdeadbeef); value = 0; ret = WinHttpSetOption(req, WINHTTP_OPTION_RESOLVE_TIMEOUT, &value, sizeof(value)); - ok(ret, "%u\n", GetLastError()); + ok(ret, "%lu\n", GetLastError()); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(req, WINHTTP_OPTION_RESOLVE_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0, "Expected 0, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0, "Expected 0, got %lu\n", value); SetLastError(0xdeadbeef); value = 0; ret = WinHttpSetOption(req, WINHTTP_OPTION_CONNECT_TIMEOUT, &value, sizeof(value)); - ok(ret, "%u\n", GetLastError()); + ok(ret, "%lu\n", GetLastError()); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(req, WINHTTP_OPTION_CONNECT_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0, "Expected 0, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0, "Expected 0, got %lu\n", value); SetLastError(0xdeadbeef); value = 0; ret = WinHttpSetOption(req, WINHTTP_OPTION_SEND_TIMEOUT, &value, sizeof(value)); - ok(ret, "%u\n", GetLastError()); + ok(ret, "%lu\n", GetLastError()); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(req, WINHTTP_OPTION_SEND_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0, "Expected 0, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0, "Expected 0, got %lu\n", value); SetLastError(0xdeadbeef); value = 0; ret = WinHttpSetOption(req, WINHTTP_OPTION_RECEIVE_TIMEOUT, &value, sizeof(value)); - ok(ret, "%u\n", GetLastError()); + ok(ret, "%lu\n", GetLastError()); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(req, WINHTTP_OPTION_RECEIVE_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0, "Expected 0, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0, "Expected 0, got %lu\n", value); SetLastError(0xdeadbeef); value = 0xbeefdead; ret = WinHttpSetOption(req, WINHTTP_OPTION_RESOLVE_TIMEOUT, &value, sizeof(value)); - ok(ret, "%u\n", GetLastError()); + ok(ret, "%lu\n", GetLastError()); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(req, WINHTTP_OPTION_RESOLVE_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0xbeefdead, "Expected 0xbeefdead, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0xbeefdead, "Expected 0xbeefdead, got %lu\n", value); SetLastError(0xdeadbeef); value = 0xbeefdead; ret = WinHttpSetOption(req, WINHTTP_OPTION_CONNECT_TIMEOUT, &value, sizeof(value)); - ok(ret, "%u\n", GetLastError()); + ok(ret, "%lu\n", GetLastError()); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(req, WINHTTP_OPTION_CONNECT_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0xbeefdead, "Expected 0xbeefdead, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0xbeefdead, "Expected 0xbeefdead, got %lu\n", value); SetLastError(0xdeadbeef); value = 0xbeefdead; ret = WinHttpSetOption(req, WINHTTP_OPTION_SEND_TIMEOUT, &value, sizeof(value)); - ok(ret, "%u\n", GetLastError()); + ok(ret, "%lu\n", GetLastError()); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(req, WINHTTP_OPTION_SEND_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0xbeefdead, "Expected 0xbeefdead, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0xbeefdead, "Expected 0xbeefdead, got %lu\n", value); SetLastError(0xdeadbeef); value = 0xbeefdead; ret = WinHttpSetOption(req, WINHTTP_OPTION_RECEIVE_TIMEOUT, &value, sizeof(value)); - ok(ret, "%u\n", GetLastError()); + ok(ret, "%lu\n", GetLastError()); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(req, WINHTTP_OPTION_RECEIVE_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0xbeefdead, "Expected 0xbeefdead, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0xbeefdead, "Expected 0xbeefdead, got %lu\n", value); /* Changing timeout values for session should not affect the values for a request, * neither should the other way around. @@ -1939,162 +1958,162 @@ static void test_timeouts(void) SetLastError(0xdeadbeef); value = 0xbeefdead; ret = WinHttpSetOption(req, WINHTTP_OPTION_RESOLVE_TIMEOUT, &value, sizeof(value)); - ok(ret, "%u\n", GetLastError()); + ok(ret, "%lu\n", GetLastError()); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(ses, WINHTTP_OPTION_RESOLVE_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0xdead, "Expected 0xdead, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0xdead, "Expected 0xdead, got %lu\n", value); SetLastError(0xdeadbeef); value = 0xbeefdead; ret = WinHttpSetOption(req, WINHTTP_OPTION_CONNECT_TIMEOUT, &value, sizeof(value)); - ok(ret, "%u\n", GetLastError()); + ok(ret, "%lu\n", GetLastError()); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(ses, WINHTTP_OPTION_CONNECT_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0xdead, "Expected 0xdead, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0xdead, "Expected 0xdead, got %lu\n", value); SetLastError(0xdeadbeef); value = 0xbeefdead; ret = WinHttpSetOption(req, WINHTTP_OPTION_SEND_TIMEOUT, &value, sizeof(value)); - ok(ret, "%u\n", GetLastError()); + ok(ret, "%lu\n", GetLastError()); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(ses, WINHTTP_OPTION_SEND_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0xdead, "Expected 0xdead, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0xdead, "Expected 0xdead, got %lu\n", value); SetLastError(0xdeadbeef); value = 0xbeefdead; ret = WinHttpSetOption(req, WINHTTP_OPTION_RECEIVE_TIMEOUT, &value, sizeof(value)); - ok(ret, "%u\n", GetLastError()); + ok(ret, "%lu\n", GetLastError()); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(ses, WINHTTP_OPTION_RECEIVE_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0xdead, "Expected 0xdead, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0xdead, "Expected 0xdead, got %lu\n", value); SetLastError(0xdeadbeef); value = 0xbeef; ret = WinHttpSetOption(ses, WINHTTP_OPTION_RESOLVE_TIMEOUT, &value, sizeof(value)); - ok(ret, "%u\n", GetLastError()); + ok(ret, "%lu\n", GetLastError()); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(req, WINHTTP_OPTION_RESOLVE_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0xbeefdead, "Expected 0xbeefdead, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0xbeefdead, "Expected 0xbeefdead, got %lu\n", value); SetLastError(0xdeadbeef); value = 0xbeef; ret = WinHttpSetOption(ses, WINHTTP_OPTION_CONNECT_TIMEOUT, &value, sizeof(value)); - ok(ret, "%u\n", GetLastError()); + ok(ret, "%lu\n", GetLastError()); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(req, WINHTTP_OPTION_CONNECT_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0xbeefdead, "Expected 0xbeefdead, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0xbeefdead, "Expected 0xbeefdead, got %lu\n", value); SetLastError(0xdeadbeef); value = 0xbeef; ret = WinHttpSetOption(ses, WINHTTP_OPTION_SEND_TIMEOUT, &value, sizeof(value)); - ok(ret, "%u\n", GetLastError()); + ok(ret, "%lu\n", GetLastError()); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(req, WINHTTP_OPTION_SEND_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0xbeefdead, "Expected 0xbeefdead, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0xbeefdead, "Expected 0xbeefdead, got %lu\n", value); SetLastError(0xdeadbeef); value = 0xbeef; ret = WinHttpSetOption(ses, WINHTTP_OPTION_RECEIVE_TIMEOUT, &value, sizeof(value)); - ok(ret, "%u\n", GetLastError()); + ok(ret, "%lu\n", GetLastError()); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(DWORD); ret = WinHttpQueryOption(req, WINHTTP_OPTION_RECEIVE_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 0xbeefdead, "Expected 0xbeefdead, got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 0xbeefdead, "Expected 0xbeefdead, got %lu\n", value); /* response timeout */ SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(value); ret = WinHttpQueryOption(req, WINHTTP_OPTION_RECEIVE_RESPONSE_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == ~0u, "got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == ~0u, "got %lu\n", value); SetLastError(0xdeadbeef); value = 30000; ret = WinHttpSetOption(req, WINHTTP_OPTION_RECEIVE_RESPONSE_TIMEOUT, &value, sizeof(value)); - ok(ret, "%u\n", GetLastError()); + ok(ret, "%lu\n", GetLastError()); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(value); ret = WinHttpQueryOption(req, WINHTTP_OPTION_RECEIVE_RESPONSE_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - todo_wine ok(value == 0xbeefdead, "got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + todo_wine ok(value == 0xbeefdead, "got %lu\n", value); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(value); ret = WinHttpQueryOption(con, WINHTTP_OPTION_RECEIVE_RESPONSE_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == ~0u, "got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == ~0u, "got %lu\n", value); SetLastError(0xdeadbeef); value = 30000; ret = WinHttpSetOption(con, WINHTTP_OPTION_RECEIVE_RESPONSE_TIMEOUT, &value, sizeof(value)); ok(!ret, "expected failure\n"); - ok(GetLastError() == ERROR_WINHTTP_INCORRECT_HANDLE_TYPE, "got %u\n", GetLastError()); + ok(GetLastError() == ERROR_WINHTTP_INCORRECT_HANDLE_TYPE, "got %lu\n", GetLastError()); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(value); ret = WinHttpQueryOption(ses, WINHTTP_OPTION_RECEIVE_RESPONSE_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == ~0u, "got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == ~0u, "got %lu\n", value); SetLastError(0xdeadbeef); value = 48878; ret = WinHttpSetOption(ses, WINHTTP_OPTION_RECEIVE_RESPONSE_TIMEOUT, &value, sizeof(value)); - ok(ret, "%u\n", GetLastError()); + ok(ret, "%lu\n", GetLastError()); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(value); ret = WinHttpQueryOption(ses, WINHTTP_OPTION_RECEIVE_RESPONSE_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - todo_wine ok(value == 48879, "got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + todo_wine ok(value == 48879, "got %lu\n", value); SetLastError(0xdeadbeef); value = 48880; ret = WinHttpSetOption(ses, WINHTTP_OPTION_RECEIVE_RESPONSE_TIMEOUT, &value, sizeof(value)); - ok(ret, "%u\n", GetLastError()); + ok(ret, "%lu\n", GetLastError()); SetLastError(0xdeadbeef); value = 0xdeadbeef; size = sizeof(value); ret = WinHttpQueryOption(ses, WINHTTP_OPTION_RECEIVE_RESPONSE_TIMEOUT, &value, &size); - ok(ret, "%u\n", GetLastError()); - ok(value == 48880, "got %u\n", value); + ok(ret, "%lu\n", GetLastError()); + ok(value == 48880, "got %lu\n", value); WinHttpCloseHandle(req); WinHttpCloseHandle(con); @@ -2103,26 +2122,24 @@ static void test_timeouts(void) static void test_resolve_timeout(void) { - static const WCHAR nxdomain[] = - {'n','x','d','o','m','a','i','n','.','w','i','n','e','h','q','.','o','r','g',0}; HINTERNET ses, con, req; DWORD timeout; BOOL ret; if (! proxy_active()) { - ses = WinHttpOpen(test_useragent, 0, NULL, NULL, 0); - ok(ses != NULL, "failed to open session %u\n", GetLastError()); + ses = WinHttpOpen(L"winetest", 0, NULL, NULL, 0); + ok(ses != NULL, "failed to open session %lu\n", GetLastError()); timeout = 10000; ret = WinHttpSetOption(ses, WINHTTP_OPTION_RESOLVE_TIMEOUT, &timeout, sizeof(timeout)); - ok(ret, "failed to set resolve timeout %u\n", GetLastError()); + ok(ret, "failed to set resolve timeout %lu\n", GetLastError()); - con = WinHttpConnect(ses, nxdomain, 0, 0); - ok(con != NULL, "failed to open a connection %u\n", GetLastError()); + con = WinHttpConnect(ses, L"nxdomain.winehq.org", 0, 0); + ok(con != NULL, "failed to open a connection %lu\n", GetLastError()); req = WinHttpOpenRequest(con, NULL, NULL, NULL, NULL, NULL, 0); - ok(req != NULL, "failed to open a request %u\n", GetLastError()); + ok(req != NULL, "failed to open a request %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = WinHttpSendRequest(req, NULL, 0, NULL, 0, 0, 0); @@ -2132,32 +2149,32 @@ static void test_resolve_timeout(void) goto done; } ok(GetLastError() == ERROR_WINHTTP_NAME_NOT_RESOLVED, - "expected ERROR_WINHTTP_NAME_NOT_RESOLVED got %u\n", GetLastError()); + "expected ERROR_WINHTTP_NAME_NOT_RESOLVED got %lu\n", GetLastError()); ret = WinHttpReceiveResponse( req, NULL ); ok( !ret && (GetLastError() == ERROR_WINHTTP_INCORRECT_HANDLE_STATE || GetLastError() == ERROR_WINHTTP_OPERATION_CANCELLED /* < win7 */), - "got %u\n", GetLastError() ); + "got %lu\n", GetLastError() ); WinHttpCloseHandle(req); WinHttpCloseHandle(con); WinHttpCloseHandle(ses); } else - skip("Skipping host resolution tests, host resolution preformed by proxy\n"); + skip("Skipping host resolution tests, host resolution performed by proxy\n"); - ses = WinHttpOpen(test_useragent, 0, NULL, NULL, 0); - ok(ses != NULL, "failed to open session %u\n", GetLastError()); + ses = WinHttpOpen(L"winetest", 0, NULL, NULL, 0); + ok(ses != NULL, "failed to open session %lu\n", GetLastError()); timeout = 10000; ret = WinHttpSetOption(ses, WINHTTP_OPTION_RESOLVE_TIMEOUT, &timeout, sizeof(timeout)); - ok(ret, "failed to set resolve timeout %u\n", GetLastError()); + ok(ret, "failed to set resolve timeout %lu\n", GetLastError()); - con = WinHttpConnect(ses, test_winehq, 0, 0); - ok(con != NULL, "failed to open a connection %u\n", GetLastError()); + con = WinHttpConnect(ses, L"test.winehq.org", 0, 0); + ok(con != NULL, "failed to open a connection %lu\n", GetLastError()); req = WinHttpOpenRequest(con, NULL, NULL, NULL, NULL, NULL, 0); - ok(req != NULL, "failed to open a request %u\n", GetLastError()); + ok(req != NULL, "failed to open a request %lu\n", GetLastError()); ret = WinHttpSendRequest(req, NULL, 0, NULL, 0, 0, 0); if (!ret && GetLastError() == ERROR_WINHTTP_CANNOT_CONNECT) @@ -2184,6 +2201,12 @@ static const char okmsg[] = "Server: winetest\r\n" "\r\n"; +static const char okmsg_length0[] = +"HTTP/1.1 200 OK\r\n" +"Server: winetest\r\n" +"Content-length: 0\r\n" +"\r\n"; + static const char notokmsg[] = "HTTP/1.1 400 Bad Request\r\n" "\r\n"; @@ -2256,6 +2279,31 @@ static const char passportauth[] = "WWW-Authenticate: Passport1.4\r\n" "\r\n"; +static const char switchprotocols[] = +"HTTP/1.1 101 Switching Protocols\r\n" +"Server: winetest\r\n" +"Upgrade: websocket\r\n" +"Connection: Upgrade\r\n"; + +static const char redirectmsg[] = +"HTTP/1.1 307 Temporary Redirect\r\n" +"Content-Length: 0\r\n" +"Location: /temporary\r\n" +"Connection: close\r\n\r\n"; + +static const char badreplyheadermsg[] = +"HTTP/1.1 200 OK\r\n" +"Server: winetest\r\n" +"SpaceAfterHdr : bad\r\n" +"OkHdr: ok\r\n" +"\r\n"; + +static const char proxy_pac[] = +"function FindProxyForURL(url, host) {\r\n" +" url = url.replace(/[:/]/g, '_');\r\n" +" return 'PROXY ' + url + '_' + host + ':8080';\r\n" +"}\r\n\r\n"; + static const char unauthorized[] = "Unauthorized"; static const char hello_world[] = "Hello World"; static const char auth_unseen[] = "Auth Unseen"; @@ -2268,6 +2316,49 @@ struct server_info #define BIG_BUFFER_LEN 0x2250 +static void create_websocket_accept(const char *key, char *buf, unsigned int buflen) +{ + HCRYPTPROV provider; + HCRYPTHASH hash; + BYTE sha1[20]; + char data[128]; + DWORD len; + + strcpy(data, key); + strcat(data, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); + + CryptAcquireContextW(&provider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); + CryptCreateHash(provider, CALG_SHA1, 0, 0, &hash); + CryptHashData(hash, (BYTE *)data, strlen(data), 0); + + len = sizeof(sha1); + CryptGetHashParam(hash, HP_HASHVAL, sha1, &len, 0); + CryptDestroyHash(hash); + CryptReleaseContext(provider, 0); + + buf[0] = 0; + len = buflen; + CryptBinaryToStringA( (BYTE *)sha1, sizeof(sha1), CRYPT_STRING_BASE64, buf, &len); +} + +static int server_receive_request(int c, char *buffer, size_t buffer_size) +{ + int i, r; + + memset(buffer, 0, buffer_size); + for(i = 0; i < buffer_size - 1; i++) + { + r = recv(c, &buffer[i], 1, 0); + if (r != 1) + break; + if (i < 4) continue; + if (buffer[i - 2] == '\n' && buffer[i] == '\n' && + buffer[i - 3] == '\r' && buffer[i - 1] == '\r') + break; + } + return r; +} + static DWORD CALLBACK server_thread(LPVOID param) { struct server_info *si = param; @@ -2301,18 +2392,7 @@ static DWORD CALLBACK server_thread(LPVOID param) do { if (c == -1) c = accept(s, NULL, NULL); - - memset(buffer, 0, sizeof buffer); - for(i = 0; i < sizeof buffer - 1; i++) - { - r = recv(c, &buffer[i], 1, 0); - if (r != 1) - break; - if (i < 4) continue; - if (buffer[i - 2] == '\n' && buffer[i] == '\n' && - buffer[i - 3] == '\r' && buffer[i - 1] == '\r') - break; - } + server_receive_request(c, buffer, sizeof(buffer)); if (strstr(buffer, "GET /basic")) { send(c, okmsg, sizeof okmsg - 1, 0); @@ -2444,12 +2524,97 @@ static DWORD CALLBACK server_thread(LPVOID param) { send(c, passportauth, sizeof(passportauth) - 1, 0); } + else if (strstr(buffer, "GET /websocket")) + { + char headers[256], key[32], accept[64]; + const char *pos = strstr(buffer, "Sec-WebSocket-Key: "); + if (pos && strstr(buffer, "Connection: Upgrade\r\n") && + (strstr(buffer, "Upgrade: websocket\r\n") || strstr(buffer, "Upgrade: Websocket\r\n")) && + strstr(buffer, "Host: ") && strstr(buffer, "Sec-WebSocket-Version: 13\r\n")) + { + memcpy(headers, switchprotocols, sizeof(switchprotocols)); + memcpy(key, pos + 19, 24); + key[24] = 0; + + create_websocket_accept(key, accept, sizeof(accept)); + + strcat(headers, "Sec-WebSocket-Accept: "); + strcat(headers, accept); + strcat(headers, "\r\n\r\n"); + + send(c, headers, strlen(headers), 0); + continue; + } + else send(c, notokmsg, sizeof(notokmsg) - 1, 0); + } + else if (strstr(buffer, "POST /redirect")) + { + send(c, redirectmsg, sizeof redirectmsg - 1, 0); + } + else if (strstr(buffer, "POST /temporary")) + { + char buf[32]; + recv(c, buf, sizeof(buf), 0); + send(c, okmsg, sizeof okmsg - 1, 0); + send(c, page1, sizeof page1 - 1, 0); + } if (strstr(buffer, "GET /quit")) { send(c, okmsg, sizeof okmsg - 1, 0); send(c, page1, sizeof page1 - 1, 0); last_request = 1; } + if (strstr(buffer, "POST /bad_headers")) + { + ok(!!strstr(buffer, "Content-Type: text/html\r\n"), "Header missing from request %s.\n", debugstr_a(buffer)); + ok(!!strstr(buffer, "Test1: Value1\r\n"), "Header missing from request %s.\n", debugstr_a(buffer)); + ok(!!strstr(buffer, "Test2: Value2\r\n"), "Header missing from request %s.\n", debugstr_a(buffer)); + ok(!!strstr(buffer, "Test3: Value3\r\n"), "Header missing from request %s.\n", debugstr_a(buffer)); + ok(!!strstr(buffer, "Test4: Value4\r\n"), "Header missing from request %s.\n", debugstr_a(buffer)); + ok(!!strstr(buffer, "Test5: Value5\r\n"), "Header missing from request %s.\n", debugstr_a(buffer)); + ok(!!strstr(buffer, "Test6: Value6\r\n"), "Header missing from request %s.\n", debugstr_a(buffer)); + ok(!!strstr(buffer, "Cookie: 111\r\n"), "Header missing from request %s.\n", debugstr_a(buffer)); + send(c, badreplyheadermsg, sizeof(badreplyheadermsg) - 1, 0); + } + if (strstr(buffer, "GET /proxy.pac")) + { + send(c, okmsg, sizeof(okmsg) - 1, 0); + send(c, proxy_pac, sizeof(proxy_pac) - 1, 0); + } + + if (strstr(buffer, "PUT /test") || strstr(buffer, "POST /test")) + { + if (strstr(buffer, "Transfer-Encoding: chunked\r\n")) + { + ok(!strstr(buffer, "Content-Length:"), "Unexpected Content-Length in request %s.\n", debugstr_a(buffer)); + r = recv(c, buffer, sizeof(buffer), 0); + ok(r == 4, "got %d.\n", r); + buffer[r] = 0; + ok(!strcmp(buffer, "post"), "got %s.\n", debugstr_a(buffer)); + } + else + { + ok(!!strstr(buffer, "Content-Length: 0\r\n"), "Header missing from request %s.\n", debugstr_a(buffer)); + } + send(c, okmsg, sizeof(okmsg) - 1, 0); + } + + if (strstr(buffer, "GET /cached")) + { + send(c, okmsg_length0, sizeof okmsg_length0 - 1, 0); + r = server_receive_request(c, buffer, sizeof(buffer)); + ok(r > 0, "got %d.\n", r); + ok(!!strstr(buffer, "GET /cached"), "request not found.\n"); + send(c, okmsg_length0, sizeof okmsg_length0 - 1, 0); + r = server_receive_request(c, buffer, sizeof(buffer)); + ok(!r, "got %d, buffer[0] %d.\n", r, buffer[0]); + } + if (strstr(buffer, "GET /notcached")) + { + send(c, okmsg, sizeof okmsg - 1, 0); + r = server_receive_request(c, buffer, sizeof(buffer)); + ok(!r, "got %d, buffer[0] %d.\n", r, buffer[0] ); + } shutdown(c, 2); closesocket(c); c = -1; @@ -2462,185 +2627,223 @@ static DWORD CALLBACK server_thread(LPVOID param) static void test_basic_request(int port, const WCHAR *verb, const WCHAR *path) { - static const WCHAR test_header_end_clrf[] = {'\r','\n','\r','\n',0}; - static const WCHAR test_header_end_raw[] = {0,0}; HINTERNET ses, con, req; char buffer[0x100]; WCHAR buffer2[0x100]; DWORD count, status, size, error, supported, first, target; BOOL ret; - ses = WinHttpOpen(test_useragent, WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0); - ok(ses != NULL, "failed to open session %u\n", GetLastError()); + ses = WinHttpOpen(L"winetest", WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0); + ok(ses != NULL, "failed to open session %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = WinHttpSetOption(ses, 0, buffer, sizeof(buffer)); - ok(!ret && GetLastError() == ERROR_WINHTTP_INVALID_OPTION, "got %u\n", GetLastError()); + ok(!ret && GetLastError() == ERROR_WINHTTP_INVALID_OPTION, "got %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = WinHttpQueryOption(ses, 0, buffer, &size); - ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %u\n", GetLastError()); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %lu\n", GetLastError()); - con = WinHttpConnect(ses, localhostW, port, 0); - ok(con != NULL, "failed to open a connection %u\n", GetLastError()); + con = WinHttpConnect(ses, L"localhost", port, 0); + ok(con != NULL, "failed to open a connection %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = WinHttpSetOption(con, 0, buffer, sizeof(buffer)); - todo_wine ok(!ret && GetLastError() == ERROR_WINHTTP_INVALID_OPTION, "got %u\n", GetLastError()); + todo_wine ok(!ret && GetLastError() == ERROR_WINHTTP_INVALID_OPTION, "got %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = WinHttpQueryOption(con, 0, buffer, &size); - ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %u\n", GetLastError()); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %lu\n", GetLastError()); req = WinHttpOpenRequest(con, verb, path, NULL, NULL, NULL, 0); - ok(req != NULL, "failed to open a request %u\n", GetLastError()); + ok(req != NULL, "failed to open a request %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = WinHttpSetOption(req, 0, buffer, sizeof(buffer)); - ok(!ret && GetLastError() == ERROR_WINHTTP_INVALID_OPTION, "got %u\n", GetLastError()); + ok(!ret && GetLastError() == ERROR_WINHTTP_INVALID_OPTION, "got %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = WinHttpQueryOption(req, 0, buffer, &size); - ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %u\n", GetLastError()); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %lu\n", GetLastError()); ret = WinHttpSendRequest(req, NULL, 0, NULL, 0, 0, 0); - ok(ret, "failed to send request %u\n", GetLastError()); + ok(ret, "failed to send request %lu\n", GetLastError()); ret = WinHttpReceiveResponse(req, NULL); - ok(ret, "failed to receive response %u\n", GetLastError()); + ok(ret, "failed to receive response %lu\n", GetLastError()); status = 0xdeadbeef; size = sizeof(status); ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL); - ok(ret, "failed to query status code %u\n", GetLastError()); - ok(status == HTTP_STATUS_OK, "request failed unexpectedly %u\n", status); + ok(ret, "failed to query status code %lu\n", GetLastError()); + ok(status == HTTP_STATUS_OK, "request failed unexpectedly %lu\n", status); supported = first = target = 0xdeadbeef; SetLastError(0xdeadbeef); ret = WinHttpQueryAuthSchemes(req, &supported, &first, &target); error = GetLastError(); ok(!ret, "unexpected success\n"); - ok(error == ERROR_INVALID_OPERATION, "expected ERROR_INVALID_OPERATION, got %u\n", error); - ok(supported == 0xdeadbeef, "got %x\n", supported); - ok(first == 0xdeadbeef, "got %x\n", first); - ok(target == 0xdeadbeef, "got %x\n", target); + ok(error == ERROR_INVALID_OPERATION, "expected ERROR_INVALID_OPERATION, got %lu\n", error); + ok(supported == 0xdeadbeef, "got %lu\n", supported); + ok(first == 0xdeadbeef, "got %lu\n", first); + ok(target == 0xdeadbeef, "got %lu\n", target); size = sizeof(buffer2); memset(buffer2, 0, sizeof(buffer2)); ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_RAW_HEADERS_CRLF, NULL, buffer2, &size, NULL); - ok(ret, "failed to query for raw headers: %u\n", GetLastError()); - ok(!memcmp(buffer2 + lstrlenW(buffer2) - 4, test_header_end_clrf, sizeof(test_header_end_clrf)), + ok(ret, "failed to query for raw headers: %lu\n", GetLastError()); + ok(!memcmp(buffer2 + lstrlenW(buffer2) - 4, L"\r\n\r\n", sizeof(L"\r\n\r\n")), "WinHttpQueryHeaders returned invalid end of header string\n"); size = sizeof(buffer2); memset(buffer2, 0, sizeof(buffer2)); ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_RAW_HEADERS, NULL, buffer2, &size, NULL); - ok(ret, "failed to query for raw headers: %u\n", GetLastError()); - ok(!memcmp(buffer2 + (size / sizeof(WCHAR)) - 1, test_header_end_raw, sizeof(test_header_end_raw)), + ok(ret, "failed to query for raw headers: %lu\n", GetLastError()); + ok(!memcmp(buffer2 + (size / sizeof(WCHAR)) - 1, L"", sizeof(L"")), "WinHttpQueryHeaders returned invalid end of header string\n"); ok(buffer2[(size / sizeof(WCHAR)) - 2] != 0, "returned string has too many NULL characters\n"); count = 0; memset(buffer, 0, sizeof(buffer)); ret = WinHttpReadData(req, buffer, sizeof buffer, &count); - ok(ret, "failed to read data %u\n", GetLastError()); - ok(count == sizeof page1 - 1, "count was wrong\n"); - ok(!memcmp(buffer, page1, sizeof page1), "http data wrong\n"); + ok(ret, "failed to read data %lu\n", GetLastError()); + if (verb && !wcscmp(verb, L"PUT")) + { + ok(!count, "got count %ld\n", count); + } + else + { + ok(count == sizeof page1 - 1, "got count %ld\n", count); + ok(!memcmp(buffer, page1, sizeof page1), "http data wrong\n"); + } WinHttpCloseHandle(req); WinHttpCloseHandle(con); WinHttpCloseHandle(ses); } +static void test_chunked_request(int port) +{ + static const WCHAR *methods[] = {L"POST", L"PUT"}; + HINTERNET ses, con, req; + char buffer[0x100]; + unsigned int i; + DWORD count; + BOOL ret; + + ses = WinHttpOpen(L"winetest", WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0); + ok(ses != NULL, "failed to open session %lu\n", GetLastError()); + + con = WinHttpConnect(ses, L"localhost", port, 0); + ok(con != NULL, "failed to open a connection %lu\n", GetLastError()); + for (i = 0; i < ARRAY_SIZE(methods); ++i) + { + req = WinHttpOpenRequest(con, methods[i], L"/test", NULL, NULL, NULL, 0); + ok(req != NULL, "failed to open a request %lu\n", GetLastError()); + + ret = WinHttpAddRequestHeaders(req, L"Transfer-Encoding: chunked", -1, WINHTTP_ADDREQ_FLAG_ADD); + ok(ret, "failed to add header %lu\n", GetLastError()); + + strcpy(buffer, "post"); + ret = WinHttpSendRequest(req, NULL, 0, buffer, 4, 4, 0); + ok(ret, "failed to send request %lu\n", GetLastError()); + ret = WinHttpReceiveResponse(req, NULL); + ok(ret, "failed to receive response %lu\n", GetLastError()); + count = 0; + memset(buffer, 0, sizeof(buffer)); + ret = WinHttpReadData(req, buffer, sizeof buffer, &count); + ok(ret, "failed to read data %lu\n", GetLastError()); + ok(!count, "got count %ld\n", count); + WinHttpCloseHandle(req); + } + WinHttpCloseHandle(con); + WinHttpCloseHandle(ses); +} + static void test_basic_authentication(int port) { - static const WCHAR authW[] = {'/','a','u','t','h',0}; - static const WCHAR auth_with_credsW[] = {'/','a','u','t','h','_','w','i','t','h','_','c','r','e','d','s',0}; - static WCHAR userW[] = {'u','s','e','r',0}; - static WCHAR passW[] = {'p','w','d',0}; - static WCHAR pass2W[] = {'p','w','d','2',0}; HINTERNET ses, con, req; DWORD status, size, error, supported, first, target; char buffer[32]; BOOL ret; - ses = WinHttpOpen(test_useragent, WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0); - ok(ses != NULL, "failed to open session %u\n", GetLastError()); + ses = WinHttpOpen(L"winetest", WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0); + ok(ses != NULL, "failed to open session %lu\n", GetLastError()); - con = WinHttpConnect(ses, localhostW, port, 0); - ok(con != NULL, "failed to open a connection %u\n", GetLastError()); + con = WinHttpConnect(ses, L"localhost", port, 0); + ok(con != NULL, "failed to open a connection %lu\n", GetLastError()); - req = WinHttpOpenRequest(con, NULL, authW, NULL, NULL, NULL, 0); - ok(req != NULL, "failed to open a request %u\n", GetLastError()); + req = WinHttpOpenRequest(con, NULL, L"/auth", NULL, NULL, NULL, 0); + ok(req != NULL, "failed to open a request %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = WinHttpQueryAuthSchemes(NULL, NULL, NULL, NULL); error = GetLastError(); ok(!ret, "expected failure\n"); - ok(error == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %u\n", error); + ok(error == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %lu\n", error); SetLastError(0xdeadbeef); ret = WinHttpQueryAuthSchemes(req, NULL, NULL, NULL); error = GetLastError(); ok(!ret, "expected failure\n"); - ok(error == ERROR_INVALID_PARAMETER || error == ERROR_INVALID_OPERATION, "got %u\n", error); + ok(error == ERROR_INVALID_PARAMETER || error == ERROR_INVALID_OPERATION, "got %lu\n", error); supported = 0xdeadbeef; SetLastError(0xdeadbeef); ret = WinHttpQueryAuthSchemes(req, &supported, NULL, NULL); error = GetLastError(); ok(!ret, "expected failure\n"); - ok(error == ERROR_INVALID_PARAMETER || error == ERROR_INVALID_OPERATION, "got %u\n", error); - ok(supported == 0xdeadbeef, "got %x\n", supported); + ok(error == ERROR_INVALID_PARAMETER || error == ERROR_INVALID_OPERATION, "got %lu\n", error); + ok(supported == 0xdeadbeef, "got %lu\n", supported); supported = first = 0xdeadbeef; SetLastError(0xdeadbeef); ret = WinHttpQueryAuthSchemes(req, &supported, &first, NULL); error = GetLastError(); ok(!ret, "expected failure\n"); - ok(error == ERROR_INVALID_PARAMETER || error == ERROR_INVALID_OPERATION, "got %u\n", error); - ok(supported == 0xdeadbeef, "got %x\n", supported); - ok(first == 0xdeadbeef, "got %x\n", first); + ok(error == ERROR_INVALID_PARAMETER || error == ERROR_INVALID_OPERATION, "got %lu\n", error); + ok(supported == 0xdeadbeef, "got %lu\n", supported); + ok(first == 0xdeadbeef, "got %lu\n", first); supported = first = target = 0xdeadbeef; SetLastError(0xdeadbeef); ret = WinHttpQueryAuthSchemes(req, &supported, &first, &target); error = GetLastError(); ok(!ret, "expected failure\n"); - ok(error == ERROR_INVALID_OPERATION, "expected ERROR_INVALID_OPERATION, got %u\n", error); - ok(supported == 0xdeadbeef, "got %x\n", supported); - ok(first == 0xdeadbeef, "got %x\n", first); - ok(target == 0xdeadbeef, "got %x\n", target); + ok(error == ERROR_INVALID_OPERATION, "expected ERROR_INVALID_OPERATION, got %lu\n", error); + ok(supported == 0xdeadbeef, "got %lu\n", supported); + ok(first == 0xdeadbeef, "got %lu\n", first); + ok(target == 0xdeadbeef, "got %lu\n", target); supported = first = target = 0xdeadbeef; SetLastError(0xdeadbeef); ret = WinHttpQueryAuthSchemes(NULL, &supported, &first, &target); error = GetLastError(); ok(!ret, "expected failure\n"); - ok(error == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %u\n", error); - ok(supported == 0xdeadbeef, "got %x\n", supported); - ok(first == 0xdeadbeef, "got %x\n", first); - ok(target == 0xdeadbeef, "got %x\n", target); + ok(error == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %lu\n", error); + ok(supported == 0xdeadbeef, "got %lu\n", supported); + ok(first == 0xdeadbeef, "got %lu\n", first); + ok(target == 0xdeadbeef, "got %lu\n", target); ret = WinHttpSendRequest(req, NULL, 0, NULL, 0, 0, 0); - ok(ret, "failed to send request %u\n", GetLastError()); + ok(ret, "failed to send request %lu\n", GetLastError()); ret = WinHttpReceiveResponse(req, NULL); - ok(ret, "failed to receive response %u\n", GetLastError()); + ok(ret, "failed to receive response %lu\n", GetLastError()); status = 0xdeadbeef; size = sizeof(status); ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL); - ok(ret, "failed to query status code %u\n", GetLastError()); - ok(status == HTTP_STATUS_DENIED, "request failed unexpectedly %u\n", status); + ok(ret, "failed to query status code %lu\n", GetLastError()); + ok(status == HTTP_STATUS_DENIED, "request failed unexpectedly %lu\n", status); size = 0; ret = WinHttpReadData(req, buffer, sizeof(buffer), &size); error = GetLastError(); - ok(ret || broken(error == ERROR_WINHTTP_SHUTDOWN || error == ERROR_WINHTTP_TIMEOUT) /* XP */, "failed to read data %u\n", GetLastError()); + ok(ret || broken(error == ERROR_WINHTTP_SHUTDOWN || error == ERROR_WINHTTP_TIMEOUT) /* XP */, "failed to read data %lu\n", GetLastError()); if (ret) { - ok(size == 12, "expected 12, got %u\n", size); + ok(size == 12, "expected 12, got %lu\n", size); ok(!memcmp(buffer, unauthorized, 12), "got %s\n", buffer); } @@ -2648,70 +2851,70 @@ static void test_basic_authentication(int port) SetLastError(0xdeadbeef); ret = WinHttpQueryAuthSchemes(req, &supported, &first, &target); error = GetLastError(); - ok(ret, "failed to query authentication schemes %u\n", error); - ok(error == ERROR_SUCCESS || broken(error == 0xdeadbeef) /* < win7 */, "expected ERROR_SUCCESS, got %u\n", error); - ok(supported == WINHTTP_AUTH_SCHEME_BASIC, "got %x\n", supported); - ok(first == WINHTTP_AUTH_SCHEME_BASIC, "got %x\n", first); - ok(target == WINHTTP_AUTH_TARGET_SERVER, "got %x\n", target); + ok(ret, "failed to query authentication schemes %lu\n", error); + ok(error == ERROR_SUCCESS || broken(error == 0xdeadbeef) /* < win7 */, "expected ERROR_SUCCESS, got %lu\n", error); + ok(supported == WINHTTP_AUTH_SCHEME_BASIC, "got %lu\n", supported); + ok(first == WINHTTP_AUTH_SCHEME_BASIC, "got %lu\n", first); + ok(target == WINHTTP_AUTH_TARGET_SERVER, "got %lu\n", target); SetLastError(0xdeadbeef); ret = WinHttpSetCredentials(req, WINHTTP_AUTH_TARGET_SERVER, WINHTTP_AUTH_SCHEME_NTLM, NULL, NULL, NULL); error = GetLastError(); - ok(ret, "failed to set credentials %u\n", error); - ok(error == ERROR_SUCCESS || broken(error == 0xdeadbeef) /* < win7 */, "expected ERROR_SUCCESS, got %u\n", error); + ok(ret, "failed to set credentials %lu\n", error); + ok(error == ERROR_SUCCESS || broken(error == 0xdeadbeef) /* < win7 */, "expected ERROR_SUCCESS, got %lu\n", error); ret = WinHttpSetCredentials(req, WINHTTP_AUTH_TARGET_SERVER, WINHTTP_AUTH_SCHEME_PASSPORT, NULL, NULL, NULL); - ok(ret, "failed to set credentials %u\n", GetLastError()); + ok(ret, "failed to set credentials %lu\n", GetLastError()); ret = WinHttpSetCredentials(req, WINHTTP_AUTH_TARGET_SERVER, WINHTTP_AUTH_SCHEME_NEGOTIATE, NULL, NULL, NULL); - ok(ret, "failed to set credentials %u\n", GetLastError()); + ok(ret, "failed to set credentials %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = WinHttpSetCredentials(req, WINHTTP_AUTH_TARGET_SERVER, WINHTTP_AUTH_SCHEME_DIGEST, NULL, NULL, NULL); error = GetLastError(); ok(!ret, "expected failure\n"); - ok(error == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %u\n", error); + ok(error == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %lu\n", error); SetLastError(0xdeadbeef); ret = WinHttpSetCredentials(req, WINHTTP_AUTH_TARGET_SERVER, WINHTTP_AUTH_SCHEME_BASIC, NULL, NULL, NULL); error = GetLastError(); ok(!ret, "expected failure\n"); - ok(error == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %u\n", error); + ok(error == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %lu\n", error); SetLastError(0xdeadbeef); - ret = WinHttpSetCredentials(req, WINHTTP_AUTH_TARGET_SERVER, WINHTTP_AUTH_SCHEME_BASIC, userW, NULL, NULL); + ret = WinHttpSetCredentials(req, WINHTTP_AUTH_TARGET_SERVER, WINHTTP_AUTH_SCHEME_BASIC, L"user", NULL, NULL); error = GetLastError(); ok(!ret, "expected failure\n"); - ok(error == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %u\n", error); + ok(error == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %lu\n", error); SetLastError(0xdeadbeef); - ret = WinHttpSetCredentials(req, WINHTTP_AUTH_TARGET_SERVER, WINHTTP_AUTH_SCHEME_BASIC, NULL, passW, NULL); + ret = WinHttpSetCredentials(req, WINHTTP_AUTH_TARGET_SERVER, WINHTTP_AUTH_SCHEME_BASIC, NULL, L"pwd", NULL); error = GetLastError(); ok(!ret, "expected failure\n"); - ok(error == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %u\n", error); + ok(error == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %lu\n", error); - ret = WinHttpSetCredentials(req, WINHTTP_AUTH_TARGET_SERVER, WINHTTP_AUTH_SCHEME_BASIC, userW, passW, NULL); - ok(ret, "failed to set credentials %u\n", GetLastError()); + ret = WinHttpSetCredentials(req, WINHTTP_AUTH_TARGET_SERVER, WINHTTP_AUTH_SCHEME_BASIC, L"user", L"pwd", NULL); + ok(ret, "failed to set credentials %lu\n", GetLastError()); ret = WinHttpSendRequest(req, NULL, 0, NULL, 0, 0, 0); - ok(ret, "failed to send request %u\n", GetLastError()); + ok(ret, "failed to send request %lu\n", GetLastError()); ret = WinHttpReceiveResponse(req, NULL); - ok(ret, "failed to receive response %u\n", GetLastError()); + ok(ret, "failed to receive response %lu\n", GetLastError()); status = 0xdeadbeef; size = sizeof(status); ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL); - ok(ret, "failed to query status code %u\n", GetLastError()); - ok(status == HTTP_STATUS_OK, "request failed unexpectedly %u\n", status); + ok(ret, "failed to query status code %lu\n", GetLastError()); + ok(status == HTTP_STATUS_OK, "request failed unexpectedly %lu\n", status); size = 0; ret = WinHttpReadData(req, buffer, sizeof(buffer), &size); error = GetLastError(); - ok(ret || broken(error == ERROR_WINHTTP_SHUTDOWN || error == ERROR_WINHTTP_TIMEOUT) /* XP */, "failed to read data %u\n", GetLastError()); + ok(ret || broken(error == ERROR_WINHTTP_SHUTDOWN || error == ERROR_WINHTTP_TIMEOUT) /* XP */, "failed to read data %lu\n", GetLastError()); if (ret) { - ok(size == 11, "expected 11, got %u\n", size); + ok(size == 11, "expected 11, got %lu\n", size); ok(!memcmp(buffer, hello_world, 11), "got %s\n", buffer); } @@ -2720,37 +2923,37 @@ static void test_basic_authentication(int port) WinHttpCloseHandle(ses); /* now set the credentials first to show that they get sent with the first request */ - ses = WinHttpOpen(test_useragent, WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0); - ok(ses != NULL, "failed to open session %u\n", GetLastError()); + ses = WinHttpOpen(L"winetest", WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0); + ok(ses != NULL, "failed to open session %lu\n", GetLastError()); - con = WinHttpConnect(ses, localhostW, port, 0); - ok(con != NULL, "failed to open a connection %u\n", GetLastError()); + con = WinHttpConnect(ses, L"localhost", port, 0); + ok(con != NULL, "failed to open a connection %lu\n", GetLastError()); - req = WinHttpOpenRequest(con, NULL, auth_with_credsW, NULL, NULL, NULL, 0); - ok(req != NULL, "failed to open a request %u\n", GetLastError()); + req = WinHttpOpenRequest(con, NULL, L"/auth_with_creds", NULL, NULL, NULL, 0); + ok(req != NULL, "failed to open a request %lu\n", GetLastError()); - ret = WinHttpSetCredentials(req, WINHTTP_AUTH_TARGET_SERVER, WINHTTP_AUTH_SCHEME_BASIC, userW, passW, NULL); - ok(ret, "failed to set credentials %u\n", GetLastError()); + ret = WinHttpSetCredentials(req, WINHTTP_AUTH_TARGET_SERVER, WINHTTP_AUTH_SCHEME_BASIC, L"user", L"pwd", NULL); + ok(ret, "failed to set credentials %lu\n", GetLastError()); ret = WinHttpSendRequest(req, NULL, 0, NULL, 0, 0, 0); - ok(ret, "failed to send request %u\n", GetLastError()); + ok(ret, "failed to send request %lu\n", GetLastError()); ret = WinHttpReceiveResponse(req, NULL); - ok(ret, "failed to receive response %u\n", GetLastError()); + ok(ret, "failed to receive response %lu\n", GetLastError()); status = 0xdeadbeef; size = sizeof(status); ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL); - ok(ret, "failed to query status code %u\n", GetLastError()); - ok(status == HTTP_STATUS_OK, "request failed unexpectedly %u\n", status); + ok(ret, "failed to query status code %lu\n", GetLastError()); + ok(status == HTTP_STATUS_OK, "request failed unexpectedly %lu\n", status); size = 0; ret = WinHttpReadData(req, buffer, sizeof(buffer), &size); error = GetLastError(); - ok(ret || broken(error == ERROR_WINHTTP_SHUTDOWN || error == ERROR_WINHTTP_TIMEOUT) /* XP */, "failed to read data %u\n", GetLastError()); + ok(ret || broken(error == ERROR_WINHTTP_SHUTDOWN || error == ERROR_WINHTTP_TIMEOUT) /* XP */, "failed to read data %lu\n", GetLastError()); if (ret) { - ok(size == 11, "expected 11, got %u\n", size); + ok(size == 11, "expected 11, got %lu\n", size); ok(!memcmp(buffer, hello_world, 11), "got %s\n", buffer); } @@ -2760,69 +2963,69 @@ static void test_basic_authentication(int port) /* credentials set with WinHttpSetCredentials take precedence over those set through options */ - ses = WinHttpOpen(test_useragent, WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0); - ok(ses != NULL, "failed to open session %u\n", GetLastError()); + ses = WinHttpOpen(L"winetest", WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0); + ok(ses != NULL, "failed to open session %lu\n", GetLastError()); - con = WinHttpConnect(ses, localhostW, port, 0); - ok(con != NULL, "failed to open a connection %u\n", GetLastError()); + con = WinHttpConnect(ses, L"localhost", port, 0); + ok(con != NULL, "failed to open a connection %lu\n", GetLastError()); - req = WinHttpOpenRequest(con, NULL, authW, NULL, NULL, NULL, 0); - ok(req != NULL, "failed to open a request %u\n", GetLastError()); + req = WinHttpOpenRequest(con, NULL, L"/auth", NULL, NULL, NULL, 0); + ok(req != NULL, "failed to open a request %lu\n", GetLastError()); - ret = WinHttpSetCredentials(req, WINHTTP_AUTH_TARGET_SERVER, WINHTTP_AUTH_SCHEME_BASIC, userW, passW, NULL); - ok(ret, "failed to set credentials %u\n", GetLastError()); + ret = WinHttpSetCredentials(req, WINHTTP_AUTH_TARGET_SERVER, WINHTTP_AUTH_SCHEME_BASIC, L"user", L"pwd", NULL); + ok(ret, "failed to set credentials %lu\n", GetLastError()); - ret = WinHttpSetOption(req, WINHTTP_OPTION_USERNAME, userW, lstrlenW(userW)); - ok(ret, "failed to set username %u\n", GetLastError()); + ret = WinHttpSetOption(req, WINHTTP_OPTION_USERNAME, (void *)L"user", lstrlenW(L"user")); + ok(ret, "failed to set username %lu\n", GetLastError()); - ret = WinHttpSetOption(req, WINHTTP_OPTION_PASSWORD, pass2W, lstrlenW(pass2W)); - ok(ret, "failed to set password %u\n", GetLastError()); + ret = WinHttpSetOption(req, WINHTTP_OPTION_PASSWORD, (void *)L"pwd2", lstrlenW(L"pwd2")); + ok(ret, "failed to set password %lu\n", GetLastError()); ret = WinHttpSendRequest(req, NULL, 0, NULL, 0, 0, 0); - ok(ret, "failed to send request %u\n", GetLastError()); + ok(ret, "failed to send request %lu\n", GetLastError()); ret = WinHttpReceiveResponse(req, NULL); - ok(ret, "failed to receive response %u\n", GetLastError()); + ok(ret, "failed to receive response %lu\n", GetLastError()); status = 0xdeadbeef; size = sizeof(status); ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL); - ok(ret, "failed to query status code %u\n", GetLastError()); - ok(status == HTTP_STATUS_OK, "request failed unexpectedly %u\n", status); + ok(ret, "failed to query status code %lu\n", GetLastError()); + ok(status == HTTP_STATUS_OK, "request failed unexpectedly %lu\n", status); WinHttpCloseHandle(req); WinHttpCloseHandle(con); WinHttpCloseHandle(ses); - ses = WinHttpOpen(test_useragent, WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0); - ok(ses != NULL, "failed to open session %u\n", GetLastError()); + ses = WinHttpOpen(L"winetest", WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0); + ok(ses != NULL, "failed to open session %lu\n", GetLastError()); - con = WinHttpConnect(ses, localhostW, port, 0); - ok(con != NULL, "failed to open a connection %u\n", GetLastError()); + con = WinHttpConnect(ses, L"localhost", port, 0); + ok(con != NULL, "failed to open a connection %lu\n", GetLastError()); - req = WinHttpOpenRequest(con, NULL, authW, NULL, NULL, NULL, 0); - ok(req != NULL, "failed to open a request %u\n", GetLastError()); + req = WinHttpOpenRequest(con, NULL, L"/auth", NULL, NULL, NULL, 0); + ok(req != NULL, "failed to open a request %lu\n", GetLastError()); - ret = WinHttpSetOption(req, WINHTTP_OPTION_USERNAME, userW, lstrlenW(userW)); - ok(ret, "failed to set username %u\n", GetLastError()); + ret = WinHttpSetOption(req, WINHTTP_OPTION_USERNAME, (void *)L"user", lstrlenW(L"user")); + ok(ret, "failed to set username %lu\n", GetLastError()); - ret = WinHttpSetOption(req, WINHTTP_OPTION_PASSWORD, passW, lstrlenW(passW)); - ok(ret, "failed to set password %u\n", GetLastError()); + ret = WinHttpSetOption(req, WINHTTP_OPTION_PASSWORD, (void *)L"pwd", lstrlenW(L"pwd")); + ok(ret, "failed to set password %lu\n", GetLastError()); - ret = WinHttpSetCredentials(req, WINHTTP_AUTH_TARGET_SERVER, WINHTTP_AUTH_SCHEME_BASIC, userW, pass2W, NULL); - ok(ret, "failed to set credentials %u\n", GetLastError()); + ret = WinHttpSetCredentials(req, WINHTTP_AUTH_TARGET_SERVER, WINHTTP_AUTH_SCHEME_BASIC, L"user", L"pwd2", NULL); + ok(ret, "failed to set credentials %lu\n", GetLastError()); ret = WinHttpSendRequest(req, NULL, 0, NULL, 0, 0, 0); - ok(ret, "failed to send request %u\n", GetLastError()); + ok(ret, "failed to send request %lu\n", GetLastError()); ret = WinHttpReceiveResponse(req, NULL); - ok(ret, "failed to receive response %u\n", GetLastError()); + ok(ret, "failed to receive response %lu\n", GetLastError()); status = 0xdeadbeef; size = sizeof(status); ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL); - ok(ret, "failed to query status code %u\n", GetLastError()); - ok(status == HTTP_STATUS_DENIED, "request failed unexpectedly %u\n", status); + ok(ret, "failed to query status code %lu\n", GetLastError()); + ok(status == HTTP_STATUS_DENIED, "request failed unexpectedly %lu\n", status); WinHttpCloseHandle(req); WinHttpCloseHandle(con); @@ -2831,23 +3034,19 @@ static void test_basic_authentication(int port) static void test_multi_authentication(int port) { - static const WCHAR multiauthW[] = {'/','m','u','l','t','i','a','u','t','h',0}; - static const WCHAR www_authenticateW[] = - {'W','W','W','-','A','u','t','h','e','n','t','i','c','a','t','e',0}; - static const WCHAR getW[] = {'G','E','T',0}; HINTERNET ses, con, req; DWORD supported, first, target, size, index; WCHAR buf[512]; BOOL ret; - ses = WinHttpOpen(test_useragent, WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0); - ok(ses != NULL, "failed to open session %u\n", GetLastError()); + ses = WinHttpOpen(L"winetest", WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0); + ok(ses != NULL, "failed to open session %lu\n", GetLastError()); - con = WinHttpConnect(ses, localhostW, port, 0); - ok(con != NULL, "failed to open a connection %u\n", GetLastError()); + con = WinHttpConnect(ses, L"localhost", port, 0); + ok(con != NULL, "failed to open a connection %lu\n", GetLastError()); - req = WinHttpOpenRequest(con, getW, multiauthW, NULL, NULL, NULL, 0); - ok(req != NULL, "failed to open a request %u\n", GetLastError()); + req = WinHttpOpenRequest(con, L"GET", L"/multiauth", NULL, NULL, NULL, 0); + ok(req != NULL, "failed to open a request %lu\n", GetLastError()); ret = WinHttpSendRequest(req, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA,0, 0, 0 ); @@ -2859,25 +3058,25 @@ static void test_multi_authentication(int port) supported = first = target = 0xdeadbeef; ret = WinHttpQueryAuthSchemes(req, &supported, &first, &target); ok(ret, "expected success\n"); - ok(supported == (WINHTTP_AUTH_SCHEME_BASIC | WINHTTP_AUTH_SCHEME_NTLM), "got %x\n", supported); - ok(target == WINHTTP_AUTH_TARGET_SERVER, "got %x\n", target); - ok(first == WINHTTP_AUTH_SCHEME_BASIC, "got %x\n", first); + ok(supported == (WINHTTP_AUTH_SCHEME_BASIC | WINHTTP_AUTH_SCHEME_NTLM), "got %#lx\n", supported); + ok(target == WINHTTP_AUTH_TARGET_SERVER, "got %#lx\n", target); + ok(first == WINHTTP_AUTH_SCHEME_BASIC, "got %#lx\n", first); index = 0; size = sizeof(buf); - ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_CUSTOM, www_authenticateW, buf, &size, &index); + ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_CUSTOM, L"WWW-Authenticate", buf, &size, &index); ok(ret, "expected success\n"); - ok(!strcmp_wa(buf, "Bearer"), "buf = %s\n", wine_dbgstr_w(buf)); - ok(size == lstrlenW(buf) * sizeof(WCHAR), "size = %u\n", size); - ok(index == 1, "index = %u\n", index); + ok(!lstrcmpW(buf, L"Bearer"), "buf = %s\n", wine_dbgstr_w(buf)); + ok(size == lstrlenW(buf) * sizeof(WCHAR), "size = %lu\n", size); + ok(index == 1, "index = %lu\n", index); index = 0; size = 0xdeadbeef; - ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_CUSTOM, www_authenticateW, NULL, &size, &index); + ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_CUSTOM, L"WWW-Authenticate", NULL, &size, &index); ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, - "WinHttpQueryHeaders returned %x(%u)\n", ret, GetLastError()); - ok(size == (lstrlenW(buf) + 1) * sizeof(WCHAR), "size = %u\n", size); - ok(index == 0, "index = %u\n", index); + "WinHttpQueryHeaders returned %d(%lu)\n", ret, GetLastError()); + ok(size == (lstrlenW(buf) + 1) * sizeof(WCHAR), "size = %lu\n", size); + ok(index == 0, "index = %lu\n", index); WinHttpCloseHandle(req); WinHttpCloseHandle(con); @@ -2886,22 +3085,18 @@ static void test_multi_authentication(int port) static void test_large_data_authentication(int port) { - static const WCHAR largeauthW[] = {'/','l','a','r','g','e','a','u','t','h',0}; - static const WCHAR getW[] = {'G','E','T',0}; - static WCHAR userW[] = {'u','s','e','r',0}; - static WCHAR passW[] = {'p','w','d',0}; HINTERNET ses, con, req; DWORD status, size; BOOL ret; - ses = WinHttpOpen(test_useragent, WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0); - ok(ses != NULL, "failed to open session %u\n", GetLastError()); + ses = WinHttpOpen(L"winetest", WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0); + ok(ses != NULL, "failed to open session %lu\n", GetLastError()); - con = WinHttpConnect(ses, localhostW, port, 0); - ok(con != NULL, "failed to open a connection %u\n", GetLastError()); + con = WinHttpConnect(ses, L"localhost", port, 0); + ok(con != NULL, "failed to open a connection %lu\n", GetLastError()); - req = WinHttpOpenRequest(con, getW, largeauthW, NULL, NULL, NULL, 0); - ok(req != NULL, "failed to open a request %u\n", GetLastError()); + req = WinHttpOpenRequest(con, L"GET", L"/largeauth", NULL, NULL, NULL, 0); + ok(req != NULL, "failed to open a request %lu\n", GetLastError()); ret = WinHttpSendRequest(req, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0); ok(ret, "expected success\n"); @@ -2913,13 +3108,13 @@ static void test_large_data_authentication(int port) ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL); ok(ret, "expected success\n"); - ok(status == HTTP_STATUS_DENIED, "got %d\n", status); + ok(status == HTTP_STATUS_DENIED, "got %lu\n", status); - ret = WinHttpSetCredentials(req, WINHTTP_AUTH_TARGET_SERVER, WINHTTP_AUTH_SCHEME_NTLM, userW, passW, NULL); + ret = WinHttpSetCredentials(req, WINHTTP_AUTH_TARGET_SERVER, WINHTTP_AUTH_SCHEME_NTLM, L"user", L"pwd", NULL); ok(ret, "expected success\n"); ret = WinHttpSendRequest(req, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0); - ok(ret, "expected success %d\n", GetLastError()); + ok(ret, "expected success %lu\n", GetLastError()); ret = WinHttpReceiveResponse(req, NULL); ok(ret, "expected success\n"); @@ -2928,7 +3123,7 @@ static void test_large_data_authentication(int port) ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL); ok(ret, "expected success\n"); - ok(status == HTTP_STATUS_OK, "got %d\n", status); + ok(status == HTTP_STATUS_OK, "got %lu\n", status); WinHttpCloseHandle(req); WinHttpCloseHandle(con); @@ -2937,25 +3132,24 @@ static void test_large_data_authentication(int port) static void test_no_headers(int port) { - static const WCHAR no_headersW[] = {'/','n','o','_','h','e','a','d','e','r','s',0}; HINTERNET ses, con, req; DWORD error; BOOL ret; - ses = WinHttpOpen(test_useragent, WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0); - ok(ses != NULL, "failed to open session %u\n", GetLastError()); + ses = WinHttpOpen(L"winetest", WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0); + ok(ses != NULL, "failed to open session %lu\n", GetLastError()); - con = WinHttpConnect(ses, localhostW, port, 0); - ok(con != NULL, "failed to open a connection %u\n", GetLastError()); + con = WinHttpConnect(ses, L"localhost", port, 0); + ok(con != NULL, "failed to open a connection %lu\n", GetLastError()); - req = WinHttpOpenRequest(con, NULL, no_headersW, NULL, NULL, NULL, 0); - ok(req != NULL, "failed to open a request %u\n", GetLastError()); + req = WinHttpOpenRequest(con, NULL, L"/no_headers", NULL, NULL, NULL, 0); + ok(req != NULL, "failed to open a request %lu\n", GetLastError()); ret = WinHttpSendRequest(req, NULL, 0, NULL, 0, 0, 0); if (!ret) { error = GetLastError(); - ok(error == ERROR_WINHTTP_INVALID_SERVER_RESPONSE, "got %u\n", error); + ok(error == ERROR_WINHTTP_INVALID_SERVER_RESPONSE, "got %lu\n", error); } else { @@ -2963,7 +3157,7 @@ static void test_no_headers(int port) ret = WinHttpReceiveResponse(req, NULL); error = GetLastError(); ok(!ret, "expected failure\n"); - ok(error == ERROR_WINHTTP_INVALID_SERVER_RESPONSE, "got %u\n", error); + ok(error == ERROR_WINHTTP_INVALID_SERVER_RESPONSE, "got %lu\n", error); } WinHttpCloseHandle(req); @@ -2973,20 +3167,19 @@ static void test_no_headers(int port) static void test_no_content(int port) { - static const WCHAR no_contentW[] = {'/','n','o','_','c','o','n','t','e','n','t',0}; HINTERNET ses, con, req; char buf[128]; DWORD size, len = sizeof(buf), bytes_read, status; BOOL ret; - ses = WinHttpOpen(test_useragent, WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0); - ok(ses != NULL, "failed to open session %u\n", GetLastError()); + ses = WinHttpOpen(L"winetest", WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0); + ok(ses != NULL, "failed to open session %lu\n", GetLastError()); - con = WinHttpConnect(ses, localhostW, port, 0); - ok(con != NULL, "failed to open a connection %u\n", GetLastError()); + con = WinHttpConnect(ses, L"localhost", port, 0); + ok(con != NULL, "failed to open a connection %lu\n", GetLastError()); - req = WinHttpOpenRequest(con, NULL, no_contentW, NULL, NULL, NULL, 0); - ok(req != NULL, "failed to open a request %u\n", GetLastError()); + req = WinHttpOpenRequest(con, NULL, L"/no_content", NULL, NULL, NULL, 0); + ok(req != NULL, "failed to open a request %lu\n", GetLastError()); size = 12345; SetLastError(0xdeadbeef); @@ -2994,9 +3187,9 @@ static void test_no_content(int port) todo_wine { ok(!ret, "expected error\n"); ok(GetLastError() == ERROR_WINHTTP_INCORRECT_HANDLE_STATE, - "expected ERROR_WINHTTP_INCORRECT_HANDLE_STATE, got 0x%08x\n", GetLastError()); + "expected ERROR_WINHTTP_INCORRECT_HANDLE_STATE, got %lu\n", GetLastError()); ok(size == 12345 || broken(size == 0) /* Win <= 2003 */, - "expected 12345, got %u\n", size); + "expected 12345, got %lu\n", size); } ret = WinHttpSendRequest(req, NULL, 0, NULL, 0, 0, 0); @@ -3010,7 +3203,7 @@ static void test_no_content(int port) ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL); ok(ret, "expected success\n"); - ok(status == HTTP_STATUS_NO_CONTENT, "expected status 204, got %d\n", status); + ok(status == HTTP_STATUS_NO_CONTENT, "expected status 204, got %lu\n", status); SetLastError(0xdeadbeef); size = sizeof(status); @@ -3018,28 +3211,28 @@ static void test_no_content(int port) ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_CONTENT_LENGTH | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, 0); ok(!ret, "expected no content-length header\n"); - ok(GetLastError() == ERROR_WINHTTP_HEADER_NOT_FOUND, "wrong error %u\n", GetLastError()); - ok(status == 12345, "expected 0, got %d\n", status); + ok(GetLastError() == ERROR_WINHTTP_HEADER_NOT_FOUND, "wrong error %lu\n", GetLastError()); + ok(status == 12345, "expected 0, got %lu\n", status); SetLastError(0xdeadbeef); size = 12345; ret = WinHttpQueryDataAvailable(req, &size); ok(ret, "expected success\n"); ok(GetLastError() == ERROR_SUCCESS || broken(GetLastError() == 0xdeadbeef) /* < win7 */, - "wrong error %u\n", GetLastError()); - ok(!size, "expected 0, got %u\n", size); + "wrong error %lu\n", GetLastError()); + ok(!size, "expected 0, got %lu\n", size); SetLastError(0xdeadbeef); ret = WinHttpReadData(req, buf, len, &bytes_read); ok(ret, "expected success\n"); ok(GetLastError() == ERROR_SUCCESS || broken(GetLastError() == 0xdeadbeef) /* < win7 */, - "wrong error %u\n", GetLastError()); - ok(!bytes_read, "expected 0, got %u\n", bytes_read); + "wrong error %lu\n", GetLastError()); + ok(!bytes_read, "expected 0, got %lu\n", bytes_read); size = 12345; ret = WinHttpQueryDataAvailable(req, &size); ok(ret, "expected success\n"); - ok(size == 0, "expected 0, got %d\n", size); + ok(size == 0, "expected 0, got %lu\n", size); WinHttpCloseHandle(req); @@ -3047,9 +3240,8 @@ static void test_no_content(int port) SetLastError(0xdeadbeef); ret = WinHttpQueryDataAvailable(req, &size); ok(!ret, "expected error\n"); - ok(GetLastError() == ERROR_INVALID_HANDLE, - "expected ERROR_INVALID_HANDLE, got 0x%08x\n", GetLastError()); - ok(size == 12345, "expected 12345, got %u\n", size); + ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %#lx\n", GetLastError()); + ok(size == 12345, "expected 12345, got %lu\n", size); WinHttpCloseHandle(con); WinHttpCloseHandle(ses); @@ -3057,152 +3249,735 @@ static void test_no_content(int port) static void test_head_request(int port) { - static const WCHAR verbW[] = {'H','E','A','D',0}; - static const WCHAR headW[] = {'/','h','e','a','d',0}; HINTERNET ses, con, req; char buf[128]; DWORD size, len, count, status; BOOL ret; - ses = WinHttpOpen(test_useragent, WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0); - ok(ses != NULL, "failed to open session %u\n", GetLastError()); + ses = WinHttpOpen(L"winetest", WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0); + ok(ses != NULL, "failed to open session %lu\n", GetLastError()); - con = WinHttpConnect(ses, localhostW, port, 0); - ok(con != NULL, "failed to open a connection %u\n", GetLastError()); + con = WinHttpConnect(ses, L"localhost", port, 0); + ok(con != NULL, "failed to open a connection %lu\n", GetLastError()); - req = WinHttpOpenRequest(con, verbW, headW, NULL, NULL, NULL, 0); - ok(req != NULL, "failed to open a request %u\n", GetLastError()); + req = WinHttpOpenRequest(con, L"HEAD", L"/head", NULL, NULL, NULL, 0); + ok(req != NULL, "failed to open a request %lu\n", GetLastError()); ret = WinHttpSendRequest(req, NULL, 0, NULL, 0, 0, 0); - ok(ret, "failed to send request %u\n", GetLastError()); + ok(ret, "failed to send request %lu\n", GetLastError()); ret = WinHttpReceiveResponse(req, NULL); - ok(ret, "failed to receive response %u\n", GetLastError()); + ok(ret, "failed to receive response %lu\n", GetLastError()); status = 0xdeadbeef; size = sizeof(status); ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL); - ok(ret, "failed to get status code %u\n", GetLastError()); - ok(status == HTTP_STATUS_OK, "got %u\n", status); + ok(ret, "failed to get status code %lu\n", GetLastError()); + ok(status == HTTP_STATUS_OK, "got %lu\n", status); len = 0xdeadbeef; size = sizeof(len); ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_CONTENT_LENGTH | WINHTTP_QUERY_FLAG_NUMBER, NULL, &len, &size, 0); - ok(ret, "failed to get content-length header %u\n", GetLastError()); - ok(len == HTTP_STATUS_CONTINUE, "got %u\n", len); + ok(ret, "failed to get content-length header %lu\n", GetLastError()); + ok(len == HTTP_STATUS_CONTINUE, "got %lu\n", len); count = 0xdeadbeef; ret = WinHttpQueryDataAvailable(req, &count); - ok(ret, "failed to query data available %u\n", GetLastError()); - ok(!count, "got %u\n", count); + ok(ret, "failed to query data available %lu\n", GetLastError()); + ok(!count, "got %lu\n", count); len = sizeof(buf); count = 0xdeadbeef; ret = WinHttpReadData(req, buf, len, &count); - ok(ret, "failed to read data %u\n", GetLastError()); - ok(!count, "got %u\n", count); + ok(ret, "failed to read data %lu\n", GetLastError()); + ok(!count, "got %lu\n", count); count = 0xdeadbeef; ret = WinHttpQueryDataAvailable(req, &count); - ok(ret, "failed to query data available %u\n", GetLastError()); - ok(!count, "got %u\n", count); + ok(ret, "failed to query data available %lu\n", GetLastError()); + ok(!count, "got %lu\n", count); WinHttpCloseHandle(req); WinHttpCloseHandle(con); WinHttpCloseHandle(ses); } +static void test_redirect(int port) +{ + HINTERNET ses, con, req; + char buf[128]; + DWORD size, len, count, status; + WCHAR url[128], expected[128]; + BOOL ret; + + ses = WinHttpOpen(L"winetest", WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0); + ok(ses != NULL, "failed to open session %lu\n", GetLastError()); + + con = WinHttpConnect(ses, L"localhost", port, 0); + ok(con != NULL, "failed to open a connection %lu\n", GetLastError()); + + req = WinHttpOpenRequest(con, L"POST", L"/redirect", NULL, NULL, NULL, 0); + ok(req != NULL, "failed to open a request %lu\n", GetLastError()); + + url[0] = 0; + size = sizeof(url); + ret = WinHttpQueryOption(req, WINHTTP_OPTION_URL, url, &size); + ok(ret, "got %lu\n", GetLastError()); + swprintf(expected, ARRAY_SIZE(expected), L"http://localhost:%u/redirect", port); + ok(!wcscmp(url, expected), "expected %s got %s\n", wine_dbgstr_w(expected), wine_dbgstr_w(url)); + + ret = WinHttpSendRequest(req, NULL, 0, (void *)"data", sizeof("data"), sizeof("data"), 0); + ok(ret, "failed to send request %lu\n", GetLastError()); + + url[0] = 0; + size = sizeof(url); + ret = WinHttpQueryOption(req, WINHTTP_OPTION_URL, url, &size); + ok(ret, "got %lu\n", GetLastError()); + ok(!wcscmp(url, expected), "expected %s got %s\n", wine_dbgstr_w(expected), wine_dbgstr_w(url)); + + /* Exact buffer size match. */ + url[0] = 0; + size = (lstrlenW(expected) + 1) * sizeof(WCHAR); + ret = WinHttpQueryOption(req, WINHTTP_OPTION_URL, url, &size); + ok(ret, "got %lu\n", GetLastError()); + ok(!wcscmp(url, expected), "expected %s got %s\n", wine_dbgstr_w(expected), wine_dbgstr_w(url)); + + ret = WinHttpReceiveResponse(req, NULL); + ok(ret, "failed to receive response %lu\n", GetLastError()); + + url[0] = 0; + size = sizeof(url); + ret = WinHttpQueryOption(req, WINHTTP_OPTION_URL, url, &size); + ok(ret, "got %lu\n", GetLastError()); + swprintf(expected, ARRAY_SIZE(expected), L"http://localhost:%u/temporary", port); + ok(!wcscmp(url, expected), "expected %s got %s\n", wine_dbgstr_w(expected), wine_dbgstr_w(url)); + + status = 0xdeadbeef; + size = sizeof(status); + ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, + NULL, &status, &size, NULL); + ok(ret, "failed to get status code %lu\n", GetLastError()); + ok(status == HTTP_STATUS_OK, "got %lu\n", status); + + count = 0; + ret = WinHttpQueryDataAvailable(req, &count); + ok(ret, "failed to query data available %lu\n", GetLastError()); + ok(count == 128, "got %lu\n", count); + + len = sizeof(buf); + count = 0; + ret = WinHttpReadData(req, buf, len, &count); + ok(ret, "failed to read data %lu\n", GetLastError()); + ok(count == 128, "got %lu\n", count); + + WinHttpCloseHandle(req); + WinHttpCloseHandle(con); + WinHttpCloseHandle(ses); +} + +static void test_websocket(int port) +{ + HINTERNET session, connection, request, socket, socket2; + DWORD size, len, count, status, index, error, value; + DWORD_PTR ctx; + WINHTTP_WEB_SOCKET_BUFFER_TYPE type; + BOOL broken_buffer_sizes = FALSE; + WCHAR header[32]; + char buf[128], *large_buf; + USHORT close_status; + BOOL ret; + + if (!pWinHttpWebSocketCompleteUpgrade) + { + win_skip("WinHttpWebSocketCompleteUpgrade not supported\n"); + return; + } + + session = WinHttpOpen(L"winetest", 0, NULL, NULL, 0); + ok(session != NULL, "got %lu\n", GetLastError()); + + connection = WinHttpConnect(session, L"localhost", port, 0); + ok(connection != NULL, "got %lu\n", GetLastError()); + + request = WinHttpOpenRequest(connection, L"GET", L"/websocket", NULL, NULL, NULL, 0); + ok(request != NULL, "got %lu\n", GetLastError()); + + ret = WinHttpSetOption(request, WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET, NULL, 0); + ok(ret, "got %lu\n", GetLastError()); + + size = sizeof(header); + SetLastError(0xdeadbeef); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_UPGRADE, NULL, &header, &size, NULL); + error = GetLastError(); + ok(!ret, "success\n"); + ok(error == ERROR_WINHTTP_INCORRECT_HANDLE_STATE, "got %lu\n", error); + + size = sizeof(header); + SetLastError(0xdeadbeef); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CONNECTION, NULL, &header, &size, NULL); + error = GetLastError(); + ok(!ret, "success\n"); + ok(error == ERROR_WINHTTP_INCORRECT_HANDLE_STATE, "got %lu\n", error); + + index = 0; + size = sizeof(buf); + SetLastError(0xdeadbeef); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + L"Sec-WebSocket-Key", buf, &size, &index); + error = GetLastError(); + ok(!ret, "success\n"); + ok(error == ERROR_WINHTTP_HEADER_NOT_FOUND, "got %lu\n", error); + + index = 0; + size = sizeof(buf); + SetLastError(0xdeadbeef); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + L"Sec-WebSocket-Version", buf, &size, &index); + error = GetLastError(); + ok(!ret, "success\n"); + ok(error == ERROR_WINHTTP_HEADER_NOT_FOUND, "got %lu\n", error); + + ret = WinHttpSendRequest(request, NULL, 0, NULL, 0, 0, 0); + ok(ret, "got %lu\n", GetLastError()); + + size = sizeof(header); + SetLastError(0xdeadbeef); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_UPGRADE, NULL, &header, &size, NULL); + error = GetLastError(); + ok(!ret, "success\n"); + ok(error == ERROR_WINHTTP_INCORRECT_HANDLE_STATE, "got %lu\n", error); + + size = sizeof(header); + SetLastError(0xdeadbeef); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CONNECTION, NULL, &header, &size, NULL); + error = GetLastError(); + ok(!ret, "success\n"); + ok(error == ERROR_WINHTTP_INCORRECT_HANDLE_STATE, "got %lu\n", error); + + index = 0; + buf[0] = 0; + size = sizeof(buf); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + L"Sec-WebSocket-Key", buf, &size, &index); + ok(ret, "got %lu\n", GetLastError()); + + index = 0; + buf[0] = 0; + size = sizeof(buf); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + L"Sec-WebSocket-Version", buf, &size, &index); + ok(ret, "got %lu\n", GetLastError()); + + ret = WinHttpReceiveResponse(request, NULL); + ok(ret, "got %lu\n", GetLastError()); + + count = 0xdeadbeef; + ret = WinHttpQueryDataAvailable(request, &count); + ok(ret, "got %lu\n", GetLastError()); + ok(!count, "got %lu\n", count); + + header[0] = 0; + size = sizeof(header); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_UPGRADE, NULL, &header, &size, NULL); + ok(ret, "got %lu\n", GetLastError()); + ok(!wcscmp( header, L"websocket" ), "got %s\n", wine_dbgstr_w(header)); + + header[0] = 0; + size = sizeof(header); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CONNECTION, NULL, &header, &size, NULL); + ok(ret, "got %lu\n", GetLastError()); + ok(!wcscmp( header, L"Upgrade" ), "got %s\n", wine_dbgstr_w(header)); + + status = 0xdeadbeef; + size = sizeof(status); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, + &size, NULL); + ok(ret, "got %lu\n", GetLastError()); + ok(status == HTTP_STATUS_SWITCH_PROTOCOLS, "got %lu\n", status); + + len = 0xdeadbeef; + size = sizeof(len); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CONTENT_LENGTH | WINHTTP_QUERY_FLAG_NUMBER, NULL, &len, + &size, NULL); + ok(!ret, "success\n"); + + index = 0; + size = sizeof(buf); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM, L"Sec-WebSocket-Accept", buf, &size, &index); + ok(ret, "got %lu\n", GetLastError()); + + socket = pWinHttpWebSocketCompleteUpgrade(request, 0); + ok(socket != NULL, "got %lu\n", GetLastError()); + + size = sizeof(header); + ret = WinHttpQueryHeaders(socket, WINHTTP_QUERY_UPGRADE, NULL, &header, &size, NULL); + error = GetLastError(); + ok(!ret, "success\n"); + ok(error == ERROR_WINHTTP_INCORRECT_HANDLE_TYPE, "got %lu\n", error); + + header[0] = 0; + size = sizeof(header); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_UPGRADE, NULL, &header, &size, NULL); + ok(ret, "got %lu\n", GetLastError()); + ok(!wcscmp( header, L"websocket" ), "got %s\n", wine_dbgstr_w(header)); + + header[0] = 0; + size = sizeof(header); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CONNECTION, NULL, &header, &size, NULL); + ok(ret, "got %lu\n", GetLastError()); + ok(!wcscmp( header, L"Upgrade" ), "got %s\n", wine_dbgstr_w(header)); + + index = 0; + size = sizeof(buf); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM, L"Sec-WebSocket-Accept", buf, &size, &index); + ok(ret, "got %lu\n", GetLastError()); + + /* sending request again generates new key */ + ret = WinHttpSendRequest(request, NULL, 0, NULL, 0, 0, 0); + ok(ret, "got %lu\n", GetLastError()); + + /* and creates a new websocket */ + socket2 = pWinHttpWebSocketCompleteUpgrade(request, 0); + ok(socket2 != NULL, "got %lu\n", GetLastError()); + ok(socket2 != socket, "got same socket\n"); + + WinHttpCloseHandle(connection); + /* request handle is still valid */ + size = sizeof(ctx); + ret = WinHttpQueryOption(request, WINHTTP_OPTION_CONTEXT_VALUE, &ctx, &size); + ok(ret, "got %lu\n", GetLastError()); + + ret = WinHttpCloseHandle(socket2); + ok(ret, "got %lu\n", GetLastError()); + + ret = WinHttpCloseHandle(socket); + ok(ret, "got %lu\n", GetLastError()); + + ret = WinHttpQueryOption(request, WINHTTP_OPTION_CONTEXT_VALUE, &ctx, &size); + ok(ret, "got %lu\n", GetLastError()); + + ret = WinHttpCloseHandle(session); + ok(ret, "got %lu\n", GetLastError()); + + ret = WinHttpQueryOption(request, WINHTTP_OPTION_CONTEXT_VALUE, &ctx, &size); + ok(ret, "got %lu\n", GetLastError()); + + ret = WinHttpCloseHandle(request); + ok(ret, "got %lu\n", GetLastError()); + + session = WinHttpOpen(L"winetest", 0, NULL, NULL, 0); + ok(session != NULL, "got %lu\n", GetLastError()); + + connection = WinHttpConnect(session, L"ws.ifelse.io", 0, 0); + ok(connection != NULL, "got %lu\n", GetLastError()); + + size = 0xdeadbeef; + ret = WinHttpQueryOption(session, WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE, &value, &size); + ok(ret, "got %lu\n", GetLastError()); + ok(size == sizeof(DWORD), "got %lu.\n", size); + ok(value == 32768, "got %lu.\n", value); + + value = 65535; + ret = WinHttpSetOption(session, WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE, &value, sizeof(DWORD)); + ok(ret, "got %lu\n", GetLastError()); + + size = 0xdeadbeef; + ret = WinHttpQueryOption(session, WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE, &value, &size); + ok(ret, "got %lu\n", GetLastError()); + ok(size == sizeof(DWORD), "got %lu.\n", size); + ok(value == 32768, "got %lu.\n", value); + + value = 15; + ret = WinHttpSetOption(session, WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE, &value, sizeof(DWORD)); + ok(ret, "got %lu\n", GetLastError()); + + request = WinHttpOpenRequest(connection, L"GET", L"/", NULL, NULL, NULL, 0); + ok(request != NULL, "got %lu\n", GetLastError()); + + size = 0xdeadbeef; + ret = WinHttpQueryOption(session, WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE, &value, &size); + ok(ret, "got %lu\n", GetLastError()); + ok(size == sizeof(DWORD), "got %lu.\n", size); + ok(value == 65535 || broken( value == WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE ) /* Win8 */, "got %lu.\n", value); + if (value == WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE) + broken_buffer_sizes = TRUE; + + size = 0xdeadbeef; + ret = WinHttpQueryOption(request, WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE, &value, &size); + ok(ret, "got %lu\n", GetLastError()); + ok(size == sizeof(DWORD), "got %lu.\n", size); + ok(value == 65535 || broken( value == WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE ), "got %lu.\n", value); + + value = 1048576; + ret = WinHttpSetOption(request, WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE, &value, sizeof(DWORD)); + ok(ret, "got %lu\n", GetLastError()); + + size = 0xdeadbeef; + ret = WinHttpQueryOption(session, WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE, &value, &size); + ok(ret, "got %lu\n", GetLastError()); + ok(size == sizeof(DWORD), "got %lu.\n", size); + ok(value == 65535 || broken( value == WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE ) /* Win8 */, "got %lu.\n", value); + + size = 0xdeadbeef; + ret = WinHttpQueryOption(request, WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE, &value, &size); + ok(ret, "got %lu\n", GetLastError()); + ok(size == sizeof(DWORD), "got %lu.\n", size); + ok(value == 1048576, "got %lu.\n", value); + + size = 0xdeadbeef; + ret = WinHttpQueryOption(connection, WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE, &value, &size); + ok(!ret, "got %d\n", ret); + todo_wine ok(GetLastError() == ERROR_WINHTTP_INCORRECT_HANDLE_TYPE, "got %lu\n", GetLastError()); + + size = 0xdeadbeef; + ret = WinHttpQueryOption(request, WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE, &value, &size); + ok(ret, "got %lu\n", GetLastError()); + ok(size == sizeof(DWORD), "got %lu.\n", size); + ok(value == 15 || broken( value == WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE ) /* Win8 */, "got %lu.\n", value); + + size = sizeof(value); + ret = WinHttpQueryOption(session, WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL, &value, &size); + ok(!ret, "got %d\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu\n", GetLastError()); + + size = sizeof(value); + ret = WinHttpQueryOption(request, WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL, &value, &size); + ok(!ret, "got %d\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu\n", GetLastError()); + + value = 20000; + ret = WinHttpSetOption(request, WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL, &value, sizeof(DWORD)); + ok(!ret, "got %d\n", ret); + todo_wine ok(GetLastError() == ERROR_WINHTTP_INCORRECT_HANDLE_TYPE, "got %lu\n", GetLastError()); + + ret = WinHttpSetOption(request, WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET, NULL, 0); + ok(ret, "got %lu\n", GetLastError()); + + if (!broken_buffer_sizes) + { + /* Fails because we have a too small send buffer size set, but is different on Win8. */ + ret = WinHttpSendRequest(request, NULL, 0, NULL, 0, 0, 0); + ok(!ret, "got %d\n", ret); + ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY, "got %lu\n", GetLastError()); + } + + value = 16; + ret = WinHttpSetOption(request, WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE, &value, sizeof(DWORD)); + ok(ret, "got %lu\n", GetLastError()); + + ret = WinHttpSendRequest(request, NULL, 0, NULL, 0, 0, 0); + ok(ret, "got %lu\n", GetLastError()); + + value = 15; + ret = WinHttpSetOption(request, WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE, &value, sizeof(DWORD)); + ok(ret, "got %lu\n", GetLastError()); + + ret = WinHttpReceiveResponse(request, NULL); + ok(ret, "got %lu\n", GetLastError()); + + status = 0xdeadbeef; + size = sizeof(status); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, + &size, NULL); + ok(ret, "got %lu\n", GetLastError()); + ok(status == HTTP_STATUS_SWITCH_PROTOCOLS, "got %lu\n", status); + + socket = pWinHttpWebSocketCompleteUpgrade(request, 0); + ok(socket != NULL, "got %lu\n", GetLastError()); + + size = sizeof(value); + ret = WinHttpQueryOption(socket, WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE, &value, &size); + ok(!ret, "got %d\n", ret); + todo_wine ok(GetLastError() == ERROR_WINHTTP_INCORRECT_HANDLE_TYPE, "got %lu\n", GetLastError()); + + value = 65535; + ret = WinHttpSetOption(socket, WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE, &value, sizeof(DWORD)); + ok(!ret, "got %d\n", ret); + todo_wine ok(GetLastError() == ERROR_WINHTTP_INCORRECT_HANDLE_TYPE, "got %lu\n", GetLastError()); + + ret = WinHttpSetOption(socket, WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE, &value, sizeof(DWORD)); + ok(!ret, "got %d\n", ret); + todo_wine ok(GetLastError() == ERROR_WINHTTP_INCORRECT_HANDLE_TYPE, "got %lu\n", GetLastError()); + + value = 20000; + ret = WinHttpSetOption(socket, WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL, &value, 2); + ok(!ret, "got %d\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu\n", GetLastError()); + + value = 20000; + ret = WinHttpSetOption(socket, WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL, &value, sizeof(DWORD) * 2); + ok(!ret, "got %d\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + value = 20000; + ret = WinHttpSetOption(socket, WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL, &value, sizeof(DWORD)); + ok(ret, "got %lu\n", GetLastError()); + ok(!GetLastError(), "got %lu\n", GetLastError()); + + size = sizeof(value); + ret = WinHttpQueryOption(socket, WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL, &value, &size); + ok(!ret, "got %d\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu\n", GetLastError()); + + size = 0; + ret = WinHttpQueryOption(socket, WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL, NULL, &size); + ok(!ret, "got %d\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu\n", GetLastError()); + + value = 10000; + ret = WinHttpSetOption(socket, WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL, &value, sizeof(DWORD)); + ok(!ret, "got %d\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu\n", GetLastError()); + + value = 10000; + ret = WinHttpSetOption(socket, WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL, &value, 2); + ok(!ret, "got %d\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu\n", GetLastError()); + + buf[0] = 0; + count = 0; + type = 0xdeadbeef; + error = pWinHttpWebSocketReceive(socket, buf, sizeof(buf), &count, &type); + ok(!error, "got %lu\n", error); + ok(buf[0] == 'R', "got %c\n", buf[0]); + ok(count, "got zero count\n"); + ok(type == WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE, "got %u\n", type); + + error = pWinHttpWebSocketSend(socket, WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE, NULL, 1); + ok(error == ERROR_INVALID_PARAMETER, "got %lu\n", error); + + large_buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(buf) * 2); + memcpy(large_buf, "hello", sizeof("hello")); + memcpy(large_buf + sizeof(buf), "world", sizeof("world")); + error = pWinHttpWebSocketSend(socket, WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE, large_buf, sizeof(buf) * 2); + ok(!error, "got %lu\n", error); + HeapFree(GetProcessHeap(), 0, large_buf); + + error = pWinHttpWebSocketReceive(socket, NULL, 0, NULL, NULL); + ok(error == ERROR_INVALID_PARAMETER, "got %lu\n", error); + + error = pWinHttpWebSocketReceive(socket, buf, 0, NULL, NULL); + ok(error == ERROR_INVALID_PARAMETER, "got %lu\n", error); + + error = pWinHttpWebSocketReceive(socket, NULL, 1, NULL, NULL); + ok(error == ERROR_INVALID_PARAMETER, "got %lu\n", error); + + buf[0] = 0; + count = 0; + type = 0xdeadbeef; + error = pWinHttpWebSocketReceive(socket, buf, sizeof(buf), &count, &type); + ok(!error, "got %lu\n", error); + ok(buf[0] == 'h', "got %c\n", buf[0]); + ok(count == sizeof(buf), "got %lu\n", count); + ok(type == WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE, "got %u\n", type); + + buf[0] = 0; + count = 0; + type = 0xdeadbeef; + error = pWinHttpWebSocketReceive(socket, buf, sizeof(buf), &count, &type); + ok(!error, "got %lu\n", error); + ok(buf[0] == 'w', "got %c\n", buf[0]); + ok(count == sizeof(buf), "got %lu\n", count); + ok(type == WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE, "got %u\n", type); + + error = pWinHttpWebSocketShutdown(socket, WINHTTP_WEB_SOCKET_SUCCESS_CLOSE_STATUS, NULL, 1); + ok(error == ERROR_INVALID_PARAMETER, "got %lu\n", error); + + error = pWinHttpWebSocketShutdown(socket, WINHTTP_WEB_SOCKET_SUCCESS_CLOSE_STATUS, buf, sizeof(buf)); + ok(error == ERROR_INVALID_PARAMETER, "got %lu\n", error); + + error = pWinHttpWebSocketShutdown(socket, WINHTTP_WEB_SOCKET_SUCCESS_CLOSE_STATUS, (void *)"success", + sizeof("success")); + ok(!error, "got %lu\n", error); + + error = pWinHttpWebSocketClose(socket, WINHTTP_WEB_SOCKET_SUCCESS_CLOSE_STATUS, NULL, 1); + ok(error == ERROR_INVALID_PARAMETER, "got %lu\n", error); + + error = pWinHttpWebSocketClose(socket, WINHTTP_WEB_SOCKET_SUCCESS_CLOSE_STATUS, buf, sizeof(buf)); + ok(error == ERROR_INVALID_PARAMETER, "got %lu\n", error); + + error = pWinHttpWebSocketClose(socket, WINHTTP_WEB_SOCKET_SUCCESS_CLOSE_STATUS, (void *)"success2", + sizeof("success2")); + ok(!error, "got %lu\n", error); + + error = pWinHttpWebSocketQueryCloseStatus(socket, NULL, NULL, 0, NULL); + ok(error == ERROR_INVALID_PARAMETER, "got %lu\n", error); + + error = pWinHttpWebSocketQueryCloseStatus(socket, &close_status, NULL, 0, NULL); + ok(error == ERROR_INVALID_PARAMETER, "got %lu\n", error); + + error = pWinHttpWebSocketQueryCloseStatus(socket, &close_status, buf, 0, NULL); + ok(error == ERROR_INVALID_PARAMETER, "got %lu\n", error); + + error = pWinHttpWebSocketQueryCloseStatus(socket, &close_status, buf, sizeof(buf), NULL); + ok(error == ERROR_INVALID_PARAMETER, "got %lu\n", error); + + error = pWinHttpWebSocketQueryCloseStatus(socket, NULL, NULL, 0, &len); + ok(error == ERROR_INVALID_PARAMETER, "got %lu\n", error); + + len = 0xdeadbeef; + error = pWinHttpWebSocketQueryCloseStatus(socket, &close_status, NULL, 0, &len); + ok(!error, "got %lu\n", error); + ok(!len, "got %lu\n", len); + + error = pWinHttpWebSocketQueryCloseStatus(socket, &close_status, NULL, 1, &len); + ok(error == ERROR_INVALID_PARAMETER, "got %lu\n", error); + + close_status = 0xdead; + len = 0xdeadbeef; + memset(buf, 0, sizeof(buf)); + error = pWinHttpWebSocketQueryCloseStatus(socket, &close_status, buf, sizeof(buf), &len); + ok(!error, "got %lu\n", error); + ok(close_status == 1000, "got %d\n", close_status); + ok(!len, "got %lu\n", len); + + WinHttpCloseHandle(socket); + WinHttpCloseHandle(request); + WinHttpCloseHandle(connection); + WinHttpCloseHandle(session); +} + static void test_not_modified(int port) { - static const WCHAR pathW[] = {'/','n','o','t','_','m','o','d','i','f','i','e','d',0}; - static const WCHAR ifmodifiedW[] = {'I','f','-','M','o','d','i','f','i','e','d','-','S','i','n','c','e',':',' '}; - static const WCHAR ifmodified2W[] = {'I','f','-','M','o','d','i','f','i','e','d','-','S','i','n','c','e',0}; BOOL ret; HINTERNET session, request, connection; DWORD index, len, status, size, start = GetTickCount(); SYSTEMTIME st; - WCHAR today[(sizeof(ifmodifiedW) + WINHTTP_TIME_FORMAT_BUFSIZE)/sizeof(WCHAR) + 3], buffer[32]; + WCHAR today[(sizeof(L"If-Modified-Since: ") + WINHTTP_TIME_FORMAT_BUFSIZE)/sizeof(WCHAR) + 3], buffer[32]; - memcpy(today, ifmodifiedW, sizeof(ifmodifiedW)); + memcpy(today, L"If-Modified-Since: ", sizeof(L"If-Modified-Since: ")); GetSystemTime(&st); - WinHttpTimeFromSystemTime(&st, &today[ARRAY_SIZE(ifmodifiedW)]); + WinHttpTimeFromSystemTime(&st, &today[ARRAY_SIZE(L"If-Modified-Since: ") - 1]); - session = WinHttpOpen(test_useragent, WINHTTP_ACCESS_TYPE_NO_PROXY, + session = WinHttpOpen(L"winetest", WINHTTP_ACCESS_TYPE_NO_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); - ok(session != NULL, "WinHttpOpen failed: %u\n", GetLastError()); + ok(session != NULL, "WinHttpOpen failed: %lu\n", GetLastError()); - connection = WinHttpConnect(session, localhostW, port, 0); - ok(connection != NULL, "WinHttpConnect failed: %u\n", GetLastError()); + connection = WinHttpConnect(session, L"localhost", port, 0); + ok(connection != NULL, "WinHttpConnect failed: %lu\n", GetLastError()); - request = WinHttpOpenRequest(connection, NULL, pathW, NULL, WINHTTP_NO_REFERER, + request = WinHttpOpenRequest(connection, NULL, L"/not_modified", NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_BYPASS_PROXY_CACHE); - ok(request != NULL, "WinHttpOpenrequest failed: %u\n", GetLastError()); + ok(request != NULL, "WinHttpOpenrequest failed: %lu\n", GetLastError()); ret = WinHttpSendRequest(request, today, 0, NULL, 0, 0, 0); - ok(ret, "WinHttpSendRequest failed: %u\n", GetLastError()); + ok(ret, "WinHttpSendRequest failed: %lu\n", GetLastError()); ret = WinHttpReceiveResponse(request, NULL); - ok(ret, "WinHttpReceiveResponse failed: %u\n", GetLastError()); + ok(ret, "WinHttpReceiveResponse failed: %lu\n", GetLastError()); index = 0; len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, - ifmodified2W, buffer, &len, &index); - ok(ret, "failed to get header %u\n", GetLastError()); + L"If-Modified-Since", buffer, &len, &index); + ok(ret, "failed to get header %lu\n", GetLastError()); status = 0xdeadbeef; size = sizeof(status); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL); - ok(ret, "WinHttpQueryHeaders failed: %u\n", GetLastError()); - ok(status == HTTP_STATUS_NOT_MODIFIED, "got %u\n", status); + ok(ret, "WinHttpQueryHeaders failed: %lu\n", GetLastError()); + ok(status == HTTP_STATUS_NOT_MODIFIED, "got %lu\n", status); size = 0xdeadbeef; ret = WinHttpQueryDataAvailable(request, &size); - ok(ret, "WinHttpQueryDataAvailable failed: %u\n", GetLastError()); - ok(!size, "got %u\n", size); + ok(ret, "WinHttpQueryDataAvailable failed: %lu\n", GetLastError()); + ok(!size, "got %lu\n", size); WinHttpCloseHandle(request); WinHttpCloseHandle(connection); WinHttpCloseHandle(session); start = GetTickCount() - start; - ok(start <= 2000, "Expected less than 2 seconds for the test, got %u ms\n", start); + ok(start <= 2000, "Expected less than 2 seconds for the test, got %lu ms\n", start); } static void test_bad_header( int port ) { - static const WCHAR bad_headerW[] = - {'C','o','n','t','e','n','t','-','T','y','p','e',':',' ', - 't','e','x','t','/','h','t','m','l','\n','\r',0}; - static const WCHAR text_htmlW[] = {'t','e','x','t','/','h','t','m','l',0}; - static const WCHAR content_typeW[] = {'C','o','n','t','e','n','t','-','T','y','p','e',0}; - WCHAR buffer[32]; + static const WCHAR expected_headers[] = + { + L"HTTP/1.1 200 OK\r\n" + L"Server: winetest\r\n" + L"SpaceAfterHdr: bad\r\n" + L"OkHdr: ok\r\n" + L"\r\n" + }; + HINTERNET ses, con, req; + WCHAR buffer[512]; DWORD index, len; + unsigned int i; BOOL ret; - ses = WinHttpOpen( test_useragent, WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0 ); - ok( ses != NULL, "failed to open session %u\n", GetLastError() ); + static const WCHAR bad_headers[] = + L"Content-Type: text/html\n\r" + L"Test1: Value1\n" + L"Test2: Value2\n\n\n" + L"Test3: Value3\r\r\r" + L"Test4: Value4\r\n\r\n" + L"Cookie: 111"; - con = WinHttpConnect( ses, localhostW, port, 0 ); - ok( con != NULL, "failed to open a connection %u\n", GetLastError() ); + static const struct + { + const WCHAR *header; + const WCHAR *value; + } + header_tests[] = + { + {L"Content-Type", L"text/html"}, + {L"Test1", L"Value1"}, + {L"Test2", L"Value2"}, + {L"Test3", L"Value3"}, + {L"Test4", L"Value4"}, + {L"Cookie", L"111"}, + }; - req = WinHttpOpenRequest( con, NULL, NULL, NULL, NULL, NULL, 0 ); - ok( req != NULL, "failed to open a request %u\n", GetLastError() ); + ses = WinHttpOpen( L"winetest", WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0 ); + ok( ses != NULL, "failed to open session %lu\n", GetLastError() ); - ret = WinHttpAddRequestHeaders( req, bad_headerW, ~0u, WINHTTP_ADDREQ_FLAG_ADD ); - ok( ret, "failed to add header %u\n", GetLastError() ); + con = WinHttpConnect( ses, L"localhost", port, 0 ); + ok( con != NULL, "failed to open a connection %lu\n", GetLastError() ); + + req = WinHttpOpenRequest( con, L"POST", L"/bad_headers", NULL, NULL, NULL, 0 ); + ok( req != NULL, "failed to open a request %lu\n", GetLastError() ); + + ret = WinHttpAddRequestHeaders( req, bad_headers, ~0u, WINHTTP_ADDREQ_FLAG_ADD ); + ok( ret, "failed to add header %lu\n", GetLastError() ); + + for (i = 0; i < ARRAY_SIZE(header_tests); ++i) + { + index = 0; + buffer[0] = 0; + len = sizeof(buffer); + ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + header_tests[i].header, buffer, &len, &index ); + ok( ret, "header %s: failed to query headers %lu\n", debugstr_w(header_tests[i].header), GetLastError() ); + ok( !wcscmp( buffer, header_tests[i].value ), "header %s: got %s\n", + debugstr_w(header_tests[i].header), debugstr_w(buffer) ); + ok( index == 1, "header %s: index = %lu\n", debugstr_w(header_tests[i].header), index ); + } + + ret = WinHttpSendRequest( req, L"Test5: Value5\rTest6: Value6", ~0u, NULL, 0, 0, 0 ); + ok( ret, "failed to send request %lu\n", GetLastError() ); + + ret = WinHttpReceiveResponse( req, NULL ); + ok( ret, "failed to receive response %lu\n", GetLastError() ); - index = 0; - buffer[0] = 0; len = sizeof(buffer); - ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_CUSTOM|WINHTTP_QUERY_FLAG_REQUEST_HEADERS, - content_typeW, buffer, &len, &index ); - ok( ret, "failed to query headers %u\n", GetLastError() ); - ok( !lstrcmpW( buffer, text_htmlW ), "got %s\n", wine_dbgstr_w(buffer) ); - ok( index == 1, "index = %u\n", index ); + ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_CUSTOM, L"OkHdr", buffer, &len, WINHTTP_NO_HEADER_INDEX ); + ok( ret, "got error %lu.\n", GetLastError() ); + + len = sizeof(buffer); + ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_RAW_HEADERS_CRLF, WINHTTP_HEADER_NAME_BY_INDEX, buffer, &len, WINHTTP_NO_HEADER_INDEX ); + ok( ret, "got error %lu.\n", GetLastError() ); + ok( !wcscmp( buffer, expected_headers ), "got %s.\n", debugstr_w(buffer) ); + + len = sizeof(buffer); + ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_CUSTOM, L"SpaceAfterHdr", buffer, &len, WINHTTP_NO_HEADER_INDEX ); + ok( ret, "got error %lu.\n", GetLastError() ); + ok( !wcscmp( buffer, L"bad" ), "got %s.\n", debugstr_w(buffer) ); WinHttpCloseHandle( req ); WinHttpCloseHandle( con ); @@ -3211,22 +3986,21 @@ static void test_bad_header( int port ) static void test_multiple_reads(int port) { - static const WCHAR bigW[] = {'b','i','g',0}; HINTERNET ses, con, req; DWORD total_len = 0; BOOL ret; - ses = WinHttpOpen(test_useragent, WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0); - ok(ses != NULL, "failed to open session %u\n", GetLastError()); + ses = WinHttpOpen(L"winetest", WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0); + ok(ses != NULL, "failed to open session %lu\n", GetLastError()); - con = WinHttpConnect(ses, localhostW, port, 0); - ok(con != NULL, "failed to open a connection %u\n", GetLastError()); + con = WinHttpConnect(ses, L"localhost", port, 0); + ok(con != NULL, "failed to open a connection %lu\n", GetLastError()); - req = WinHttpOpenRequest(con, NULL, bigW, NULL, NULL, NULL, 0); - ok(req != NULL, "failed to open a request %u\n", GetLastError()); + req = WinHttpOpenRequest(con, NULL, L"big", NULL, NULL, NULL, 0); + ok(req != NULL, "failed to open a request %lu\n", GetLastError()); ret = WinHttpSendRequest(req, NULL, 0, NULL, 0, 0, 0); - ok(ret, "failed to send request %u\n", GetLastError()); + ok(ret, "failed to send request %lu\n", GetLastError()); trace("waiting for response\n"); ret = WinHttpReceiveResponse(req, NULL); @@ -3238,7 +4012,7 @@ static void test_multiple_reads(int port) { DWORD len = 0xdeadbeef; ret = WinHttpQueryDataAvailable( req, &len ); - ok( ret, "WinHttpQueryDataAvailable failed with error %u\n", GetLastError() ); + ok( ret, "WinHttpQueryDataAvailable failed with error %lu\n", GetLastError() ); if (ret) ok( len != 0xdeadbeef, "WinHttpQueryDataAvailable return wrong length\n" ); if (len) { @@ -3246,17 +4020,17 @@ static void test_multiple_reads(int port) char *buf = HeapAlloc( GetProcessHeap(), 0, len + 1 ); ret = WinHttpReadData( req, buf, len, &bytes_read ); - ok(ret, "WinHttpReadData failed: %u.\n", GetLastError()); - ok( len == bytes_read, "only got %u of %u available\n", bytes_read, len ); + ok(ret, "WinHttpReadData failed: %lu\n", GetLastError()); + ok( len == bytes_read, "only got %lu of %lu available\n", bytes_read, len ); HeapFree( GetProcessHeap(), 0, buf ); if (!bytes_read) break; total_len += bytes_read; - trace("read bytes %u, total_len: %u\n", bytes_read, total_len); + trace("read bytes %lu, total_len: %lu\n", bytes_read, total_len); } if (!len) break; } - ok(total_len == BIG_BUFFER_LEN, "got wrong length: 0x%x\n", total_len); + ok(total_len == BIG_BUFFER_LEN, "got wrong length: %lu\n", total_len); WinHttpCloseHandle(req); WinHttpCloseHandle(con); @@ -3265,159 +4039,151 @@ static void test_multiple_reads(int port) static void test_cookies( int port ) { - static const WCHAR cookieW[] = {'/','c','o','o','k','i','e',0}; - static const WCHAR cookie2W[] = {'/','c','o','o','k','i','e','2',0}; - static const WCHAR cookie3W[] = {'/','c','o','o','k','i','e','3',0}; - static const WCHAR cookie4W[] = {'/','c','o','o','k','i','e','4',0}; - static const WCHAR cookie5W[] = {'/','c','o','o','k','i','e','5',0}; - static const WCHAR cookieheaderW[] = - {'C','o','o','k','i','e',':',' ','n','a','m','e','=','v','a','l','u','e','2','\r','\n',0}; HINTERNET ses, con, req; DWORD status, size; BOOL ret; - ses = WinHttpOpen( test_useragent, WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0 ); - ok( ses != NULL, "failed to open session %u\n", GetLastError() ); + ses = WinHttpOpen( L"winetest", WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0 ); + ok( ses != NULL, "failed to open session %lu\n", GetLastError() ); - con = WinHttpConnect( ses, localhostW, port, 0 ); - ok( con != NULL, "failed to open a connection %u\n", GetLastError() ); + con = WinHttpConnect( ses, L"localhost", port, 0 ); + ok( con != NULL, "failed to open a connection %lu\n", GetLastError() ); - req = WinHttpOpenRequest( con, NULL, cookieW, NULL, NULL, NULL, 0 ); - ok( req != NULL, "failed to open a request %u\n", GetLastError() ); + req = WinHttpOpenRequest( con, NULL, L"/cookie", NULL, NULL, NULL, 0 ); + ok( req != NULL, "failed to open a request %lu\n", GetLastError() ); ret = WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 ); - ok( ret, "failed to send request %u\n", GetLastError() ); + ok( ret, "failed to send request %lu\n", GetLastError() ); ret = WinHttpReceiveResponse( req, NULL ); - ok( ret, "failed to receive response %u\n", GetLastError() ); + ok( ret, "failed to receive response %lu\n", GetLastError() ); status = 0xdeadbeef; size = sizeof(status); ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL ); - ok( ret, "failed to query status code %u\n", GetLastError() ); - ok( status == HTTP_STATUS_OK, "request failed unexpectedly %u\n", status ); + ok( ret, "failed to query status code %lu\n", GetLastError() ); + ok( status == HTTP_STATUS_OK, "request failed unexpectedly %lu\n", status ); WinHttpCloseHandle( req ); - req = WinHttpOpenRequest( con, NULL, cookie2W, NULL, NULL, NULL, 0 ); - ok( req != NULL, "failed to open a request %u\n", GetLastError() ); + req = WinHttpOpenRequest( con, NULL, L"/cookie2", NULL, NULL, NULL, 0 ); + ok( req != NULL, "failed to open a request %lu\n", GetLastError() ); ret = WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 ); - ok( ret, "failed to send request %u\n", GetLastError() ); + ok( ret, "failed to send request %lu\n", GetLastError() ); ret = WinHttpReceiveResponse( req, NULL ); - ok( ret, "failed to receive response %u\n", GetLastError() ); + ok( ret, "failed to receive response %lu\n", GetLastError() ); status = 0xdeadbeef; size = sizeof(status); ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL ); - ok( ret, "failed to query status code %u\n", GetLastError() ); - ok( status == HTTP_STATUS_OK, "request failed unexpectedly %u\n", status ); + ok( ret, "failed to query status code %lu\n", GetLastError() ); + ok( status == HTTP_STATUS_OK, "request failed unexpectedly %lu\n", status ); WinHttpCloseHandle( req ); WinHttpCloseHandle( con ); - con = WinHttpConnect( ses, localhostW, port, 0 ); - ok( con != NULL, "failed to open a connection %u\n", GetLastError() ); + con = WinHttpConnect( ses, L"localhost", port, 0 ); + ok( con != NULL, "failed to open a connection %lu\n", GetLastError() ); - req = WinHttpOpenRequest( con, NULL, cookie2W, NULL, NULL, NULL, 0 ); - ok( req != NULL, "failed to open a request %u\n", GetLastError() ); + req = WinHttpOpenRequest( con, NULL, L"/cookie2", NULL, NULL, NULL, 0 ); + ok( req != NULL, "failed to open a request %lu\n", GetLastError() ); ret = WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 ); - ok( ret, "failed to send request %u\n", GetLastError() ); + ok( ret, "failed to send request %lu\n", GetLastError() ); ret = WinHttpReceiveResponse( req, NULL ); - ok( ret, "failed to receive response %u\n", GetLastError() ); + ok( ret, "failed to receive response %lu\n", GetLastError() ); status = 0xdeadbeef; size = sizeof(status); ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL ); - ok( ret, "failed to query status code %u\n", GetLastError() ); - ok( status == HTTP_STATUS_OK, "request failed unexpectedly %u\n", status ); + ok( ret, "failed to query status code %lu\n", GetLastError() ); + ok( status == HTTP_STATUS_OK, "request failed unexpectedly %lu\n", status ); WinHttpCloseHandle( req ); - req = WinHttpOpenRequest( con, NULL, cookie3W, NULL, NULL, NULL, 0 ); - ok( req != NULL, "failed to open a request %u\n", GetLastError() ); - - ret = WinHttpSendRequest( req, cookieheaderW, ~0u, NULL, 0, 0, 0 ); - ok( ret, "failed to send request %u\n", GetLastError() ); + req = WinHttpOpenRequest( con, NULL, L"/cookie3", NULL, NULL, NULL, 0 ); + ok( req != NULL, "failed to open a request %lu\n", GetLastError() ); + ret = WinHttpSendRequest( req, L"Cookie: name=value2\r\n", ~0u, NULL, 0, 0, 0 ); + ok( ret, "failed to send request %lu\n", GetLastError() ); ret = WinHttpReceiveResponse( req, NULL ); - ok( ret, "failed to receive response %u\n", GetLastError() ); + ok( ret, "failed to receive response %lu\n", GetLastError() ); status = 0xdeadbeef; size = sizeof(status); ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL ); - ok( ret, "failed to query status code %u\n", GetLastError() ); - ok( status == HTTP_STATUS_OK || broken(status == HTTP_STATUS_BAD_REQUEST), "request failed unexpectedly %u\n", status ); + ok( ret, "failed to query status code %lu\n", GetLastError() ); + ok( status == HTTP_STATUS_OK || broken(status == HTTP_STATUS_BAD_REQUEST), "request failed unexpectedly %lu\n", status ); WinHttpCloseHandle( req ); WinHttpCloseHandle( con ); WinHttpCloseHandle( ses ); - ses = WinHttpOpen( test_useragent, WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0 ); - ok( ses != NULL, "failed to open session %u\n", GetLastError() ); + ses = WinHttpOpen( L"winetest", WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0 ); + ok( ses != NULL, "failed to open session %lu\n", GetLastError() ); - con = WinHttpConnect( ses, localhostW, port, 0 ); - ok( con != NULL, "failed to open a connection %u\n", GetLastError() ); + con = WinHttpConnect( ses, L"localhost", port, 0 ); + ok( con != NULL, "failed to open a connection %lu\n", GetLastError() ); - req = WinHttpOpenRequest( con, NULL, cookie2W, NULL, NULL, NULL, 0 ); - ok( req != NULL, "failed to open a request %u\n", GetLastError() ); + req = WinHttpOpenRequest( con, NULL, L"/cookie2", NULL, NULL, NULL, 0 ); + ok( req != NULL, "failed to open a request %lu\n", GetLastError() ); ret = WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 ); - ok( ret, "failed to send request %u\n", GetLastError() ); + ok( ret, "failed to send request %lu\n", GetLastError() ); ret = WinHttpReceiveResponse( req, NULL ); - ok( ret, "failed to receive response %u\n", GetLastError() ); + ok( ret, "failed to receive response %lu\n", GetLastError() ); status = 0xdeadbeef; size = sizeof(status); ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL ); - ok( ret, "failed to query status code %u\n", GetLastError() ); - ok( status == HTTP_STATUS_BAD_REQUEST, "request failed unexpectedly %u\n", status ); + ok( ret, "failed to query status code %lu\n", GetLastError() ); + ok( status == HTTP_STATUS_BAD_REQUEST, "request failed unexpectedly %lu\n", status ); WinHttpCloseHandle( req ); WinHttpCloseHandle( con ); WinHttpCloseHandle( ses ); - ses = WinHttpOpen( test_useragent, WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0 ); - ok( ses != NULL, "failed to open session %u\n", GetLastError() ); + ses = WinHttpOpen( L"winetest", WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0 ); + ok( ses != NULL, "failed to open session %lu\n", GetLastError() ); - con = WinHttpConnect( ses, localhostW, port, 0 ); - ok( con != NULL, "failed to open a connection %u\n", GetLastError() ); + con = WinHttpConnect( ses, L"localhost", port, 0 ); + ok( con != NULL, "failed to open a connection %lu\n", GetLastError() ); - req = WinHttpOpenRequest( con, NULL, cookie4W, NULL, NULL, NULL, 0 ); - ok( req != NULL, "failed to open a request %u\n", GetLastError() ); + req = WinHttpOpenRequest( con, NULL, L"/cookie4", NULL, NULL, NULL, 0 ); + ok( req != NULL, "failed to open a request %lu\n", GetLastError() ); ret = WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 ); - ok( ret, "failed to send request %u\n", GetLastError() ); + ok( ret, "failed to send request %lu\n", GetLastError() ); ret = WinHttpReceiveResponse( req, NULL ); - ok( ret, "failed to receive response %u\n", GetLastError() ); + ok( ret, "failed to receive response %lu\n", GetLastError() ); status = 0xdeadbeef; size = sizeof(status); ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL ); - ok( ret, "failed to query status code %u\n", GetLastError() ); - ok( status == HTTP_STATUS_OK, "request failed unexpectedly %u\n", status ); + ok( ret, "failed to query status code %lu\n", GetLastError() ); + ok( status == HTTP_STATUS_OK, "request failed unexpectedly %lu\n", status ); WinHttpCloseHandle( req ); - req = WinHttpOpenRequest( con, NULL, cookie5W, NULL, NULL, NULL, 0 ); - ok( req != NULL, "failed to open a request %u\n", GetLastError() ); + req = WinHttpOpenRequest( con, NULL, L"/cookie5", NULL, NULL, NULL, 0 ); + ok( req != NULL, "failed to open a request %lu\n", GetLastError() ); ret = WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 ); - ok( ret, "failed to send request %u\n", GetLastError() ); + ok( ret, "failed to send request %lu\n", GetLastError() ); ret = WinHttpReceiveResponse( req, NULL ); - ok( ret, "failed to receive response %u\n", GetLastError() ); + ok( ret, "failed to receive response %lu\n", GetLastError() ); status = 0xdeadbeef; size = sizeof(status); ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL ); - ok( ret, "failed to query status code %u\n", GetLastError() ); + ok( ret, "failed to query status code %lu\n", GetLastError() ); ok( status == HTTP_STATUS_OK || broken(status == HTTP_STATUS_BAD_REQUEST) /* < win7 */, - "request failed unexpectedly %u\n", status ); + "request failed unexpectedly %lu\n", status ); WinHttpCloseHandle( req ); WinHttpCloseHandle( con ); @@ -3431,20 +4197,20 @@ static void do_request( HINTERNET con, const WCHAR *obj, DWORD flags ) BOOL ret; req = WinHttpOpenRequest( con, NULL, obj, NULL, NULL, NULL, flags ); - ok( req != NULL, "failed to open a request %u\n", GetLastError() ); + ok( req != NULL, "failed to open a request %lu\n", GetLastError() ); ret = WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 ); - ok( ret, "failed to send request %u\n", GetLastError() ); + ok( ret, "failed to send request %lu\n", GetLastError() ); ret = WinHttpReceiveResponse( req, NULL ); - ok( ret, "failed to receive response %u\n", GetLastError() ); + ok( ret, "failed to receive response %lu\n", GetLastError() ); status = 0xdeadbeef; size = sizeof(status); ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL ); - ok( ret, "failed to query status code %u\n", GetLastError() ); + ok( ret, "failed to query status code %lu\n", GetLastError() ); ok( status == HTTP_STATUS_OK || broken(status == HTTP_STATUS_BAD_REQUEST) /* < win7 */, - "request %s with flags %08x failed %u\n", wine_dbgstr_w(obj), flags, status ); + "request %s with flags %#lx failed %lu\n", wine_dbgstr_w(obj), flags, status ); WinHttpCloseHandle( req ); } @@ -3474,11 +4240,11 @@ static void test_request_path_escapes( int port ) {'/','e','s','c','a','p','e','&','t','e','x','t','=',0x541b,0x306e,0x540d,0x306f,0}; HINTERNET ses, con; - ses = WinHttpOpen( test_useragent, WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0 ); - ok( ses != NULL, "failed to open session %u\n", GetLastError() ); + ses = WinHttpOpen( L"winetest", WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0 ); + ok( ses != NULL, "failed to open session %lu\n", GetLastError() ); - con = WinHttpConnect( ses, localhostW, port, 0 ); - ok( con != NULL, "failed to open a connection %u\n", GetLastError() ); + con = WinHttpConnect( ses, L"localhost", port, 0 ); + ok( con != NULL, "failed to open a connection %lu\n", GetLastError() ); do_request( con, objW, 0 ); do_request( con, obj2W, WINHTTP_FLAG_ESCAPE_PERCENT ); @@ -3494,20 +4260,19 @@ static void test_request_path_escapes( int port ) static void test_connection_info( int port ) { - static const WCHAR basicW[] = {'/','b','a','s','i','c',0}; HINTERNET ses, con, req; WINHTTP_CONNECTION_INFO info; DWORD size, error; BOOL ret; - ses = WinHttpOpen( test_useragent, WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0 ); - ok( ses != NULL, "failed to open session %u\n", GetLastError() ); + ses = WinHttpOpen( L"winetest", WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0 ); + ok( ses != NULL, "failed to open session %lu\n", GetLastError() ); - con = WinHttpConnect( ses, localhostW, port, 0 ); - ok( con != NULL, "failed to open a connection %u\n", GetLastError() ); + con = WinHttpConnect( ses, L"localhost", port, 0 ); + ok( con != NULL, "failed to open a connection %lu\n", GetLastError() ); - req = WinHttpOpenRequest( con, NULL, basicW, NULL, NULL, NULL, 0 ); - ok( req != NULL, "failed to open a request %u\n", GetLastError() ); + req = WinHttpOpenRequest( con, NULL, L"/basic", NULL, NULL, NULL, 0 ); + ok( req != NULL, "failed to open a request %lu\n", GetLastError() ); size = sizeof(info); SetLastError( 0xdeadbeef ); @@ -3519,32 +4284,32 @@ static void test_connection_info( int port ) return; } ok( !ret, "unexpected success\n" ); - ok( error == ERROR_WINHTTP_INCORRECT_HANDLE_STATE, "got %u\n", error ); + ok( error == ERROR_WINHTTP_INCORRECT_HANDLE_STATE, "got %lu\n", error ); ret = WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 ); - ok( ret, "failed to send request %u\n", GetLastError() ); + ok( ret, "failed to send request %lu\n", GetLastError() ); size = 0; SetLastError( 0xdeadbeef ); ret = WinHttpQueryOption( req, WINHTTP_OPTION_CONNECTION_INFO, &info, &size ); error = GetLastError(); ok( !ret, "unexpected success\n" ); - ok( error == ERROR_INSUFFICIENT_BUFFER, "got %u\n", error ); + ok( error == ERROR_INSUFFICIENT_BUFFER, "got %lu\n", error ); size = sizeof(info); memset( &info, 0, sizeof(info) ); ret = WinHttpQueryOption( req, WINHTTP_OPTION_CONNECTION_INFO, &info, &size ); - ok( ret, "failed to retrieve connection info %u\n", GetLastError() ); - ok( info.cbSize == sizeof(info) || info.cbSize == sizeof(info) - sizeof(info.cbSize) /* Win7 */, "wrong size %u\n", info.cbSize ); + ok( ret, "failed to retrieve connection info %lu\n", GetLastError() ); + ok( info.cbSize == sizeof(info) || info.cbSize == sizeof(info) - sizeof(info.cbSize) /* Win7 */, "wrong size %lu\n", info.cbSize ); ret = WinHttpReceiveResponse( req, NULL ); - ok( ret, "failed to receive response %u\n", GetLastError() ); + ok( ret, "failed to receive response %lu\n", GetLastError() ); size = sizeof(info); memset( &info, 0, sizeof(info) ); ret = WinHttpQueryOption( req, WINHTTP_OPTION_CONNECTION_INFO, &info, &size ); - ok( ret, "failed to retrieve connection info %u\n", GetLastError() ); - ok( info.cbSize == sizeof(info) || info.cbSize == sizeof(info) - sizeof(info.cbSize) /* Win7 */, "wrong size %u\n", info.cbSize ); + ok( ret, "failed to retrieve connection info %lu\n", GetLastError() ); + ok( info.cbSize == sizeof(info) || info.cbSize == sizeof(info) - sizeof(info.cbSize) /* Win7 */, "wrong size %lu\n", info.cbSize ); WinHttpCloseHandle( req ); WinHttpCloseHandle( con ); @@ -3553,42 +4318,34 @@ static void test_connection_info( int port ) static void test_passport_auth( int port ) { - static const WCHAR passportW[] = - {'/','p','a','s','s','p','o','r','t',0}; - static const WCHAR foundW[] = - {'F','o','u','n','d',0}; - static const WCHAR unauthorizedW[] = - {'U','n','a','u','t','h','o','r','i','z','e','d',0}; static const WCHAR headersW[] = - {'H','T','T','P','/','1','.','1',' ','4','0','1',' ','F','o','u','n','d','\r','\n', - 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',':',' ','0','\r','\n', - 'L','o','c','a','t','i','o','n',':',' ','/','\r','\n', - 'W','W','W','-','A','u','t','h','e','n','t','i','c','a','t','e',':',' ', - 'P','a','s','s','p','o','r','t','1','.','4','\r','\n','\r','\n',0}; + L"HTTP/1.1 401 Found\r\nContent-Length: 0\r\nLocation: /\r\nWWW-Authenticate: Passport1.4\r\n\r\n"; HINTERNET ses, con, req; - DWORD status, size, option; + DWORD status, size, option, err; WCHAR buf[128]; BOOL ret; - ses = WinHttpOpen( test_useragent, 0, NULL, NULL, 0 ); - ok( ses != NULL, "got %u\n", GetLastError() ); + ses = WinHttpOpen( L"winetest", 0, NULL, NULL, 0 ); + ok( ses != NULL, "got %lu\n", GetLastError() ); option = WINHTTP_ENABLE_PASSPORT_AUTH; ret = WinHttpSetOption( ses, WINHTTP_OPTION_CONFIGURE_PASSPORT_AUTH, &option, sizeof(option) ); - ok( ret, "got %u\n", GetLastError() ); + ok( ret, "got %lu\n", GetLastError() ); - con = WinHttpConnect( ses, localhostW, port, 0 ); - ok( con != NULL, "got %u\n", GetLastError() ); + con = WinHttpConnect( ses, L"localhost", port, 0 ); + ok( con != NULL, "got %lu\n", GetLastError() ); - req = WinHttpOpenRequest( con, NULL, passportW, NULL, NULL, NULL, 0 ); - ok( req != NULL, "got %u\n", GetLastError() ); + req = WinHttpOpenRequest( con, NULL, L"/passport", NULL, NULL, NULL, 0 ); + ok( req != NULL, "got %lu\n", GetLastError() ); ret = WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 ); - ok( ret, "got %u\n", GetLastError() ); + ok( ret, "got %lu\n", GetLastError() ); ret = WinHttpReceiveResponse( req, NULL ); - ok( ret || broken(!ret && GetLastError() == ERROR_WINHTTP_LOGIN_FAILURE) /* winxp */, "got %u\n", GetLastError() ); - if (!ret && GetLastError() == ERROR_WINHTTP_LOGIN_FAILURE) + err = GetLastError(); + ok( ret || broken(!ret && err == ERROR_WINHTTP_LOGIN_FAILURE) /* winxp */ + || broken(!ret && err == ERROR_WINHTTP_INVALID_SERVER_RESPONSE ), "got %lu\n", err ); + if (!ret) { win_skip("no support for Passport redirects\n"); goto cleanup; @@ -3597,22 +4354,23 @@ static void test_passport_auth( int port ) status = 0xdeadbeef; size = sizeof(status); ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL ); - ok( ret, "got %u\n", GetLastError() ); - ok( status == HTTP_STATUS_DENIED, "got %u\n", status ); + ok( ret, "got %lu\n", GetLastError() ); + ok( status == HTTP_STATUS_DENIED, "got %lu\n", status ); buf[0] = 0; size = sizeof(buf); ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_TEXT, NULL, buf, &size, NULL ); - ok( ret, "got %u\n", GetLastError() ); - ok( !lstrcmpW(foundW, buf) || broken(!lstrcmpW(unauthorizedW, buf)) /* < win7 */, "got %s\n", wine_dbgstr_w(buf) ); + ok( ret, "got %lu\n", GetLastError() ); + ok( !lstrcmpW(L"Found", buf) || broken(!lstrcmpW(L"Unauthorized", buf)) /* < win7 */, "got %s\n", + wine_dbgstr_w(buf) ); buf[0] = 0; size = sizeof(buf); ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_RAW_HEADERS_CRLF, NULL, buf, &size, NULL ); - ok( ret || broken(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER) /* < win7 */, "got %u\n", GetLastError() ); + ok( ret || broken(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER) /* < win7 */, "got %lu\n", GetLastError() ); if (ret) { - ok( size == lstrlenW(headersW) * sizeof(WCHAR), "got %u\n", size ); + ok( size == lstrlenW(headersW) * sizeof(WCHAR), "got %lu\n", size ); ok( !lstrcmpW(headersW, buf), "got %s\n", wine_dbgstr_w(buf) ); } @@ -3633,109 +4391,217 @@ static void test_credentials(void) WCHAR buffer[32]; BOOL ret; - ses = WinHttpOpen(test_useragent, 0, proxy_userW, proxy_passW, 0); - ok(ses != NULL, "failed to open session %u\n", GetLastError()); + ses = WinHttpOpen(L"winetest", 0, proxy_userW, proxy_passW, 0); + ok(ses != NULL, "failed to open session %lu\n", GetLastError()); - con = WinHttpConnect(ses, localhostW, 0, 0); - ok(con != NULL, "failed to open a connection %u\n", GetLastError()); + con = WinHttpConnect(ses, L"localhost", 0, 0); + ok(con != NULL, "failed to open a connection %lu\n", GetLastError()); req = WinHttpOpenRequest(con, NULL, NULL, NULL, NULL, NULL, 0); - ok(req != NULL, "failed to open a request %u\n", GetLastError()); + ok(req != NULL, "failed to open a request %lu\n", GetLastError()); size = ARRAY_SIZE(buffer); ret = WinHttpQueryOption(req, WINHTTP_OPTION_PROXY_USERNAME, &buffer, &size); - ok(ret, "failed to query proxy username %u\n", GetLastError()); + ok(ret, "failed to query proxy username %lu\n", GetLastError()); ok(!buffer[0], "unexpected result %s\n", wine_dbgstr_w(buffer)); - ok(!size, "expected 0, got %u\n", size); + ok(!size, "expected 0, got %lu\n", size); + + size = 4; + SetLastError(0xdeadbeef); + ret = WinHttpQueryOption(req, WINHTTP_OPTION_PROXY_USERNAME, NULL, &size); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Unexpected error %lu\n", GetLastError()); + ok(size == 2, "Unexpected size %lu\n", size); size = ARRAY_SIZE(buffer); ret = WinHttpQueryOption(req, WINHTTP_OPTION_PROXY_PASSWORD, &buffer, &size); - ok(ret, "failed to query proxy password %u\n", GetLastError()); + ok(ret, "failed to query proxy password %lu\n", GetLastError()); ok(!buffer[0], "unexpected result %s\n", wine_dbgstr_w(buffer)); - ok(!size, "expected 0, got %u\n", size); + ok(!size, "expected 0, got %lu\n", size); + + size = 4; + SetLastError(0xdeadbeef); + ret = WinHttpQueryOption(req, WINHTTP_OPTION_PROXY_PASSWORD, NULL, &size); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Unexpected error %lu\n", GetLastError()); + ok(size == 2, "Unexpected size %lu\n", size); ret = WinHttpSetOption(req, WINHTTP_OPTION_PROXY_USERNAME, proxy_userW, lstrlenW(proxy_userW)); - ok(ret, "failed to set username %u\n", GetLastError()); + ok(ret, "failed to set username %lu\n", GetLastError()); size = ARRAY_SIZE(buffer); ret = WinHttpQueryOption(req, WINHTTP_OPTION_PROXY_USERNAME, &buffer, &size); - ok(ret, "failed to query proxy username %u\n", GetLastError()); - ok(!winetest_strcmpW(buffer, proxy_userW), "unexpected result %s\n", wine_dbgstr_w(buffer)); - ok(size == lstrlenW(proxy_userW) * sizeof(WCHAR), "unexpected result %u\n", size); + ok(ret, "failed to query proxy username %lu\n", GetLastError()); + ok(!wcscmp(buffer, proxy_userW), "unexpected result %s\n", wine_dbgstr_w(buffer)); + ok(size == lstrlenW(proxy_userW) * sizeof(WCHAR), "unexpected result %lu\n", size); + + /* Exact buffer size match. */ + size = (lstrlenW(proxy_userW) + 1) * sizeof(WCHAR); + buffer[0] = 0; + ret = WinHttpQueryOption(req, WINHTTP_OPTION_PROXY_USERNAME, &buffer, &size); + ok(ret, "failed to query proxy username %lu\n", GetLastError()); + ok(!wcscmp(buffer, proxy_userW), "unexpected result %s\n", wine_dbgstr_w(buffer)); + ok(size == lstrlenW(proxy_userW) * sizeof(WCHAR), "unexpected result %lu\n", size); + + buffer[0] = 0x1; + SetLastError(0xdeadbeef); + ret = WinHttpQueryOption(req, WINHTTP_OPTION_PROXY_USERNAME, &buffer, &size); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Unexpected error %lu\n", GetLastError()); + ok(*buffer == 0x1, "unexpected result %s\n", wine_dbgstr_w(buffer)); + ok(size == (lstrlenW(proxy_userW) + 1) * sizeof(WCHAR), "unexpected result %lu\n", size); + + size = 0; + SetLastError(0xdeadbeef); + ret = WinHttpQueryOption(req, WINHTTP_OPTION_PROXY_USERNAME, NULL, &size); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Unexpected error %lu\n", GetLastError()); + ok(size == (lstrlenW(proxy_userW) + 1) * sizeof(WCHAR), "Unexpected size %lu\n", size); size = ARRAY_SIZE(buffer); ret = WinHttpQueryOption(req, WINHTTP_OPTION_USERNAME, &buffer, &size); - ok(ret, "failed to query username %u\n", GetLastError()); + ok(ret, "failed to query username %lu\n", GetLastError()); ok(!buffer[0], "unexpected result %s\n", wine_dbgstr_w(buffer)); - ok(!size, "expected 0, got %u\n", size); + ok(!size, "expected 0, got %lu\n", size); + + size = 4; + SetLastError(0xdeadbeef); + ret = WinHttpQueryOption(req, WINHTTP_OPTION_USERNAME, NULL, &size); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Unexpected error %lu\n", GetLastError()); + ok(size == 2, "Unexpected size %lu\n", size); size = ARRAY_SIZE(buffer); ret = WinHttpQueryOption(req, WINHTTP_OPTION_PASSWORD, &buffer, &size); - ok(ret, "failed to query password %u\n", GetLastError()); + ok(ret, "failed to query password %lu\n", GetLastError()); ok(!buffer[0], "unexpected result %s\n", wine_dbgstr_w(buffer)); - ok(!size, "expected 0, got %u\n", size); + ok(!size, "expected 0, got %lu\n", size); + + size = 4; + SetLastError(0xdeadbeef); + ret = WinHttpQueryOption(req, WINHTTP_OPTION_PASSWORD, NULL, &size); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Unexpected error %lu\n", GetLastError()); + ok(size == 2, "Unexpected size %lu\n", size); ret = WinHttpSetOption(req, WINHTTP_OPTION_PROXY_PASSWORD, proxy_passW, lstrlenW(proxy_passW)); - ok(ret, "failed to set proxy password %u\n", GetLastError()); + ok(ret, "failed to set proxy password %lu\n", GetLastError()); size = ARRAY_SIZE(buffer); ret = WinHttpQueryOption(req, WINHTTP_OPTION_PROXY_PASSWORD, &buffer, &size); - ok(ret, "failed to query proxy password %u\n", GetLastError()); - ok(!winetest_strcmpW(buffer, proxy_passW), "unexpected result %s\n", wine_dbgstr_w(buffer)); - ok(size == lstrlenW(proxy_passW) * sizeof(WCHAR), "unexpected result %u\n", size); + ok(ret, "failed to query proxy password %lu\n", GetLastError()); + ok(!wcscmp(buffer, proxy_passW), "unexpected result %s\n", wine_dbgstr_w(buffer)); + ok(size == lstrlenW(proxy_passW) * sizeof(WCHAR), "unexpected result %lu\n", size); + + /* Exact buffer size match. */ + size = (lstrlenW(proxy_passW) + 1) * sizeof(WCHAR); + buffer[0] = 0; + ret = WinHttpQueryOption(req, WINHTTP_OPTION_PROXY_PASSWORD, &buffer, &size); + ok(ret, "failed to query proxy password %lu\n", GetLastError()); + ok(!wcscmp(buffer, proxy_passW), "unexpected result %s\n", wine_dbgstr_w(buffer)); + ok(size == lstrlenW(proxy_passW) * sizeof(WCHAR), "unexpected result %lu\n", size); + + buffer[0] = 0x1; + SetLastError(0xdeadbeef); + ret = WinHttpQueryOption(req, WINHTTP_OPTION_PROXY_PASSWORD, &buffer, &size); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Unexpected error %lu\n", GetLastError()); + ok(*buffer == 0x1, "unexpected result %s\n", wine_dbgstr_w(buffer)); + ok(size == (lstrlenW(proxy_passW) + 1) * sizeof(WCHAR), "unexpected result %lu\n", size); + + size = 0; + SetLastError(0xdeadbeef); + ret = WinHttpQueryOption(req, WINHTTP_OPTION_PROXY_PASSWORD, NULL, &size); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Unexpected error %lu\n", GetLastError()); + ok(size == (lstrlenW(proxy_passW) + 1) * sizeof(WCHAR), "Unexpected size %lu\n", size); ret = WinHttpSetOption(req, WINHTTP_OPTION_USERNAME, userW, lstrlenW(userW)); - ok(ret, "failed to set username %u\n", GetLastError()); + ok(ret, "failed to set username %lu\n", GetLastError()); size = ARRAY_SIZE(buffer); ret = WinHttpQueryOption(req, WINHTTP_OPTION_USERNAME, &buffer, &size); - ok(ret, "failed to query username %u\n", GetLastError()); - ok(!winetest_strcmpW(buffer, userW), "unexpected result %s\n", wine_dbgstr_w(buffer)); - ok(size == lstrlenW(userW) * sizeof(WCHAR), "unexpected result %u\n", size); + ok(ret, "failed to query username %lu\n", GetLastError()); + ok(!wcscmp(buffer, userW), "unexpected result %s\n", wine_dbgstr_w(buffer)); + ok(size == lstrlenW(userW) * sizeof(WCHAR), "unexpected result %lu\n", size); + + /* Exact buffer size match. */ + size = (lstrlenW(userW) + 1) * sizeof(WCHAR); + buffer[0] = 0; + ret = WinHttpQueryOption(req, WINHTTP_OPTION_USERNAME, &buffer, &size); + ok(ret, "failed to query username %lu\n", GetLastError()); + ok(!wcscmp(buffer, userW), "unexpected result %s\n", wine_dbgstr_w(buffer)); + ok(size == lstrlenW(userW) * sizeof(WCHAR), "unexpected result %lu\n", size); + + buffer[0] = 0x1; + SetLastError(0xdeadbeef); + ret = WinHttpQueryOption(req, WINHTTP_OPTION_USERNAME, &buffer, &size); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Unexpected error %lu\n", GetLastError()); + ok(*buffer == 0x1, "unexpected result %s\n", wine_dbgstr_w(buffer)); + ok(size == (lstrlenW(userW) + 1) * sizeof(WCHAR), "unexpected result %lu\n", size); + + size = 0; + SetLastError(0xdeadbeef); + ret = WinHttpQueryOption(req, WINHTTP_OPTION_USERNAME, NULL, &size); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Unexpected error %lu\n", GetLastError()); + ok(size == (lstrlenW(userW) + 1) * sizeof(WCHAR), "Unexpected size %lu\n", size); ret = WinHttpSetOption(req, WINHTTP_OPTION_PASSWORD, passW, lstrlenW(passW)); - ok(ret, "failed to set password %u\n", GetLastError()); + ok(ret, "failed to set password %lu\n", GetLastError()); size = ARRAY_SIZE(buffer); ret = WinHttpQueryOption(req, WINHTTP_OPTION_PASSWORD, &buffer, &size); - ok(ret, "failed to query password %u\n", GetLastError()); - ok(!winetest_strcmpW(buffer, passW), "unexpected result %s\n", wine_dbgstr_w(buffer)); - ok(size == lstrlenW(passW) * sizeof(WCHAR), "unexpected result %u\n", size); + ok(ret, "failed to query password %lu\n", GetLastError()); + ok(!wcscmp(buffer, passW), "unexpected result %s\n", wine_dbgstr_w(buffer)); + ok(size == lstrlenW(passW) * sizeof(WCHAR), "unexpected result %lu\n", size); + + /* Exact buffer size match. */ + buffer[0] = 0; + size = (lstrlenW(passW) + 1) * sizeof(WCHAR); + ret = WinHttpQueryOption(req, WINHTTP_OPTION_PASSWORD, &buffer, &size); + ok(ret, "failed to query password %lu\n", GetLastError()); + ok(!wcscmp(buffer, passW), "unexpected result %s\n", wine_dbgstr_w(buffer)); + ok(size == lstrlenW(passW) * sizeof(WCHAR), "unexpected result %lu\n", size); + + buffer[0] = 0x1; + SetLastError(0xdeadbeef); + ret = WinHttpQueryOption(req, WINHTTP_OPTION_PASSWORD, &buffer, &size); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Unexpected error %lu\n", GetLastError()); + ok(*buffer == 0x1, "unexpected result %s\n", wine_dbgstr_w(buffer)); + ok(size == (lstrlenW(passW) + 1) * sizeof(WCHAR), "unexpected result %lu\n", size); + + size = 0; + SetLastError(0xdeadbeef); + ret = WinHttpQueryOption(req, WINHTTP_OPTION_PASSWORD, NULL, &size); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Unexpected error %lu\n", GetLastError()); + ok(size == (lstrlenW(passW) + 1) * sizeof(WCHAR), "Unexpected size %lu\n", size); WinHttpCloseHandle(req); req = WinHttpOpenRequest(con, NULL, NULL, NULL, NULL, NULL, 0); - ok(req != NULL, "failed to open a request %u\n", GetLastError()); + ok(req != NULL, "failed to open a request %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = WinHttpSetCredentials(req, WINHTTP_AUTH_TARGET_SERVER, WINHTTP_AUTH_SCHEME_BASIC, userW, NULL, NULL); error = GetLastError(); ok(!ret, "expected failure\n"); - ok(error == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %u\n", error); + ok(error == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %lu\n", error); SetLastError(0xdeadbeef); ret = WinHttpSetCredentials(req, WINHTTP_AUTH_TARGET_SERVER, WINHTTP_AUTH_SCHEME_BASIC, NULL, passW, NULL); error = GetLastError(); ok(!ret, "expected failure\n"); - ok(error == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %u\n", error); + ok(error == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %lu\n", error); ret = WinHttpSetCredentials(req, WINHTTP_AUTH_TARGET_SERVER, WINHTTP_AUTH_SCHEME_BASIC, userW, passW, NULL); - ok(ret, "failed to set credentials %u\n", GetLastError()); + ok(ret, "failed to set credentials %lu\n", GetLastError()); size = ARRAY_SIZE(buffer); ret = WinHttpQueryOption(req, WINHTTP_OPTION_USERNAME, &buffer, &size); - ok(ret, "failed to query username %u\n", GetLastError()); + ok(ret, "failed to query username %lu\n", GetLastError()); todo_wine { ok(!buffer[0], "unexpected result %s\n", wine_dbgstr_w(buffer)); - ok(!size, "expected 0, got %u\n", size); + ok(!size, "expected 0, got %lu\n", size); } size = ARRAY_SIZE(buffer); ret = WinHttpQueryOption(req, WINHTTP_OPTION_PASSWORD, &buffer, &size); - ok(ret, "failed to query password %u\n", GetLastError()); + ok(ret, "failed to query password %lu\n", GetLastError()); todo_wine { ok(!buffer[0], "unexpected result %s\n", wine_dbgstr_w(buffer)); - ok(!size, "expected 0, got %u\n", size); + ok(!size, "expected 0, got %lu\n", size); } WinHttpCloseHandle(req); @@ -3746,27 +4612,11 @@ static void test_credentials(void) static void test_IWinHttpRequest(int port) { static const WCHAR data_start[] = {'<','!','D','O','C','T','Y','P','E',' ','h','t','m','l',' ','P','U','B','L','I','C'}; - static const WCHAR usernameW[] = {'u','s','e','r','n','a','m','e',0}; - static const WCHAR passwordW[] = {'p','a','s','s','w','o','r','d',0}; - static const WCHAR url1W[] = {'h','t','t','p',':','/','/','t','e','s','t','.','w','i','n','e','h','q','.','o','r','g',0}; - static const WCHAR url2W[] = {'t','e','s','t','.','w','i','n','e','h','q','.','o','r','g',0}; - static const WCHAR url3W[] = {'h','t','t','p',':','/','/','t','e','s','t','.','w','i','n','e','h','q','.', - 'o','r','g','/','t','e','s','t','s','/','p','o','s','t','.','p','h','p',0}; - static const WCHAR method1W[] = {'G','E','T',0}; - static const WCHAR method2W[] = {'I','N','V','A','L','I','D',0}; - static const WCHAR method3W[] = {'P','O','S','T',0}; - static const WCHAR proxy_serverW[] = {'p','r','o','x','y','s','e','r','v','e','r',0}; - static const WCHAR bypas_listW[] = {'b','y','p','a','s','s','l','i','s','t',0}; - static const WCHAR connectionW[] = {'C','o','n','n','e','c','t','i','o','n',0}; - static const WCHAR dateW[] = {'D','a','t','e',0}; - static const WCHAR test_dataW[] = {'t','e','s','t','d','a','t','a',128,0}; - static const WCHAR utf8W[] = {'u','t','f','-','8',0}; - static const WCHAR unauthW[] = {'U','n','a','u','t','h','o','r','i','z','e','d',0}; HRESULT hr; IWinHttpRequest *req; BSTR method, url, username, password, response = NULL, status_text = NULL, headers = NULL; BSTR date, today, connection, value = NULL; - VARIANT async, empty, timeout, body, body2, proxy_server, bypass_list, data, cp; + VARIANT async, empty, timeout, body, body2, proxy_server, bypass_list, data, cp, flags; VARIANT_BOOL succeeded; LONG status; WCHAR todayW[WINHTTP_TIME_FORMAT_BUFSIZE]; @@ -3782,7 +4632,7 @@ static void test_IWinHttpRequest(int port) CoInitialize( NULL ); hr = CoCreateInstance( &CLSID_WinHttpRequest, NULL, CLSCTX_INPROC_SERVER, &IID_IWinHttpRequest, (void **)&req ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); V_VT( &empty ) = VT_ERROR; V_ERROR( &empty ) = 0xdeadbeef; @@ -3790,460 +4640,527 @@ static void test_IWinHttpRequest(int port) V_VT( &async ) = VT_BOOL; V_BOOL( &async ) = VARIANT_FALSE; - method = SysAllocString( method3W ); - url = SysAllocString( url3W ); + method = SysAllocString( L"POST" ); + url = SysAllocString( L"http://test.winehq.org/tests/post.php" ); hr = IWinHttpRequest_Open( req, method, url, async ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); SysFreeString( method ); SysFreeString( url ); V_VT( &data ) = VT_BSTR; - V_BSTR( &data ) = SysAllocString( test_dataW ); + V_BSTR( &data ) = SysAllocString( L"testdata\x80" ); hr = IWinHttpRequest_Send( req, data ); - ok( hr == S_OK || hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_INVALID_SERVER_RESPONSE ), "got %08x\n", hr ); + ok( hr == S_OK || hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_INVALID_SERVER_RESPONSE ), "got %#lx\n", hr ); SysFreeString( V_BSTR( &data ) ); if (hr != S_OK) goto done; hr = IWinHttpRequest_Open( req, NULL, NULL, empty ); - ok( hr == E_INVALIDARG, "got %08x\n", hr ); + ok( hr == E_INVALIDARG, "got %#lx\n", hr ); - method = SysAllocString( method1W ); + method = SysAllocString( L"GET" ); hr = IWinHttpRequest_Open( req, method, NULL, empty ); - ok( hr == E_INVALIDARG, "got %08x\n", hr ); + ok( hr == E_INVALIDARG, "got %#lx\n", hr ); hr = IWinHttpRequest_Open( req, method, NULL, async ); - ok( hr == E_INVALIDARG, "got %08x\n", hr ); + ok( hr == E_INVALIDARG, "got %#lx\n", hr ); - url = SysAllocString( url1W ); + url = SysAllocString( L"http://test.winehq.org" ); hr = IWinHttpRequest_Open( req, NULL, url, empty ); - ok( hr == E_INVALIDARG, "got %08x\n", hr ); + ok( hr == E_INVALIDARG, "got %#lx\n", hr ); hr = IWinHttpRequest_Abort( req ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); hr = IWinHttpRequest_Open( req, method, url, empty ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); hr = IWinHttpRequest_Abort( req ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); IWinHttpRequest_Release( req ); hr = CoCreateInstance( &CLSID_WinHttpRequest, NULL, CLSCTX_INPROC_SERVER, &IID_IWinHttpRequest, (void **)&req ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); SysFreeString( url ); - url = SysAllocString( url2W ); + url = SysAllocString( L"test.winehq.org" ); hr = IWinHttpRequest_Open( req, method, url, async ); - ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_UNRECOGNIZED_SCHEME ), "got %08x\n", hr ); + ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_UNRECOGNIZED_SCHEME ), "got %#lx\n", hr ); SysFreeString( method ); - method = SysAllocString( method2W ); + method = SysAllocString( L"INVALID" ); hr = IWinHttpRequest_Open( req, method, url, async ); - ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_UNRECOGNIZED_SCHEME ), "got %08x\n", hr ); + ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_UNRECOGNIZED_SCHEME ), "got %#lx\n", hr ); + + V_VT( &flags ) = VT_ERROR; + V_ERROR( &flags ) = 0xdeadbeef; + hr = IWinHttpRequest_get_Option( req, WinHttpRequestOption_SslErrorIgnoreFlags, &flags ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( V_VT( &flags ) == VT_I4, "got %#x\n", V_VT( &flags ) ); + ok( V_I4( &flags ) == 0, "got %lx\n", V_I4( &flags ) ); + + V_VT( &flags ) = VT_I4; + V_I4( &flags ) = SECURITY_FLAG_IGNORE_UNKNOWN_CA; + hr = IWinHttpRequest_put_Option( req, WinHttpRequestOption_SslErrorIgnoreFlags, flags ); + ok( hr == S_OK, "got %#lx\n", hr ); + + V_VT( &flags ) = VT_ERROR; + V_ERROR( &flags ) = 0xdeadbeef; + hr = IWinHttpRequest_get_Option( req, WinHttpRequestOption_SslErrorIgnoreFlags, &flags ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( V_I4( &flags ) == SECURITY_FLAG_IGNORE_UNKNOWN_CA, "got %lx\n", V_I4( &flags ) ); SysFreeString( method ); - method = SysAllocString( method1W ); + method = SysAllocString( L"GET" ); SysFreeString( url ); - url = SysAllocString( url1W ); + url = SysAllocString( L"http://test.winehq.org" ); V_VT( &async ) = VT_ERROR; V_ERROR( &async ) = DISP_E_PARAMNOTFOUND; hr = IWinHttpRequest_Open( req, method, url, async ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); V_VT( &cp ) = VT_ERROR; V_ERROR( &cp ) = 0xdeadbeef; hr = IWinHttpRequest_get_Option( req, WinHttpRequestOption_URLCodePage, &cp ); - ok( hr == S_OK, "got %08x\n", hr ); - ok( V_VT( &cp ) == VT_I4, "got %08x\n", V_VT( &cp ) ); - ok( V_I4( &cp ) == CP_UTF8, "got %u\n", V_I4( &cp ) ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( V_VT( &cp ) == VT_I4, "got %#x\n", V_VT( &cp ) ); + ok( V_I4( &cp ) == CP_UTF8, "got %ld\n", V_I4( &cp ) ); V_VT( &cp ) = VT_UI4; V_UI4( &cp ) = CP_ACP; hr = IWinHttpRequest_put_Option( req, WinHttpRequestOption_URLCodePage, cp ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); V_VT( &cp ) = VT_ERROR; V_ERROR( &cp ) = 0xdeadbeef; hr = IWinHttpRequest_get_Option( req, WinHttpRequestOption_URLCodePage, &cp ); - ok( hr == S_OK, "got %08x\n", hr ); - ok( V_VT( &cp ) == VT_I4, "got %08x\n", V_VT( &cp ) ); - ok( V_I4( &cp ) == CP_ACP, "got %u\n", V_I4( &cp ) ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( V_VT( &cp ) == VT_I4, "got %#x\n", V_VT( &cp ) ); + ok( V_I4( &cp ) == CP_ACP, "got %ld\n", V_I4( &cp ) ); - value = SysAllocString( utf8W ); + value = SysAllocString( L"utf-8" ); V_VT( &cp ) = VT_BSTR; V_BSTR( &cp ) = value; hr = IWinHttpRequest_put_Option( req, WinHttpRequestOption_URLCodePage, cp ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); SysFreeString( value ); V_VT( &cp ) = VT_ERROR; V_ERROR( &cp ) = 0xdeadbeef; hr = IWinHttpRequest_get_Option( req, WinHttpRequestOption_URLCodePage, &cp ); - ok( hr == S_OK, "got %08x\n", hr ); - ok( V_VT( &cp ) == VT_I4, "got %08x\n", V_VT( &cp ) ); - ok( V_I4( &cp ) == CP_UTF8, "got %u\n", V_I4( &cp ) ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( V_VT( &cp ) == VT_I4, "got %#x\n", V_VT( &cp ) ); + ok( V_I4( &cp ) == CP_UTF8, "got %ld\n", V_I4( &cp ) ); + + V_VT( &flags ) = VT_ERROR; + V_ERROR( &flags ) = 0xdeadbeef; + hr = IWinHttpRequest_get_Option( req, WinHttpRequestOption_SslErrorIgnoreFlags, &flags ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( V_I4( &flags ) == SECURITY_FLAG_IGNORE_UNKNOWN_CA, "got %lx\n", V_I4( &flags ) ); + + V_VT( &flags ) = VT_I4; + V_I4( &flags ) = 0x321; + hr = IWinHttpRequest_put_Option( req, WinHttpRequestOption_SslErrorIgnoreFlags, flags ); + ok( hr == E_INVALIDARG, "got %#lx\n", hr ); + + V_VT( &flags ) = VT_UI4; + V_UI4( &flags ) = 0x123; + hr = IWinHttpRequest_put_Option( req, WinHttpRequestOption_SslErrorIgnoreFlags, flags ); + ok( hr == E_INVALIDARG, "got %#lx\n", hr ); + + V_VT( &flags ) = VT_UI4; + V_UI4( &flags ) = SECURITY_FLAG_IGNORE_CERT_DATE_INVALID; + hr = IWinHttpRequest_put_Option( req, WinHttpRequestOption_SslErrorIgnoreFlags, flags); + ok( hr == S_OK, "got %#lx\n", hr ); + + V_VT( &flags ) = VT_ERROR; + V_ERROR( &flags ) = 0xdeadbeef; + hr = IWinHttpRequest_get_Option( req, WinHttpRequestOption_SslErrorIgnoreFlags, &flags ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( V_I4( &flags ) == SECURITY_FLAG_IGNORE_CERT_DATE_INVALID, "got %lx\n", V_I4( &flags ) ); + + V_VT( &flags ) = VT_I4; + V_I4( &flags ) = SECURITY_FLAG_IGNORE_UNKNOWN_CA|SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE; + hr = IWinHttpRequest_put_Option( req, WinHttpRequestOption_SslErrorIgnoreFlags, flags ); + ok( hr == S_OK, "got %#lx\n", hr ); + + V_VT( &flags ) = VT_ERROR; + V_ERROR( &flags ) = 0xdeadbeef; + hr = IWinHttpRequest_get_Option( req, WinHttpRequestOption_SslErrorIgnoreFlags, &flags ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( V_I4( &flags ) == (SECURITY_FLAG_IGNORE_UNKNOWN_CA|SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE), "got %lx\n", V_I4( &flags ) ); hr = IWinHttpRequest_Abort( req ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); hr = IWinHttpRequest_Send( req, empty ); - ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_CANNOT_CALL_BEFORE_OPEN ), "got %08x\n", hr ); + ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_CANNOT_CALL_BEFORE_OPEN ), "got %#lx\n", hr ); hr = IWinHttpRequest_Abort( req ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); IWinHttpRequest_Release( req ); hr = CoCreateInstance( &CLSID_WinHttpRequest, NULL, CLSCTX_INPROC_SERVER, &IID_IWinHttpRequest, (void **)&req ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); hr = IWinHttpRequest_get_ResponseText( req, NULL ); - ok( hr == E_INVALIDARG, "got %08x\n", hr ); + ok( hr == E_INVALIDARG, "got %#lx\n", hr ); hr = IWinHttpRequest_get_ResponseText( req, &response ); - ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND ), "got %08x\n", hr ); + ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND ), "got %#lx\n", hr ); hr = IWinHttpRequest_get_Status( req, NULL ); - ok( hr == E_INVALIDARG, "got %08x\n", hr ); + ok( hr == E_INVALIDARG, "got %#lx\n", hr ); hr = IWinHttpRequest_get_Status( req, &status ); - ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND ), "got %08x\n", hr ); + ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND ), "got %#lx\n", hr ); hr = IWinHttpRequest_get_StatusText( req, NULL ); - ok( hr == E_INVALIDARG, "got %08x\n", hr ); + ok( hr == E_INVALIDARG, "got %#lx\n", hr ); hr = IWinHttpRequest_get_StatusText( req, &status_text ); - ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND ), "got %08x\n", hr ); + ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND ), "got %#lx\n", hr ); hr = IWinHttpRequest_get_ResponseBody( req, NULL ); - ok( hr == E_INVALIDARG, "got %08x\n", hr ); + ok( hr == E_INVALIDARG, "got %#lx\n", hr ); hr = IWinHttpRequest_SetTimeouts( req, 10000, 10000, 10000, 10000 ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); hr = IWinHttpRequest_SetCredentials( req, NULL, NULL, 0xdeadbeef ); - ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_CANNOT_CALL_BEFORE_OPEN ), "got %08x\n", hr ); + ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_CANNOT_CALL_BEFORE_OPEN ), "got %#lx\n", hr ); VariantInit( &proxy_server ); V_VT( &proxy_server ) = VT_ERROR; VariantInit( &bypass_list ); V_VT( &bypass_list ) = VT_ERROR; hr = IWinHttpRequest_SetProxy( req, HTTPREQUEST_PROXYSETTING_DIRECT, proxy_server, bypass_list ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); hr = IWinHttpRequest_SetProxy( req, HTTPREQUEST_PROXYSETTING_PROXY, proxy_server, bypass_list ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); hr = IWinHttpRequest_SetProxy( req, HTTPREQUEST_PROXYSETTING_DIRECT, proxy_server, bypass_list ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); hr = IWinHttpRequest_GetAllResponseHeaders( req, NULL ); - ok( hr == E_INVALIDARG, "got %08x\n", hr ); + ok( hr == E_INVALIDARG, "got %#lx\n", hr ); hr = IWinHttpRequest_GetAllResponseHeaders( req, &headers ); - ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND ), "got %08x\n", hr ); + ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND ), "got %#lx\n", hr ); hr = IWinHttpRequest_GetResponseHeader( req, NULL, NULL ); - ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND ), "got %08x\n", hr ); + ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND ), "got %#lx\n", hr ); - connection = SysAllocString( connectionW ); + connection = SysAllocString( L"Connection" ); hr = IWinHttpRequest_GetResponseHeader( req, connection, NULL ); - ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND ), "got %08x\n", hr ); + ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND ), "got %#lx\n", hr ); hr = IWinHttpRequest_GetResponseHeader( req, connection, &value ); - ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND ), "got %08x\n", hr ); + ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND ), "got %#lx\n", hr ); hr = IWinHttpRequest_SetRequestHeader( req, NULL, NULL ); - ok( hr == E_INVALIDARG, "got %08x\n", hr ); + ok( hr == E_INVALIDARG, "got %#lx\n", hr ); - date = SysAllocString( dateW ); + date = SysAllocString( L"Date" ); hr = IWinHttpRequest_SetRequestHeader( req, date, NULL ); - ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_CANNOT_CALL_BEFORE_OPEN ), "got %08x\n", hr ); + ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_CANNOT_CALL_BEFORE_OPEN ), "got %#lx\n", hr ); today = SysAllocString( todayW ); hr = IWinHttpRequest_SetRequestHeader( req, date, today ); - ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_CANNOT_CALL_BEFORE_OPEN ), "got %08x\n", hr ); + ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_CANNOT_CALL_BEFORE_OPEN ), "got %#lx\n", hr ); hr = IWinHttpRequest_SetAutoLogonPolicy( req, 0xdeadbeef ); - ok( hr == E_INVALIDARG, "got %08x\n", hr ); + ok( hr == E_INVALIDARG, "got %#lx\n", hr ); hr = IWinHttpRequest_SetAutoLogonPolicy( req, AutoLogonPolicy_OnlyIfBypassProxy ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); SysFreeString( method ); - method = SysAllocString( method1W ); + method = SysAllocString( L"GET" ); SysFreeString( url ); - url = SysAllocString( url1W ); + url = SysAllocString( L"http://test.winehq.org" ); hr = IWinHttpRequest_Open( req, method, url, async ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); hr = IWinHttpRequest_get_ResponseText( req, NULL ); - ok( hr == E_INVALIDARG, "got %08x\n", hr ); + ok( hr == E_INVALIDARG, "got %#lx\n", hr ); hr = IWinHttpRequest_get_ResponseText( req, &response ); - ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND ), "got %08x\n", hr ); + ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND ), "got %#lx\n", hr ); hr = IWinHttpRequest_get_Status( req, &status ); - ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND ), "got %08x\n", hr ); + ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND ), "got %#lx\n", hr ); hr = IWinHttpRequest_get_StatusText( req, &status_text ); - ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND ), "got %08x\n", hr ); + ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND ), "got %#lx\n", hr ); hr = IWinHttpRequest_get_ResponseBody( req, NULL ); - ok( hr == E_INVALIDARG, "got %08x\n", hr ); + ok( hr == E_INVALIDARG, "got %#lx\n", hr ); hr = IWinHttpRequest_SetTimeouts( req, 10000, 10000, 10000, 10000 ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); hr = IWinHttpRequest_SetCredentials( req, NULL, NULL, 0xdeadbeef ); - ok( hr == E_INVALIDARG, "got %08x\n", hr ); + ok( hr == E_INVALIDARG, "got %#lx\n", hr ); - username = SysAllocString( usernameW ); + username = SysAllocString( L"username" ); hr = IWinHttpRequest_SetCredentials( req, username, NULL, 0xdeadbeef ); - ok( hr == E_INVALIDARG, "got %08x\n", hr ); + ok( hr == E_INVALIDARG, "got %#lx\n", hr ); - password = SysAllocString( passwordW ); + password = SysAllocString( L"password" ); hr = IWinHttpRequest_SetCredentials( req, NULL, password, 0xdeadbeef ); - ok( hr == E_INVALIDARG, "got %08x\n", hr ); + ok( hr == E_INVALIDARG, "got %#lx\n", hr ); hr = IWinHttpRequest_SetCredentials( req, username, password, 0xdeadbeef ); - ok( hr == E_INVALIDARG, "got %08x\n", hr ); + ok( hr == E_INVALIDARG, "got %#lx\n", hr ); hr = IWinHttpRequest_SetCredentials( req, NULL, password, HTTPREQUEST_SETCREDENTIALS_FOR_SERVER ); - ok( hr == E_INVALIDARG, "got %08x\n", hr ); + ok( hr == E_INVALIDARG, "got %#lx\n", hr ); hr = IWinHttpRequest_SetCredentials( req, username, password, HTTPREQUEST_SETCREDENTIALS_FOR_SERVER ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); + + V_VT( &flags ) = VT_I4; + V_I4( &flags ) = SECURITY_FLAG_IGNORE_UNKNOWN_CA|SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE; + hr = IWinHttpRequest_put_Option( req, WinHttpRequestOption_SslErrorIgnoreFlags, flags ); + ok( hr == S_OK, "got %#lx\n", hr ); V_VT( &proxy_server ) = VT_BSTR; - V_BSTR( &proxy_server ) = SysAllocString( proxy_serverW ); + V_BSTR( &proxy_server ) = SysAllocString( L"proxyserver" ); V_VT( &bypass_list ) = VT_BSTR; - V_BSTR( &bypass_list ) = SysAllocString( bypas_listW ); + V_BSTR( &bypass_list ) = SysAllocString( L"bypasslist" ); hr = IWinHttpRequest_SetProxy( req, HTTPREQUEST_PROXYSETTING_PROXY, proxy_server, bypass_list ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); hr = IWinHttpRequest_SetProxy( req, 0xdeadbeef, proxy_server, bypass_list ); - ok( hr == E_INVALIDARG, "got %08x\n", hr ); + ok( hr == E_INVALIDARG, "got %#lx\n", hr ); hr = IWinHttpRequest_SetProxy( req, HTTPREQUEST_PROXYSETTING_DIRECT, proxy_server, bypass_list ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); hr = IWinHttpRequest_GetAllResponseHeaders( req, &headers ); - ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND ), "got %08x\n", hr ); + ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND ), "got %#lx\n", hr ); hr = IWinHttpRequest_GetResponseHeader( req, connection, &value ); - ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND ), "got %08x\n", hr ); + ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND ), "got %#lx\n", hr ); hr = IWinHttpRequest_SetRequestHeader( req, date, today ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); hr = IWinHttpRequest_SetRequestHeader( req, date, NULL ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); hr = IWinHttpRequest_SetAutoLogonPolicy( req, AutoLogonPolicy_OnlyIfBypassProxy ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); hr = IWinHttpRequest_Send( req, empty ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); hr = IWinHttpRequest_Send( req, empty ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); + + V_VT( &flags ) = VT_ERROR; + V_ERROR( &flags ) = 0xdeadbeef; + hr = IWinHttpRequest_get_Option( req, WinHttpRequestOption_SslErrorIgnoreFlags, &flags ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( V_I4( &flags ) == (SECURITY_FLAG_IGNORE_UNKNOWN_CA|SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE), "got %lx\n", V_I4( &flags ) ); hr = IWinHttpRequest_get_ResponseText( req, NULL ); - ok( hr == E_INVALIDARG, "got %08x\n", hr ); + ok( hr == E_INVALIDARG, "got %#lx\n", hr ); hr = IWinHttpRequest_get_ResponseText( req, &response ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); ok( !memcmp(response, data_start, sizeof(data_start)), "got %s\n", wine_dbgstr_wn(response, 32) ); SysFreeString( response ); hr = IWinHttpRequest_get_Status( req, NULL ); - ok( hr == E_INVALIDARG, "got %08x\n", hr ); + ok( hr == E_INVALIDARG, "got %#lx\n", hr ); status = 0; hr = IWinHttpRequest_get_Status( req, &status ); - ok( hr == S_OK, "got %08x\n", hr ); - trace("Status=%d\n", status); + ok( hr == S_OK, "got %#lx\n", hr ); + trace("Status = %lu\n", status); hr = IWinHttpRequest_get_StatusText( req, NULL ); - ok( hr == E_INVALIDARG, "got %08x\n", hr ); + ok( hr == E_INVALIDARG, "got %#lx\n", hr ); hr = IWinHttpRequest_get_StatusText( req, &status_text ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); trace("StatusText=%s\n", wine_dbgstr_w(status_text)); SysFreeString( status_text ); hr = IWinHttpRequest_get_ResponseBody( req, NULL ); - ok( hr == E_INVALIDARG, "got %08x\n", hr ); + ok( hr == E_INVALIDARG, "got %#lx\n", hr ); hr = IWinHttpRequest_SetCredentials( req, username, password, HTTPREQUEST_SETCREDENTIALS_FOR_SERVER ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); hr = IWinHttpRequest_SetProxy( req, HTTPREQUEST_PROXYSETTING_PROXY, proxy_server, bypass_list ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); hr = IWinHttpRequest_SetProxy( req, HTTPREQUEST_PROXYSETTING_DIRECT, proxy_server, bypass_list ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); hr = IWinHttpRequest_GetAllResponseHeaders( req, NULL ); - ok( hr == E_INVALIDARG, "got %08x\n", hr ); + ok( hr == E_INVALIDARG, "got %#lx\n", hr ); hr = IWinHttpRequest_GetAllResponseHeaders( req, &headers ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); SysFreeString( headers ); hr = IWinHttpRequest_GetResponseHeader( req, NULL, NULL ); - ok( hr == E_INVALIDARG, "got %08x\n", hr ); + ok( hr == E_INVALIDARG, "got %#lx\n", hr ); hr = IWinHttpRequest_GetResponseHeader( req, connection, NULL ); - ok( hr == E_INVALIDARG, "got %08x\n", hr ); + ok( hr == E_INVALIDARG, "got %#lx\n", hr ); hr = IWinHttpRequest_GetResponseHeader( req, connection, &value ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); SysFreeString( value ); hr = IWinHttpRequest_SetRequestHeader( req, date, today ); - ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_CANNOT_CALL_AFTER_SEND ), "got %08x\n", hr ); + ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_CANNOT_CALL_AFTER_SEND ), "got %#lx\n", hr ); hr = IWinHttpRequest_SetAutoLogonPolicy( req, AutoLogonPolicy_OnlyIfBypassProxy ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); VariantInit( &timeout ); V_VT( &timeout ) = VT_I4; V_I4( &timeout ) = 10; hr = IWinHttpRequest_WaitForResponse( req, timeout, &succeeded ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); hr = IWinHttpRequest_get_Status( req, &status ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); hr = IWinHttpRequest_get_StatusText( req, &status_text ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); SysFreeString( status_text ); hr = IWinHttpRequest_SetCredentials( req, username, password, HTTPREQUEST_SETCREDENTIALS_FOR_SERVER ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); hr = IWinHttpRequest_SetProxy( req, HTTPREQUEST_PROXYSETTING_PROXY, proxy_server, bypass_list ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); hr = IWinHttpRequest_SetProxy( req, HTTPREQUEST_PROXYSETTING_DIRECT, proxy_server, bypass_list ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); hr = IWinHttpRequest_Send( req, empty ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); hr = IWinHttpRequest_get_ResponseText( req, NULL ); - ok( hr == E_INVALIDARG, "got %08x\n", hr ); + ok( hr == E_INVALIDARG, "got %#lx\n", hr ); hr = IWinHttpRequest_get_ResponseText( req, &response ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); SysFreeString( response ); hr = IWinHttpRequest_get_ResponseBody( req, NULL ); - ok( hr == E_INVALIDARG, "got %08x\n", hr ); + ok( hr == E_INVALIDARG, "got %#lx\n", hr ); VariantInit( &body ); V_VT( &body ) = VT_ERROR; hr = IWinHttpRequest_get_ResponseBody( req, &body ); - ok( hr == S_OK, "got %08x\n", hr ); - ok( V_VT( &body ) == (VT_ARRAY|VT_UI1), "got %08x\n", V_VT( &body ) ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( V_VT( &body ) == (VT_ARRAY|VT_UI1), "got %#x\n", V_VT( &body ) ); hr = VariantClear( &body ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); VariantInit( &body ); V_VT( &body ) = VT_ERROR; hr = IWinHttpRequest_get_ResponseStream( req, &body ); - ok( hr == S_OK, "got %08x\n", hr ); - ok( V_VT( &body ) == VT_UNKNOWN, "got %08x\n", V_VT( &body ) ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( V_VT( &body ) == VT_UNKNOWN, "got %#x\n", V_VT( &body ) ); hr = IUnknown_QueryInterface( V_UNKNOWN( &body ), &IID_IStream, (void **)&stream ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); ok( V_UNKNOWN( &body ) == (IUnknown *)stream, "got different interface pointer\n" ); buf[0] = 0; count = 0xdeadbeef; hr = IStream_Read( stream, buf, 128, &count ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); ok( count != 0xdeadbeef, "count not set\n" ); ok( buf[0], "no data\n" ); VariantInit( &body2 ); V_VT( &body2 ) = VT_ERROR; hr = IWinHttpRequest_get_ResponseStream( req, &body2 ); - ok( hr == S_OK, "got %08x\n", hr ); - ok( V_VT( &body2 ) == VT_UNKNOWN, "got %08x\n", V_VT( &body2 ) ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( V_VT( &body2 ) == VT_UNKNOWN, "got %#x\n", V_VT( &body2 ) ); ok( V_UNKNOWN( &body ) != V_UNKNOWN( &body2 ), "got same interface pointer\n" ); hr = IUnknown_QueryInterface( V_UNKNOWN( &body2 ), &IID_IStream, (void **)&stream2 ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); ok( V_UNKNOWN( &body2 ) == (IUnknown *)stream2, "got different interface pointer\n" ); IStream_Release( stream2 ); hr = VariantClear( &body ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); hr = VariantClear( &body2 ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); hr = IWinHttpRequest_SetProxy( req, HTTPREQUEST_PROXYSETTING_PROXY, proxy_server, bypass_list ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); hr = IWinHttpRequest_SetProxy( req, HTTPREQUEST_PROXYSETTING_DIRECT, proxy_server, bypass_list ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); hr = IWinHttpRequest_GetAllResponseHeaders( req, &headers ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); SysFreeString( headers ); hr = IWinHttpRequest_GetResponseHeader( req, connection, &value ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); SysFreeString( value ); hr = IWinHttpRequest_SetRequestHeader( req, date, today ); - ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_CANNOT_CALL_AFTER_SEND ), "got %08x\n", hr ); + ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_CANNOT_CALL_AFTER_SEND ), "got %#lx\n", hr ); hr = IWinHttpRequest_SetAutoLogonPolicy( req, AutoLogonPolicy_OnlyIfBypassProxy ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); hr = IWinHttpRequest_Send( req, empty ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); hr = IWinHttpRequest_Abort( req ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); hr = IWinHttpRequest_Abort( req ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); IWinHttpRequest_Release( req ); pos.QuadPart = 0; hr = IStream_Seek( stream, pos, STREAM_SEEK_SET, NULL ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); buf[0] = 0; count = 0xdeadbeef; hr = IStream_Read( stream, buf, 128, &count ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); ok( count != 0xdeadbeef, "count not set\n" ); ok( buf[0], "no data\n" ); IStream_Release( stream ); hr = CoCreateInstance( &CLSID_WinHttpRequest, NULL, CLSCTX_INPROC_SERVER, &IID_IWinHttpRequest, (void **)&req ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); V_VT( &async ) = VT_I4; V_I4( &async ) = 1; hr = IWinHttpRequest_Open( req, method, url, async ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); hr = IWinHttpRequest_Send( req, empty ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); hr = IWinHttpRequest_WaitForResponse( req, timeout, &succeeded ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); IWinHttpRequest_Release( req ); @@ -4258,24 +5175,25 @@ static void test_IWinHttpRequest(int port) VariantClear( &bypass_list ); hr = CoCreateInstance( &CLSID_WinHttpRequest, NULL, CLSCTX_INPROC_SERVER, &IID_IWinHttpRequest, (void **)&req ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); - url = SysAllocString( test_winehq_https ); - method = SysAllocString( method3W ); + url = SysAllocString( L"https://test.winehq.org:443" ); + method = SysAllocString( L"POST" ); V_VT( &async ) = VT_BOOL; V_BOOL( &async ) = VARIANT_FALSE; hr = IWinHttpRequest_Open( req, method, url, async ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); SysFreeString( method ); SysFreeString( url ); hr = IWinHttpRequest_Send( req, empty ); - ok( hr == S_OK || hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_INVALID_SERVER_RESPONSE ) || - hr == SEC_E_ILLEGAL_MESSAGE /* winxp */, "got %08x\n", hr ); + ok( hr == S_OK || + hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_INVALID_SERVER_RESPONSE ) || + hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_SECURE_CHANNEL_ERROR ) /* win7 */, "got %#lx\n", hr ); if (hr != S_OK) goto done; hr = IWinHttpRequest_get_ResponseText( req, &response ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); #ifdef __REACTOS__ ok( !memcmp(response, data_start, sizeof(data_start)), "got %s\n", wine_dbgstr_wn(response, min(SysStringLen(response), 32)) ); @@ -4287,37 +5205,37 @@ static void test_IWinHttpRequest(int port) IWinHttpRequest_Release( req ); hr = CoCreateInstance( &CLSID_WinHttpRequest, NULL, CLSCTX_INPROC_SERVER, &IID_IWinHttpRequest, (void **)&req ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); sprintf( buf, "http://localhost:%d/auth", port ); MultiByteToWideChar( CP_ACP, 0, buf, -1, bufW, ARRAY_SIZE( bufW )); url = SysAllocString( bufW ); - method = SysAllocString( method3W ); + method = SysAllocString( L"POST" ); V_VT( &async ) = VT_BOOL; V_BOOL( &async ) = VARIANT_FALSE; hr = IWinHttpRequest_Open( req, method, url, async ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); SysFreeString( method ); SysFreeString( url ); hr = IWinHttpRequest_get_Status( req, &status ); - ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND ), "got %08x\n", hr ); + ok( hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND ), "got %#lx\n", hr ); V_VT( &data ) = VT_BSTR; - V_BSTR( &data ) = SysAllocString( test_dataW ); + V_BSTR( &data ) = SysAllocString( L"testdata\x80" ); hr = IWinHttpRequest_Send( req, data ); - ok( hr == S_OK, "got %08x\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); SysFreeString( V_BSTR( &data ) ); hr = IWinHttpRequest_get_ResponseText( req, &response ); - ok( hr == S_OK, "got %08x\n", hr ); - ok( !memcmp( response, unauthW, sizeof(unauthW) ), "got %s\n", wine_dbgstr_w(response) ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( !memcmp( response, L"Unauthorized", sizeof(L"Unauthorized") ), "got %s\n", wine_dbgstr_w(response) ); SysFreeString( response ); status = 0xdeadbeef; hr = IWinHttpRequest_get_Status( req, &status ); - ok( hr == S_OK, "got %08x\n", hr ); - ok( status == HTTP_STATUS_DENIED, "got %d\n", status ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( status == HTTP_STATUS_DENIED, "got %lu\n", status ); done: IWinHttpRequest_Release( req ); @@ -4341,13 +5259,11 @@ static void request_get_property(IWinHttpRequest *request, int property, VARIANT VariantInit(ret); hr = IWinHttpRequest_Invoke(request, DISPID_HTTPREQUEST_OPTION, &IID_NULL, 0, DISPATCH_PROPERTYGET, ¶ms, ret, NULL, NULL); - ok(hr == S_OK, "error %#x\n", hr); + ok(hr == S_OK, "error %#lx\n", hr); } static void test_IWinHttpRequest_Invoke(void) { - static const WCHAR utf8W[] = {'U','T','F','-','8',0}; - static const WCHAR regid[] = {'W','i','n','H','t','t','p','.','W','i','n','H','t','t','p','R','e','q','u','e','s','t','.','5','.','1',0}; WCHAR openW[] = {'O','p','e','n',0}; WCHAR optionW[] = {'O','p','t','i','o','n',0}; OLECHAR *open = openW, *option = optionW; @@ -4364,29 +5280,29 @@ static void test_IWinHttpRequest_Invoke(void) CoInitialize(NULL); - hr = CLSIDFromProgID(regid, &clsid); - ok(hr == S_OK, "CLSIDFromProgID error %#x\n", hr); + hr = CLSIDFromProgID(L"WinHttp.WinHttpRequest.5.1", &clsid); + ok(hr == S_OK, "CLSIDFromProgID error %#lx\n", hr); bret = IsEqualIID(&clsid, &CLSID_WinHttpRequest); ok(bret || broken(!bret) /* win2003 */, "not expected %s\n", wine_dbgstr_guid(&clsid)); hr = CoCreateInstance(&CLSID_WinHttpRequest, 0, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&request); - ok(hr == S_OK, "error %#x\n", hr); + ok(hr == S_OK, "error %#lx\n", hr); hr = IWinHttpRequest_QueryInterface(request, &IID_IDispatch, (void **)&dispatch); - ok(hr == S_OK, "error %#x\n", hr); + ok(hr == S_OK, "error %#lx\n", hr); IDispatch_Release(dispatch); hr = IWinHttpRequest_GetIDsOfNames(request, &IID_NULL, &open, 1, 0x0409, &id); - ok(hr == S_OK, "error %#x\n", hr); - ok(id == DISPID_HTTPREQUEST_OPEN, "expected DISPID_HTTPREQUEST_OPEN, got %u\n", id); + ok(hr == S_OK, "error %#lx\n", hr); + ok(id == DISPID_HTTPREQUEST_OPEN, "expected DISPID_HTTPREQUEST_OPEN, got %lu\n", id); hr = IWinHttpRequest_GetIDsOfNames(request, &IID_NULL, &option, 1, 0x0409, &id); - ok(hr == S_OK, "error %#x\n", hr); - ok(id == DISPID_HTTPREQUEST_OPTION, "expected DISPID_HTTPREQUEST_OPTION, got %u\n", id); + ok(hr == S_OK, "error %#lx\n", hr); + ok(id == DISPID_HTTPREQUEST_OPTION, "expected DISPID_HTTPREQUEST_OPTION, got %lu\n", id); request_get_property(request, WinHttpRequestOption_URLCodePage, &ret); - ok(V_VT(&ret) == VT_I4, "expected VT_I4, got %d\n", V_VT(&ret)); - ok(V_I4(&ret) == CP_UTF8, "expected CP_UTF8, got %d\n", V_I4(&ret)); + ok(V_VT(&ret) == VT_I4, "expected VT_I4, got %#x\n", V_VT(&ret)); + ok(V_I4(&ret) == CP_UTF8, "expected CP_UTF8, got %ld\n", V_I4(&ret)); memset(¶ms, 0, sizeof(params)); params.cArgs = 2; @@ -4399,11 +5315,11 @@ static void test_IWinHttpRequest_Invoke(void) VariantInit(&ret); hr = IWinHttpRequest_Invoke(request, DISPID_HTTPREQUEST_OPTION, &IID_NULL, 0, DISPATCH_METHOD, ¶ms, NULL, NULL, &err); - ok(hr == S_OK, "error %#x\n", hr); + ok(hr == S_OK, "error %#lx\n", hr); request_get_property(request, WinHttpRequestOption_URLCodePage, &ret); - ok(V_VT(&ret) == VT_I4, "expected VT_I4, got %d\n", V_VT(&ret)); - ok(V_I4(&ret) == CP_UTF8, "expected CP_UTF8, got %d\n", V_I4(&ret)); + ok(V_VT(&ret) == VT_I4, "expected VT_I4, got %#x\n", V_VT(&ret)); + ok(V_I4(&ret) == CP_UTF8, "expected CP_UTF8, got %ld\n", V_I4(&ret)); memset(¶ms, 0, sizeof(params)); params.cArgs = 2; @@ -4416,11 +5332,11 @@ static void test_IWinHttpRequest_Invoke(void) VariantInit(&ret); hr = IWinHttpRequest_Invoke(request, DISPID_HTTPREQUEST_OPTION, &IID_NULL, 0, DISPATCH_METHOD | DISPATCH_PROPERTYPUT, ¶ms, NULL, NULL, &err); - ok(hr == S_OK, "error %#x\n", hr); + ok(hr == S_OK, "error %#lx\n", hr); request_get_property(request, WinHttpRequestOption_URLCodePage, &ret); - ok(V_VT(&ret) == VT_I4, "expected VT_I4, got %d\n", V_VT(&ret)); - ok(V_I4(&ret) == CP_UTF8, "expected CP_UTF8, got %d\n", V_I4(&ret)); + ok(V_VT(&ret) == VT_I4, "expected VT_I4, got %#x\n", V_VT(&ret)); + ok(V_I4(&ret) == CP_UTF8, "expected CP_UTF8, got %ld\n", V_I4(&ret)); memset(¶ms, 0, sizeof(params)); params.cArgs = 2; @@ -4433,53 +5349,53 @@ static void test_IWinHttpRequest_Invoke(void) VariantInit(&ret); hr = IWinHttpRequest_Invoke(request, DISPID_HTTPREQUEST_OPTION, &IID_NULL, 0, DISPATCH_PROPERTYPUT, ¶ms, NULL, NULL, &err); - ok(hr == S_OK, "error %#x\n", hr); + ok(hr == S_OK, "error %#lx\n", hr); request_get_property(request, WinHttpRequestOption_URLCodePage, &ret); - ok(V_VT(&ret) == VT_I4, "expected VT_I4, got %d\n", V_VT(&ret)); - ok(V_I4(&ret) == 1252, "expected 1252, got %d\n", V_I4(&ret)); + ok(V_VT(&ret) == VT_I4, "expected VT_I4, got %#x\n", V_VT(&ret)); + ok(V_I4(&ret) == 1252, "expected 1252, got %ld\n", V_I4(&ret)); memset(¶ms, 0, sizeof(params)); params.cArgs = 2; params.cNamedArgs = 0; params.rgvarg = arg; V_VT(&arg[0]) = VT_BSTR; - utf8 = SysAllocString(utf8W); + utf8 = SysAllocString(L"UTF-8"); V_BSTR(&arg[0]) = utf8; V_VT(&arg[1]) = VT_R8; V_R8(&arg[1]) = 2.0; /* WinHttpRequestOption_URLCodePage */ hr = IWinHttpRequest_Invoke(request, id, &IID_NULL, 0, DISPATCH_METHOD, ¶ms, NULL, NULL, &err); - ok(hr == S_OK, "error %#x\n", hr); + ok(hr == S_OK, "error %#lx\n", hr); request_get_property(request, WinHttpRequestOption_URLCodePage, &ret); - ok(V_VT(&ret) == VT_I4, "expected VT_I4, got %d\n", V_VT(&ret)); - ok(V_I4(&ret) == 1252, "expected 1252, got %d\n", V_I4(&ret)); + ok(V_VT(&ret) == VT_I4, "expected VT_I4, got %#x\n", V_VT(&ret)); + ok(V_I4(&ret) == 1252, "expected 1252, got %ld\n", V_I4(&ret)); VariantInit(&ret); hr = IWinHttpRequest_Invoke(request, id, &IID_NULL, 0, DISPATCH_METHOD, ¶ms, &ret, NULL, &err); - ok(hr == S_OK, "error %#x\n", hr); + ok(hr == S_OK, "error %#lx\n", hr); request_get_property(request, WinHttpRequestOption_URLCodePage, &ret); - ok(V_VT(&ret) == VT_I4, "expected VT_I4, got %d\n", V_VT(&ret)); - ok(V_I4(&ret) == 1252, "expected 1252, got %d\n", V_I4(&ret)); + ok(V_VT(&ret) == VT_I4, "expected VT_I4, got %#x\n", V_VT(&ret)); + ok(V_I4(&ret) == 1252, "expected 1252, got %ld\n", V_I4(&ret)); VariantInit(&ret); hr = IWinHttpRequest_Invoke(request, id, &IID_NULL, 0, DISPATCH_PROPERTYPUT, ¶ms, &ret, NULL, &err); - ok(hr == S_OK, "error %#x\n", hr); + ok(hr == S_OK, "error %#lx\n", hr); request_get_property(request, WinHttpRequestOption_URLCodePage, &ret); - ok(V_VT(&ret) == VT_I4, "expected VT_I4, got %d\n", V_VT(&ret)); - ok(V_I4(&ret) == CP_UTF8, "expected CP_UTF8, got %d\n", V_I4(&ret)); + ok(V_VT(&ret) == VT_I4, "expected VT_I4, got %#x\n", V_VT(&ret)); + ok(V_I4(&ret) == CP_UTF8, "expected CP_UTF8, got %ld\n", V_I4(&ret)); hr = IWinHttpRequest_Invoke(request, DISPID_HTTPREQUEST_OPTION, &IID_NULL, 0, DISPATCH_PROPERTYPUT, ¶ms, NULL, NULL, NULL); - ok(hr == S_OK, "error %#x\n", hr); + ok(hr == S_OK, "error %#lx\n", hr); hr = IWinHttpRequest_Invoke(request, 255, &IID_NULL, 0, DISPATCH_PROPERTYPUT, ¶ms, NULL, NULL, NULL); - ok(hr == DISP_E_MEMBERNOTFOUND, "error %#x\n", hr); + ok(hr == DISP_E_MEMBERNOTFOUND, "error %#lx\n", hr); VariantInit(&ret); hr = IWinHttpRequest_Invoke(request, DISPID_HTTPREQUEST_OPTION, &IID_IUnknown, 0, DISPATCH_PROPERTYPUT, ¶ms, &ret, NULL, &err); - ok(hr == DISP_E_UNKNOWNINTERFACE, "error %#x\n", hr); + ok(hr == DISP_E_UNKNOWNINTERFACE, "error %#lx\n", hr); VariantInit(&ret); if (0) /* crashes */ @@ -4487,13 +5403,13 @@ static void test_IWinHttpRequest_Invoke(void) params.cArgs = 1; hr = IWinHttpRequest_Invoke(request, DISPID_HTTPREQUEST_OPTION, &IID_NULL, 0, DISPATCH_PROPERTYPUT, ¶ms, &ret, NULL, &err); - ok(hr == DISP_E_TYPEMISMATCH, "error %#x\n", hr); + ok(hr == DISP_E_TYPEMISMATCH, "error %#lx\n", hr); VariantInit(&arg[2]); params.cArgs = 3; hr = IWinHttpRequest_Invoke(request, DISPID_HTTPREQUEST_OPTION, &IID_NULL, 0, DISPATCH_PROPERTYPUT, ¶ms, &ret, NULL, &err); -todo_wine - ok(hr == S_OK, "error %#x\n", hr); + todo_wine + ok(hr == S_OK, "error %#lx\n", hr); VariantInit(&arg[0]); VariantInit(&arg[1]); @@ -4503,46 +5419,46 @@ todo_wine V_VT(&arg[0]) = VT_I4; V_I4(&arg[0]) = WinHttpRequestOption_URLCodePage; hr = IWinHttpRequest_Invoke(request, DISPID_HTTPREQUEST_OPTION, &IID_NULL, 0, DISPATCH_PROPERTYGET, ¶ms, NULL, NULL, NULL); - ok(hr == S_OK, "error %#x\n", hr); + ok(hr == S_OK, "error %#lx\n", hr); V_VT(&ret) = 0xdead; V_I4(&ret) = 0xbeef; hr = IWinHttpRequest_Invoke(request, DISPID_HTTPREQUEST_OPTION, &IID_NULL, 0, DISPATCH_METHOD|DISPATCH_PROPERTYGET, ¶ms, &ret, NULL, NULL); - ok(hr == S_OK, "error %#x\n", hr); - ok(V_VT(&ret) == VT_I4, "expected VT_I4, got %d\n", V_VT(&ret)); - ok(V_I4(&ret) == CP_UTF8, "expected CP_UTF8, got %d\n", V_I4(&ret)); + ok(hr == S_OK, "error %#lx\n", hr); + ok(V_VT(&ret) == VT_I4, "expected VT_I4, got %#x\n", V_VT(&ret)); + ok(V_I4(&ret) == CP_UTF8, "expected CP_UTF8, got %ld\n", V_I4(&ret)); V_VT(&ret) = 0xdead; V_I4(&ret) = 0xbeef; hr = IWinHttpRequest_Invoke(request, DISPID_HTTPREQUEST_OPTION, &IID_NULL, 0, DISPATCH_METHOD, ¶ms, &ret, NULL, NULL); - ok(hr == S_OK, "error %#x\n", hr); - ok(V_VT(&ret) == VT_I4, "expected VT_I4, got %d\n", V_VT(&ret)); - ok(V_I4(&ret) == CP_UTF8, "expected CP_UTF8, got %d\n", V_I4(&ret)); + ok(hr == S_OK, "error %#lx\n", hr); + ok(V_VT(&ret) == VT_I4, "expected VT_I4, got %#x\n", V_VT(&ret)); + ok(V_I4(&ret) == CP_UTF8, "expected CP_UTF8, got %ld\n", V_I4(&ret)); hr = IWinHttpRequest_Invoke(request, DISPID_HTTPREQUEST_OPTION, &IID_NULL, 0, DISPATCH_METHOD|DISPATCH_PROPERTYGET, ¶ms, NULL, NULL, NULL); - ok(hr == S_OK, "error %#x\n", hr); + ok(hr == S_OK, "error %#lx\n", hr); V_VT(&ret) = 0xdead; V_I4(&ret) = 0xbeef; hr = IWinHttpRequest_Invoke(request, DISPID_HTTPREQUEST_OPTION, &IID_NULL, 0, 0, ¶ms, &ret, NULL, NULL); - ok(hr == S_OK, "error %#x\n", hr); - ok(V_VT(&ret) == VT_EMPTY, "expected VT_EMPTY, got %d\n", V_VT(&ret)); - ok(V_I4(&ret) == 0xbeef || V_I4(&ret) == 0 /* Win8 */, "expected 0xdead, got %d\n", V_I4(&ret)); + ok(hr == S_OK, "error %#lx\n", hr); + ok(V_VT(&ret) == VT_EMPTY, "expected VT_EMPTY, got %#x\n", V_VT(&ret)); + ok(V_I4(&ret) == 0xbeef || V_I4(&ret) == 0 /* Win8 */, "expected 0xdead, got %ld\n", V_I4(&ret)); hr = IWinHttpRequest_Invoke(request, DISPID_HTTPREQUEST_OPTION, &IID_NULL, 0, 0, ¶ms, NULL, NULL, NULL); - ok(hr == S_OK, "error %#x\n", hr); + ok(hr == S_OK, "error %#lx\n", hr); hr = IWinHttpRequest_Invoke(request, DISPID_HTTPREQUEST_OPTION, &IID_IUnknown, 0, DISPATCH_PROPERTYGET, ¶ms, NULL, NULL, NULL); - ok(hr == DISP_E_UNKNOWNINTERFACE, "error %#x\n", hr); + ok(hr == DISP_E_UNKNOWNINTERFACE, "error %#lx\n", hr); params.cArgs = 2; hr = IWinHttpRequest_Invoke(request, DISPID_HTTPREQUEST_OPTION, &IID_NULL, 0, DISPATCH_PROPERTYGET, ¶ms, NULL, NULL, NULL); -todo_wine - ok(hr == S_OK, "error %#x\n", hr); + todo_wine + ok(hr == S_OK, "error %#lx\n", hr); params.cArgs = 0; hr = IWinHttpRequest_Invoke(request, DISPID_HTTPREQUEST_OPTION, &IID_NULL, 0, DISPATCH_PROPERTYGET, ¶ms, NULL, NULL, NULL); - ok(hr == DISP_E_PARAMNOTFOUND, "error %#x\n", hr); + ok(hr == DISP_E_PARAMNOTFOUND, "error %#lx\n", hr); SysFreeString(utf8); @@ -4552,7 +5468,7 @@ todo_wine VariantInit(&ret); hr = IWinHttpRequest_Invoke(request, DISPID_HTTPREQUEST_SETAUTOLOGONPOLICY, &IID_NULL, 0, DISPATCH_METHOD, ¶ms, &ret, NULL, NULL); - ok(hr == S_OK, "error %#x\n", hr); + ok(hr == S_OK, "error %#lx\n", hr); IWinHttpRequest_Release(request); @@ -4569,20 +5485,20 @@ static void test_WinHttpDetectAutoProxyConfigUrl(void) ret = WinHttpDetectAutoProxyConfigUrl( 0, NULL ); error = GetLastError(); ok( !ret, "expected failure\n" ); - ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + ok( error == ERROR_INVALID_PARAMETER, "got %lu\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 ); + ok( error == ERROR_INVALID_PARAMETER, "got %lu\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 ); + ok( error == ERROR_INVALID_PARAMETER, "got %lu\n", error ); url = (WCHAR *)0xdeadbeef; SetLastError(0xdeadbeef); @@ -4590,7 +5506,7 @@ static void test_WinHttpDetectAutoProxyConfigUrl(void) error = GetLastError(); if (!ret) { - ok( error == ERROR_WINHTTP_AUTODETECTION_FAILED, "got %u\n", error ); + ok( error == ERROR_WINHTTP_AUTODETECTION_FAILED, "got %lu\n", error ); ok( !url || broken(url == (WCHAR *)0xdeadbeef), "got %p\n", url ); } else @@ -4605,12 +5521,12 @@ static void test_WinHttpDetectAutoProxyConfigUrl(void) error = GetLastError(); if (!ret) { - ok( error == ERROR_WINHTTP_AUTODETECTION_FAILED, "got %u\n", error ); + ok( error == ERROR_WINHTTP_AUTODETECTION_FAILED, "got %lu\n", error ); ok( !url || broken(url == (WCHAR *)0xdeadbeef), "got %p\n", url ); } else { - ok( error == ERROR_SUCCESS, "got %u\n", error ); + ok( error == ERROR_SUCCESS, "got %lu\n", error ); trace("%s\n", wine_dbgstr_w(url)); GlobalFree( url ); } @@ -4628,13 +5544,13 @@ static void test_WinHttpGetIEProxyConfigForCurrentUser(void) ret = WinHttpGetIEProxyConfigForCurrentUser( NULL ); error = GetLastError(); ok( !ret, "expected failure\n" ); - ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + ok( error == ERROR_INVALID_PARAMETER, "got %lu\n", error ); SetLastError(0xdeadbeef); ret = WinHttpGetIEProxyConfigForCurrentUser( &cfg ); error = GetLastError(); ok( ret, "expected success\n" ); - ok( error == ERROR_SUCCESS || broken(error == ERROR_NO_TOKEN) /* < win7 */, "got %u\n", error ); + ok( error == ERROR_SUCCESS || broken(error == ERROR_NO_TOKEN) /* < win7 */, "got %lu\n", error ); trace("IEProxy.AutoDetect=%d\n", cfg.fAutoDetect); trace("IEProxy.AutoConfigUrl=%s\n", wine_dbgstr_w(cfg.lpszAutoConfigUrl)); @@ -4645,12 +5561,10 @@ static void test_WinHttpGetIEProxyConfigForCurrentUser(void) GlobalFree( cfg.lpszProxyBypass ); } -static void test_WinHttpGetProxyForUrl(void) +static void test_WinHttpGetProxyForUrl(int port) { - static const WCHAR urlW[] = {'h','t','t','p',':','/','/','w','i','n','e','h','q','.','o','r','g',0}; - static const WCHAR wpadW[] = {'h','t','t','p',':','/','/','w','p','a','d','/','w','p','a','d','.','d','a','t',0}; - static const WCHAR emptyW[] = {0}; - BOOL ret; + WCHAR pac_url[64]; + BOOL ret, old_winhttp = FALSE; DWORD error; HINTERNET session; WINHTTP_AUTOPROXY_OPTIONS options; @@ -4662,100 +5576,173 @@ static void test_WinHttpGetProxyForUrl(void) ret = WinHttpGetProxyForUrl( NULL, NULL, NULL, NULL ); error = GetLastError(); ok( !ret, "expected failure\n" ); - ok( error == ERROR_INVALID_HANDLE, "got %u\n", error ); + ok( error == ERROR_INVALID_HANDLE, "got %lu\n", error ); - session = WinHttpOpen( test_useragent, 0, NULL, NULL, 0 ); - ok( session != NULL, "failed to open session %u\n", GetLastError() ); + session = WinHttpOpen( L"winetest", 0, NULL, NULL, 0 ); + ok( session != NULL, "failed to open session %lu\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 ); + ok( error == ERROR_INVALID_PARAMETER, "got %lu\n", error ); SetLastError(0xdeadbeef); - ret = WinHttpGetProxyForUrl( session, emptyW, NULL, NULL ); + ret = WinHttpGetProxyForUrl( session, L"", NULL, NULL ); error = GetLastError(); ok( !ret, "expected failure\n" ); - ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + ok( error == ERROR_INVALID_PARAMETER, "got %lu\n", error ); SetLastError(0xdeadbeef); - ret = WinHttpGetProxyForUrl( session, urlW, NULL, NULL ); + ret = WinHttpGetProxyForUrl( session, L"http://winehq.org", NULL, NULL ); error = GetLastError(); ok( !ret, "expected failure\n" ); - ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + ok( error == ERROR_INVALID_PARAMETER, "got %lu\n", error ); SetLastError(0xdeadbeef); - ret = WinHttpGetProxyForUrl( session, urlW, &options, &info ); + ret = WinHttpGetProxyForUrl( session, L"http://winehq.org", &options, &info ); error = GetLastError(); ok( !ret, "expected failure\n" ); - ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + ok( error == ERROR_INVALID_PARAMETER, "got %lu\n", error ); options.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT; options.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DNS_A; SetLastError(0xdeadbeef); - ret = WinHttpGetProxyForUrl( session, urlW, &options, NULL ); + ret = WinHttpGetProxyForUrl( session, L"http://winehq.org", &options, NULL ); error = GetLastError(); ok( !ret, "expected failure\n" ); - ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + ok( error == ERROR_INVALID_PARAMETER, "got %lu\n", error ); options.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT; options.dwAutoDetectFlags = 0; SetLastError(0xdeadbeef); - ret = WinHttpGetProxyForUrl( session, urlW, &options, &info ); + ret = WinHttpGetProxyForUrl( session, L"http://winehq.org", &options, &info ); error = GetLastError(); ok( !ret, "expected failure\n" ); - ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + ok( error == ERROR_INVALID_PARAMETER, "got %lu\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 ); + ret = WinHttpGetProxyForUrl( session, L"http://winehq.org", &options, &info ); error = GetLastError(); ok( !ret, "expected failure\n" ); - ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + ok( error == ERROR_INVALID_PARAMETER, "got %lu\n", error ); options.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT; options.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DNS_A; memset( &info, 0, sizeof(info) ); SetLastError(0xdeadbeef); - ret = WinHttpGetProxyForUrl( session, urlW, &options, &info ); + ret = WinHttpGetProxyForUrl( session, L"http://winehq.org", &options, &info ); error = GetLastError(); if (ret) { - ok( error == ERROR_SUCCESS, "got %u\n", error ); - trace("Proxy.AccessType=%u\n", info.dwAccessType); + ok( error == ERROR_SUCCESS, "got %lu\n", error ); + trace("Proxy.AccessType=%lu\n", info.dwAccessType); trace("Proxy.Proxy=%s\n", wine_dbgstr_w(info.lpszProxy)); trace("Proxy.ProxyBypass=%s\n", wine_dbgstr_w(info.lpszProxyBypass)); GlobalFree( info.lpszProxy ); GlobalFree( info.lpszProxyBypass ); + + ret = WinHttpGetProxyForUrl( session, L"http:", &options, &info ); + ok( !ret, "expected failure\n" ); } options.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL; options.dwAutoDetectFlags = 0; - options.lpszAutoConfigUrl = wpadW; + options.lpszAutoConfigUrl = L"http://wpad/wpad.dat"; memset( &info, 0, sizeof(info) ); - ret = WinHttpGetProxyForUrl( session, urlW, &options, &info ); + ret = WinHttpGetProxyForUrl( session, L"http://winehq.org", &options, &info ); if (ret) { - trace("Proxy.AccessType=%u\n", info.dwAccessType); + trace("Proxy.AccessType=%lu\n", info.dwAccessType); trace("Proxy.Proxy=%s\n", wine_dbgstr_w(info.lpszProxy)); trace("Proxy.ProxyBypass=%s\n", wine_dbgstr_w(info.lpszProxyBypass)); GlobalFree( info.lpszProxy ); GlobalFree( info.lpszProxyBypass ); } + + options.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT|WINHTTP_AUTOPROXY_CONFIG_URL; + options.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP|WINHTTP_AUTO_DETECT_TYPE_DNS_A; + options.lpszAutoConfigUrl = L"http://wpad/wpad.dat"; + + SetLastError(0xdeadbeef); + memset( &info, 0, sizeof(info) ); + ret = WinHttpGetProxyForUrl( session, L"http://winehq.org", &options, &info ); + error = GetLastError(); + ok( error != ERROR_INVALID_PARAMETER, "got ERROR_INVALID_PARAMETER\n" ); + if (ret) + { + GlobalFree( info.lpszProxy ); + GlobalFree( info.lpszProxyBypass ); + } + + options.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT; + options.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP|WINHTTP_AUTO_DETECT_TYPE_DNS_A; + + ret = WinHttpGetProxyForUrl( session, L"http:", &options, &info ); + ok( !ret, "expected failure\n" ); + + swprintf(pac_url, ARRAY_SIZE(pac_url), L"http://localhost:%d/proxy.pac?ver=1", port); + options.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL | WINHTTP_AUTOPROXY_NO_CACHE_SVC; + options.dwAutoDetectFlags = 0; + options.lpszAutoConfigUrl = pac_url; + + ret = WinHttpGetProxyForUrl( session, L"HTTP://WINEHQ.ORG/Test.html", &options, &info); + if (!ret) + { + old_winhttp = TRUE; + options.dwFlags &= ~WINHTTP_AUTOPROXY_NO_CACHE_SVC; + ret = WinHttpGetProxyForUrl( session, L"HTTP://WINEHQ.ORG/Test.html", &options, &info); + } + ok(ret, "expected success\n" ); + ok(info.dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY, + "info.dwAccessType = %lu\n", info.dwAccessType); + ok(!wcscmp(info.lpszProxy, L"http___WINEHQ.ORG_Test.html_WINEHQ.ORG:8080") || + broken(old_winhttp && !wcscmp(info.lpszProxy, L"HTTP___WINEHQ.ORG_Test.html_WINEHQ.ORG:8080")), + "info.Proxy = %s\n", wine_dbgstr_w(info.lpszProxy)); + ok(!info.lpszProxyBypass, "info.ProxyBypass = %s\n", + wine_dbgstr_w(info.lpszProxyBypass)); + GlobalFree( info.lpszProxy ); + + options.dwFlags |= WINHTTP_AUTOPROXY_HOST_LOWERCASE; + + ret = WinHttpGetProxyForUrl( session, L"HTTP://WINEHQ.ORG/Test.html", &options, &info); + ok(ret, "expected success\n" ); + ok(info.dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY, + "info.dwAccessType = %lu\n", info.dwAccessType); + ok(!wcscmp(info.lpszProxy, L"http___winehq.org_Test.html_winehq.org:8080") || + broken(old_winhttp && !wcscmp(info.lpszProxy, L"HTTP___winehq.org_Test.html_winehq.org:8080")), + "info.Proxy = %s\n", wine_dbgstr_w(info.lpszProxy)); + ok(!info.lpszProxyBypass, "info.ProxyBypass = %s\n", + wine_dbgstr_w(info.lpszProxyBypass)); + GlobalFree( info.lpszProxy ); + + if (!old_winhttp) + { + options.dwFlags |= WINHTTP_AUTOPROXY_HOST_KEEPCASE; + + ret = WinHttpGetProxyForUrl( session, L"HTTP://WINEHQ.ORG/Test.html", &options, &info); + ok(ret, "expected success\n" ); + ok(info.dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY, + "info.dwAccessType = %lu\n", info.dwAccessType); + ok(!wcscmp(info.lpszProxy, L"http___WINEHQ.ORG_Test.html_WINEHQ.ORG:8080"), + "info.Proxy = %s\n", wine_dbgstr_w(info.lpszProxy)); + ok(!info.lpszProxyBypass, "info.ProxyBypass = %s\n", + wine_dbgstr_w(info.lpszProxyBypass)); + GlobalFree( info.lpszProxy ); + } + WinHttpCloseHandle( session ); } static void test_chunked_read(void) { - static const WCHAR verb[] = {'/','t','e','s','t','s','/','c','h','u','n','k','e','d',0}; - static const WCHAR chunked[] = {'c','h','u','n','k','e','d',0}; WCHAR header[32]; DWORD len, err; HINTERNET ses, con = NULL, req = NULL; @@ -4763,16 +5750,16 @@ static void test_chunked_read(void) trace( "starting chunked read test\n" ); - ses = WinHttpOpen( test_useragent, 0, NULL, NULL, 0 ); - ok( ses != NULL, "WinHttpOpen failed with error %u\n", GetLastError() ); + ses = WinHttpOpen( L"winetest", 0, NULL, NULL, 0 ); + ok( ses != NULL, "WinHttpOpen failed with error %lu\n", GetLastError() ); if (!ses) goto done; - con = WinHttpConnect( ses, test_winehq, 0, 0 ); - ok( con != NULL, "WinHttpConnect failed with error %u\n", GetLastError() ); + con = WinHttpConnect( ses, L"test.winehq.org", 0, 0 ); + ok( con != NULL, "WinHttpConnect failed with error %lu\n", GetLastError() ); if (!con) goto done; - req = WinHttpOpenRequest( con, NULL, verb, NULL, NULL, NULL, 0 ); - ok( req != NULL, "WinHttpOpenRequest failed with error %u\n", GetLastError() ); + req = WinHttpOpenRequest( con, NULL, L"/tests/chunked", NULL, NULL, NULL, 0 ); + ok( req != NULL, "WinHttpOpenRequest failed with error %lu\n", GetLastError() ); if (!req) goto done; ret = WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 ); @@ -4782,18 +5769,18 @@ static void test_chunked_read(void) skip("connection failed, skipping\n"); goto done; } - ok( ret, "WinHttpSendRequest failed with error %u\n", GetLastError() ); + ok( ret, "WinHttpSendRequest failed with error %lu\n", GetLastError() ); if (!ret) goto done; ret = WinHttpReceiveResponse( req, NULL ); - ok( ret, "WinHttpReceiveResponse failed with error %u\n", GetLastError() ); + ok( ret, "WinHttpReceiveResponse failed with error %lu\n", GetLastError() ); if (!ret) goto done; header[0] = 0; len = sizeof(header); ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_TRANSFER_ENCODING, NULL, header, &len, 0 ); - ok( ret, "failed to get TRANSFER_ENCODING header (error %u)\n", GetLastError() ); - ok( !lstrcmpW( header, chunked ), "wrong transfer encoding %s\n", wine_dbgstr_w(header) ); + ok( ret, "failed to get TRANSFER_ENCODING header with error %lu\n", GetLastError() ); + ok( !lstrcmpW( header, L"chunked" ), "wrong transfer encoding %s\n", wine_dbgstr_w(header) ); trace( "transfer encoding: %s\n", wine_dbgstr_w(header) ); header[0] = 0; @@ -4801,27 +5788,27 @@ static void test_chunked_read(void) SetLastError( 0xdeadbeef ); ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_CONTENT_LENGTH, NULL, &header, &len, 0 ); ok( !ret, "unexpected CONTENT_LENGTH header %s\n", wine_dbgstr_w(header) ); - ok( GetLastError() == ERROR_WINHTTP_HEADER_NOT_FOUND, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_WINHTTP_HEADER_NOT_FOUND, "wrong error %lu\n", GetLastError() ); trace( "entering query loop\n" ); for (;;) { len = 0xdeadbeef; ret = WinHttpQueryDataAvailable( req, &len ); - ok( ret, "WinHttpQueryDataAvailable failed with error %u\n", GetLastError() ); + ok( ret, "WinHttpQueryDataAvailable failed with error %lu\n", GetLastError() ); if (ret) ok( len != 0xdeadbeef, "WinHttpQueryDataAvailable return wrong length\n" ); - trace( "got %u available\n", len ); + trace( "got %lu available\n", len ); if (len) { DWORD bytes_read; char *buf = HeapAlloc( GetProcessHeap(), 0, len + 1 ); ret = WinHttpReadData( req, buf, len, &bytes_read ); - ok(ret, "WinHttpReadData failed: %u.\n", GetLastError()); + ok(ret, "WinHttpReadData failed: %lu\n", GetLastError()); buf[bytes_read] = 0; - trace( "WinHttpReadData -> %d %u\n", ret, bytes_read ); - ok( len == bytes_read, "only got %u of %u available\n", bytes_read, len ); + trace( "WinHttpReadData -> %d %lu\n", ret, bytes_read ); + ok( len == bytes_read, "only got %lu of %lu available\n", bytes_read, len ); ok( buf[bytes_read - 1] == '\n', "received partial line '%s'\n", buf ); HeapFree( GetProcessHeap(), 0, buf ); @@ -4837,20 +5824,452 @@ done: if (ses) WinHttpCloseHandle( ses ); } +static void test_max_http_automatic_redirects (void) +{ + HINTERNET session, request, connection; + DWORD max_redirects, err, size; + WCHAR url[128]; + BOOL ret; + + session = WinHttpOpen(L"winetest", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); + ok(session != NULL, "WinHttpOpen failed to open session.\n"); + + connection = WinHttpConnect (session, L"test.winehq.org", INTERNET_DEFAULT_HTTP_PORT, 0); + ok(connection != NULL, "WinHttpConnect failed to open a connection, error: %lu\n", GetLastError()); + + /* Test with 2 redirects (page will try to redirect 3 times) */ + request = WinHttpOpenRequest(connection, L"GET", L"tests/redirecttest.php?max=3", NULL, WINHTTP_NO_REFERER, + WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_BYPASS_PROXY_CACHE); + if (request == NULL && GetLastError() == ERROR_WINHTTP_NAME_NOT_RESOLVED) + { + skip("Network unreachable, skipping.\n"); + goto done; + } + ok(request != NULL, "WinHttpOpenRequest failed to open a request, error: %lu\n", GetLastError()); + if (!request) goto done; + + max_redirects = 2; + ret = WinHttpSetOption(request, WINHTTP_OPTION_MAX_HTTP_AUTOMATIC_REDIRECTS, &max_redirects, sizeof(max_redirects)); + ok(ret, "WinHttpSetOption failed: %lu\n", GetLastError()); + + ret = WinHttpSendRequest(request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0); + err = GetLastError(); + if (!ret && (err == ERROR_WINHTTP_CANNOT_CONNECT || err == ERROR_WINHTTP_TIMEOUT)) + { + skip("connection failed, skipping\n"); + goto done; + } + ok(ret == TRUE, "WinHttpSendRequest failed: %lu\n", GetLastError()); + + url[0] = 0; + size = sizeof(url); + ret = WinHttpQueryOption(request, WINHTTP_OPTION_URL, url, &size); + ok(ret, "got %lu\n", GetLastError()); + ok(!wcscmp(url, L"http://test.winehq.org/tests/redirecttest.php?max=3"), "got %s\n", wine_dbgstr_w(url)); + + SetLastError(0xdeadbeef); + ret = WinHttpReceiveResponse(request, NULL); + ok(!ret, "WinHttpReceiveResponse succeeded, expected failure\n"); + ok(GetLastError() == ERROR_WINHTTP_REDIRECT_FAILED, "Expected ERROR_WINHTTP_REDIRECT_FAILED, got %lu\n", GetLastError()); + + url[0] = 0; + size = sizeof(url); + ret = WinHttpQueryOption(request, WINHTTP_OPTION_URL, url, &size); + ok(ret, "got %lu\n", GetLastError()); + ok(!wcscmp(url, L"http://test.winehq.org/tests/redirecttest.php?id=2&max=3") || + broken(!wcscmp(url, L"http://test.winehq.org/tests/redirecttest.php?id=1&max=3")) /* < Win10 1809 */, + "got %s\n", wine_dbgstr_w(url)); + + done: + ret = WinHttpCloseHandle(request); + ok(ret == TRUE, "WinHttpCloseHandle failed on closing request, got %d.\n", ret); + ret = WinHttpCloseHandle(connection); + ok(ret == TRUE, "WinHttpCloseHandle failed on closing connection, got %d.\n", ret); + ret = WinHttpCloseHandle(session); + ok(ret == TRUE, "WinHttpCloseHandle failed on closing session, got %d.\n", ret); +} + +static const BYTE pfxdata[] = +{ + 0x30, 0x82, 0x0b, 0x1d, 0x02, 0x01, 0x03, 0x30, 0x82, 0x0a, 0xe3, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82, + 0x0a, 0xd4, 0x04, 0x82, 0x0a, 0xd0, 0x30, 0x82, 0x0a, 0xcc, 0x30, 0x82, + 0x05, 0x07, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, + 0x06, 0xa0, 0x82, 0x04, 0xf8, 0x30, 0x82, 0x04, 0xf4, 0x02, 0x01, 0x00, + 0x30, 0x82, 0x04, 0xed, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x07, 0x01, 0x30, 0x1c, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x0c, 0x01, 0x06, 0x30, 0x0e, 0x04, 0x08, 0xac, 0x3e, 0x35, + 0xa8, 0xed, 0x0d, 0x50, 0x07, 0x02, 0x02, 0x08, 0x00, 0x80, 0x82, 0x04, + 0xc0, 0x5a, 0x62, 0x55, 0x25, 0xf6, 0x2c, 0xf1, 0x78, 0x6c, 0x63, 0x96, + 0x8a, 0xea, 0x04, 0x64, 0xb3, 0x99, 0x3b, 0x80, 0x50, 0x05, 0x37, 0x55, + 0xa3, 0x5e, 0x9f, 0x35, 0xc3, 0x3c, 0xdc, 0xf6, 0xc4, 0xc1, 0x39, 0xa2, + 0xd7, 0x50, 0xad, 0xf9, 0x29, 0x3c, 0x51, 0xea, 0x15, 0x20, 0x25, 0xd3, + 0x4d, 0x69, 0xdf, 0x10, 0xd8, 0x9d, 0x60, 0x78, 0x8a, 0x70, 0x44, 0x7f, + 0x01, 0x4f, 0x4a, 0xfa, 0xab, 0xfd, 0x46, 0x48, 0x96, 0x2b, 0x69, 0xfc, + 0x11, 0xf8, 0x3f, 0xd3, 0x79, 0x09, 0x75, 0x81, 0x47, 0xdf, 0xce, 0xfe, + 0x07, 0x2f, 0x0a, 0xd8, 0xac, 0x87, 0x14, 0x1f, 0x7b, 0x95, 0x70, 0xee, + 0x7e, 0x52, 0x90, 0x11, 0xd6, 0x69, 0xf4, 0xd5, 0x38, 0x85, 0xc9, 0xc1, + 0x07, 0x01, 0xe8, 0xbb, 0xfb, 0xe2, 0x08, 0xa8, 0xfa, 0xbf, 0xf0, 0x92, + 0x63, 0x1d, 0xbb, 0x2b, 0x45, 0x6f, 0xce, 0x97, 0x01, 0xd7, 0x95, 0xf0, + 0x9c, 0x9a, 0x6b, 0x73, 0x01, 0xbf, 0xf9, 0x3d, 0xc8, 0x2b, 0x86, 0x7a, + 0xd5, 0x65, 0x84, 0xd7, 0xff, 0xb2, 0xf9, 0x20, 0x52, 0x35, 0xc5, 0x60, + 0x33, 0x70, 0x1d, 0x2f, 0x26, 0x09, 0x1c, 0x22, 0x17, 0xd8, 0x08, 0x4e, + 0x69, 0x20, 0xe2, 0x71, 0xe4, 0x07, 0xb1, 0x48, 0x5f, 0x20, 0x08, 0x7a, + 0xbf, 0x65, 0x53, 0x23, 0x07, 0xf9, 0x6c, 0xde, 0x3e, 0x29, 0xbf, 0x6b, + 0xef, 0xbb, 0x6a, 0x5f, 0x79, 0xa1, 0x72, 0xa1, 0x10, 0x24, 0x80, 0xb4, + 0x44, 0xb8, 0xc9, 0xfc, 0xa3, 0x36, 0x7e, 0x23, 0x37, 0x58, 0xc6, 0x1e, + 0xe8, 0x42, 0x4d, 0xb5, 0xf5, 0x58, 0x93, 0x21, 0x38, 0xa2, 0xc4, 0xa9, + 0x01, 0x96, 0xf9, 0x61, 0xac, 0x55, 0xb3, 0x3d, 0xe4, 0x54, 0x8b, 0x6c, + 0xc3, 0x83, 0xff, 0x50, 0x87, 0x94, 0xe8, 0x35, 0x3c, 0x26, 0x0d, 0x20, + 0x8a, 0x25, 0x0e, 0xb6, 0x67, 0x78, 0x29, 0xc7, 0xbf, 0x76, 0x8e, 0x62, + 0x62, 0xc4, 0x50, 0xd6, 0xc5, 0x3c, 0xb4, 0x7a, 0x35, 0xbe, 0x53, 0x52, + 0xc4, 0xe4, 0x10, 0xb3, 0xe0, 0x73, 0xb0, 0xd1, 0xc1, 0x5a, 0x4f, 0x4e, + 0x64, 0x0d, 0x92, 0x51, 0x2d, 0x4d, 0xec, 0xb0, 0xc6, 0x40, 0x1b, 0x03, + 0x89, 0x7f, 0xc2, 0x2c, 0xe3, 0x2c, 0xbd, 0x8c, 0x9c, 0xd9, 0xe0, 0x08, + 0x59, 0xd3, 0xaf, 0x48, 0x56, 0x89, 0x60, 0x85, 0x76, 0xe0, 0xd8, 0x7c, + 0xcf, 0x02, 0x8f, 0xfd, 0xb2, 0x8f, 0x2b, 0x61, 0xcf, 0x28, 0x56, 0x8b, + 0x6b, 0x03, 0x2b, 0x2f, 0x83, 0x31, 0xa0, 0x1c, 0xd1, 0x6c, 0x87, 0x49, + 0xc4, 0x77, 0x55, 0x1f, 0x61, 0x45, 0x58, 0x88, 0x9f, 0x01, 0xc3, 0x63, + 0x62, 0x30, 0x35, 0xdf, 0x61, 0x74, 0x55, 0x63, 0x3f, 0xae, 0x41, 0xc1, + 0xb8, 0xf0, 0x9f, 0xab, 0x25, 0xad, 0x41, 0x5c, 0x1f, 0x00, 0x0d, 0xef, + 0xf0, 0xcf, 0xaf, 0x41, 0x23, 0xca, 0x8c, 0x38, 0xea, 0x5a, 0xe4, 0x8b, + 0xb4, 0x89, 0xd0, 0x76, 0x7f, 0x2b, 0x77, 0x8f, 0xe4, 0x44, 0xd5, 0x37, + 0xac, 0xc2, 0x09, 0x7e, 0x7e, 0x7e, 0x02, 0x5c, 0x27, 0x01, 0xcb, 0x4d, + 0xea, 0xb3, 0x97, 0x36, 0x35, 0xd2, 0x05, 0x3c, 0x4e, 0xb8, 0x04, 0x5c, + 0xb8, 0x95, 0x3f, 0xc6, 0xbf, 0xd4, 0x20, 0x01, 0xfb, 0xed, 0x37, 0x5a, + 0xad, 0x4c, 0x61, 0x93, 0xfe, 0x95, 0x7c, 0x34, 0x11, 0x15, 0x9d, 0x00, + 0x0b, 0x99, 0x69, 0xcb, 0x7e, 0xb9, 0x53, 0x46, 0x57, 0x39, 0x3f, 0x59, + 0x4b, 0x30, 0x8d, 0xfb, 0x84, 0x66, 0x2d, 0x06, 0xc9, 0x88, 0xa6, 0x18, + 0xd7, 0x36, 0xc6, 0xf6, 0xf7, 0x47, 0x85, 0x38, 0xc8, 0x3d, 0x37, 0xea, + 0x57, 0x4c, 0xb0, 0x7c, 0x95, 0x29, 0x84, 0xab, 0xbb, 0x19, 0x86, 0xc2, + 0xc5, 0x99, 0x01, 0x38, 0x6b, 0xf1, 0xd3, 0x1d, 0xa8, 0x02, 0xf9, 0x6f, + 0xaa, 0xf1, 0x57, 0xd0, 0x88, 0x68, 0x62, 0x5f, 0x9f, 0x7a, 0x63, 0xba, + 0x3a, 0xc9, 0x95, 0x11, 0x3c, 0xf9, 0xa1, 0xc1, 0x35, 0xfe, 0xd5, 0x12, + 0x49, 0x88, 0x0d, 0x5c, 0xe2, 0xd1, 0x15, 0x18, 0xfb, 0xd5, 0x7f, 0x19, + 0x3f, 0xaf, 0xa0, 0xcb, 0x31, 0x20, 0x9e, 0x03, 0x93, 0xa4, 0x66, 0xbd, + 0x83, 0xe8, 0x60, 0x34, 0x55, 0x0d, 0x97, 0x10, 0x23, 0x24, 0x7a, 0x45, + 0x36, 0xb4, 0xc4, 0xee, 0x60, 0x6f, 0xd8, 0x46, 0xc5, 0xac, 0x2b, 0xa9, + 0x18, 0x74, 0x83, 0x1e, 0xdf, 0x7c, 0x1a, 0x5a, 0xe8, 0x5f, 0x8b, 0x4f, + 0x9f, 0x40, 0x3e, 0x5e, 0xfb, 0xd3, 0x68, 0xac, 0x34, 0x62, 0x30, 0x23, + 0xb6, 0xbc, 0xdf, 0xbc, 0xc7, 0x25, 0xd2, 0x1b, 0x57, 0x33, 0xfb, 0x78, + 0x22, 0x21, 0x1e, 0x3a, 0xf6, 0x44, 0x18, 0x7e, 0x12, 0x36, 0x47, 0x58, + 0xd0, 0x59, 0x26, 0x98, 0x98, 0x95, 0xf4, 0xd1, 0xaa, 0x45, 0xaa, 0xe7, + 0xd1, 0xe6, 0x2d, 0x78, 0xf0, 0x8b, 0x1c, 0xfd, 0xf8, 0x50, 0x60, 0xa2, + 0x1e, 0x7f, 0xe3, 0x31, 0x77, 0x31, 0x58, 0x99, 0x0f, 0xda, 0x0e, 0xa3, + 0xc6, 0x7a, 0x30, 0x45, 0x55, 0x11, 0x91, 0x77, 0x41, 0x79, 0xd3, 0x56, + 0xb2, 0x07, 0x00, 0x61, 0xab, 0xec, 0x27, 0xc7, 0x9f, 0xfa, 0x89, 0x08, + 0xc2, 0x87, 0xcf, 0xe9, 0xdc, 0x9e, 0x29, 0x22, 0xfb, 0x23, 0x7f, 0x9d, + 0x89, 0xd5, 0x6e, 0x75, 0x20, 0xd8, 0x00, 0x5b, 0xc4, 0x94, 0xbb, 0xc5, + 0xb2, 0xba, 0x77, 0x2b, 0xf6, 0x3c, 0x88, 0xb0, 0x4c, 0x38, 0x46, 0x55, + 0xee, 0x8b, 0x03, 0x15, 0xbc, 0x0a, 0x1d, 0x47, 0x87, 0x44, 0xaf, 0xb1, + 0x2a, 0xa7, 0x4d, 0x08, 0xdf, 0x3b, 0x2d, 0x70, 0xa1, 0x67, 0x31, 0x76, + 0x6e, 0x6f, 0x40, 0x3b, 0x3b, 0xe8, 0xf9, 0xdf, 0x90, 0xa4, 0xce, 0x7f, + 0xb8, 0x2d, 0x69, 0xcb, 0x1c, 0x1e, 0x94, 0xcd, 0xb1, 0xd8, 0x43, 0x22, + 0xb8, 0x4f, 0x98, 0x92, 0x74, 0xb3, 0xde, 0xeb, 0x7a, 0xcb, 0xfa, 0xd0, + 0x36, 0xe4, 0x5d, 0xfa, 0xd3, 0xce, 0xf9, 0xba, 0x3e, 0x0f, 0x6c, 0xc3, + 0x5b, 0xb3, 0x81, 0x84, 0x6e, 0x5d, 0xc1, 0x21, 0x89, 0xec, 0x67, 0x9a, + 0xfd, 0x55, 0x20, 0xb0, 0x71, 0x53, 0xae, 0xf8, 0xa4, 0x8d, 0xd5, 0xe5, + 0x2d, 0x3a, 0xce, 0x89, 0x55, 0x8c, 0x4f, 0x3b, 0x37, 0x95, 0x4e, 0x15, + 0xbe, 0xe7, 0xd1, 0x7a, 0x36, 0x82, 0x45, 0x69, 0x7c, 0x27, 0x4f, 0xb9, + 0x4b, 0x7d, 0xcd, 0x59, 0xc8, 0xf4, 0x8b, 0x0f, 0x4f, 0x75, 0x23, 0xd3, + 0xd0, 0xc7, 0x10, 0x79, 0xc0, 0xf1, 0xac, 0x14, 0xf7, 0x0d, 0xc8, 0x5e, + 0xfc, 0xff, 0x1a, 0x2b, 0x10, 0x88, 0x7e, 0x7e, 0x2f, 0xfa, 0x7b, 0x9f, + 0x47, 0x23, 0x34, 0xfc, 0xf5, 0xde, 0xd9, 0xa3, 0x05, 0x99, 0x2a, 0x96, + 0x83, 0x3d, 0xa4, 0x7f, 0x6a, 0x66, 0x9b, 0xe7, 0xf1, 0x00, 0x4e, 0x9a, + 0xfc, 0x68, 0xd2, 0x74, 0x17, 0xba, 0xc9, 0xc8, 0x20, 0x39, 0xa1, 0xa8, + 0x85, 0xc6, 0x10, 0x2b, 0xab, 0x97, 0x34, 0x2d, 0x49, 0x68, 0x57, 0xb0, + 0x43, 0xee, 0x25, 0xbb, 0x35, 0x1b, 0x03, 0x99, 0xa3, 0x21, 0x68, 0x66, + 0x86, 0x3f, 0xc6, 0xfc, 0x49, 0xf0, 0xba, 0x5f, 0x00, 0xc6, 0xe3, 0x1c, + 0xb2, 0x9f, 0x16, 0x7f, 0xc7, 0x40, 0x4a, 0x9a, 0x39, 0xc1, 0x95, 0x69, + 0xa2, 0x87, 0xba, 0x58, 0xc6, 0xf2, 0xd6, 0x66, 0xa6, 0x4c, 0x6d, 0x29, + 0x9c, 0xa8, 0x6e, 0xa9, 0xd2, 0xe4, 0x54, 0x17, 0x89, 0xe2, 0x43, 0xf0, + 0xe1, 0x8b, 0x57, 0x84, 0x6c, 0x87, 0x63, 0x17, 0xbb, 0xf6, 0x33, 0x1b, + 0xe4, 0x34, 0x6a, 0x80, 0x70, 0x7b, 0x1b, 0xfd, 0xf8, 0x79, 0x28, 0xc8, + 0x3c, 0x8e, 0xa4, 0xd5, 0xb8, 0x96, 0x54, 0xd4, 0xec, 0x72, 0xe5, 0x40, + 0x8f, 0x56, 0xde, 0x82, 0x15, 0x72, 0x4d, 0xd8, 0x0c, 0x07, 0xea, 0xe6, + 0x44, 0xcd, 0x94, 0x73, 0x5c, 0x04, 0xe8, 0x8e, 0xb7, 0xc7, 0xc9, 0x29, + 0xdc, 0x04, 0xef, 0x7c, 0x31, 0x9b, 0x50, 0xbc, 0xea, 0x71, 0x1f, 0x28, + 0x22, 0xb6, 0x04, 0x53, 0x2e, 0x71, 0xc4, 0xf6, 0xbb, 0x88, 0x51, 0xee, + 0x3e, 0x76, 0x65, 0xb4, 0x4b, 0x1b, 0xa3, 0xec, 0x7b, 0xa7, 0x9d, 0x31, + 0x5d, 0xb8, 0x9f, 0xab, 0x6b, 0x54, 0x7d, 0xbd, 0xc1, 0x2c, 0x55, 0xb0, + 0x23, 0x8c, 0x06, 0x60, 0x01, 0x4f, 0x60, 0x85, 0x56, 0x7f, 0xfb, 0x99, + 0x0c, 0xdc, 0x8c, 0x09, 0x37, 0x46, 0x5b, 0x97, 0x5d, 0xe8, 0x31, 0x00, + 0x1b, 0x30, 0x9b, 0x02, 0x92, 0x29, 0xb5, 0x20, 0xce, 0x4b, 0x90, 0xfb, + 0x91, 0x07, 0x5a, 0xd3, 0xf5, 0xa0, 0xe6, 0x8f, 0xf8, 0x73, 0xc5, 0x4b, + 0xbb, 0xad, 0x2a, 0xeb, 0xa8, 0xb7, 0x68, 0x34, 0x36, 0x47, 0xd5, 0x4b, + 0x61, 0x89, 0x53, 0xe6, 0xb6, 0xb1, 0x07, 0xe4, 0x08, 0x2e, 0xed, 0x50, + 0xd4, 0x1e, 0xed, 0x7f, 0xbf, 0x35, 0x68, 0x04, 0x45, 0x72, 0x86, 0x71, + 0x15, 0x55, 0xdf, 0xe6, 0x30, 0xc0, 0x8b, 0x8a, 0xb0, 0x6c, 0xd0, 0x35, + 0x57, 0x8f, 0x04, 0x37, 0xbc, 0xe1, 0xb8, 0xbf, 0x27, 0x37, 0x3d, 0xd0, + 0xc8, 0x46, 0x67, 0x42, 0x51, 0x30, 0x82, 0x05, 0xbd, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82, 0x05, 0xae, + 0x04, 0x82, 0x05, 0xaa, 0x30, 0x82, 0x05, 0xa6, 0x30, 0x82, 0x05, 0xa2, + 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01, + 0x02, 0xa0, 0x82, 0x04, 0xee, 0x30, 0x82, 0x04, 0xea, 0x30, 0x1c, 0x06, + 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x03, 0x30, + 0x0e, 0x04, 0x08, 0x9f, 0xa4, 0x72, 0x2b, 0x6b, 0x0e, 0xcb, 0x9f, 0x02, + 0x02, 0x08, 0x00, 0x04, 0x82, 0x04, 0xc8, 0xe5, 0x35, 0xb9, 0x72, 0x28, + 0x20, 0x28, 0xad, 0xe3, 0x01, 0xd7, 0x0b, 0xe0, 0x4e, 0x36, 0xc3, 0x73, + 0x06, 0xd5, 0xf6, 0x75, 0x1a, 0x78, 0xb2, 0xd8, 0xf6, 0x5a, 0x85, 0x8e, + 0x50, 0xa3, 0x05, 0x49, 0x02, 0x2d, 0xf8, 0xa3, 0x2f, 0xe6, 0x02, 0x7a, + 0xd5, 0x0b, 0x1d, 0xf1, 0xd1, 0xe4, 0x16, 0xaa, 0x70, 0x2e, 0x34, 0xdb, + 0x56, 0xd9, 0x33, 0x94, 0x11, 0xaa, 0x60, 0xd4, 0xfa, 0x5b, 0xd1, 0xb3, + 0x2e, 0x86, 0x6a, 0x5a, 0x69, 0xdf, 0x11, 0x91, 0xb0, 0xca, 0x82, 0xff, + 0x63, 0xad, 0x6a, 0x0b, 0x90, 0xa6, 0xc7, 0x9b, 0xef, 0x9a, 0xf8, 0x96, + 0xec, 0xe4, 0xc4, 0xdf, 0x55, 0x4c, 0x12, 0x07, 0xab, 0x7c, 0x5c, 0x68, + 0x47, 0xf2, 0x92, 0xfb, 0x94, 0xab, 0xc3, 0x64, 0xd3, 0xfe, 0xb2, 0x16, + 0xb4, 0x78, 0x80, 0x52, 0xe9, 0x32, 0x39, 0x3b, 0x8d, 0x12, 0x91, 0x36, + 0xfd, 0xa1, 0x97, 0xc2, 0x0a, 0x4a, 0xf1, 0xb3, 0x8a, 0xe4, 0x01, 0xed, + 0x0a, 0xda, 0x2e, 0xa0, 0x38, 0xa9, 0x47, 0x3d, 0x3a, 0x64, 0x87, 0x06, + 0xc3, 0x83, 0x60, 0xaf, 0x84, 0xdb, 0x87, 0xff, 0x70, 0x61, 0x43, 0x7d, + 0x2d, 0x61, 0x9a, 0xf7, 0x0d, 0xca, 0x0c, 0x0f, 0xbe, 0x43, 0x5b, 0x99, + 0xe1, 0x90, 0x64, 0x1f, 0xa7, 0x1b, 0xa6, 0xa6, 0x5c, 0x13, 0x70, 0xa3, + 0xdb, 0xd7, 0xf0, 0xe8, 0x7a, 0xb0, 0xd1, 0x9b, 0x52, 0xa6, 0x4f, 0xd6, + 0xff, 0x54, 0x4d, 0xa6, 0x15, 0x05, 0x5c, 0xe9, 0x04, 0x6a, 0xc3, 0x49, + 0x12, 0x2f, 0x24, 0x03, 0xc3, 0x80, 0x06, 0xa6, 0x07, 0x8b, 0x96, 0xe7, + 0x39, 0x31, 0x6d, 0xd3, 0x1b, 0xa5, 0x45, 0x58, 0x04, 0xe7, 0x87, 0xdf, + 0x26, 0xfb, 0x1b, 0x9f, 0x92, 0x93, 0x32, 0x12, 0x9a, 0xc9, 0xe6, 0xcb, + 0x88, 0x14, 0x9f, 0x23, 0x0b, 0x52, 0xa2, 0xb8, 0x32, 0x6c, 0xa9, 0x33, + 0xa1, 0x17, 0xe8, 0x4a, 0xd4, 0x5c, 0x7d, 0xb3, 0xa3, 0x64, 0x86, 0x03, + 0x7c, 0x7c, 0x3f, 0x99, 0xdc, 0x21, 0x9f, 0x93, 0xc6, 0xb9, 0x1d, 0xe0, + 0x21, 0x79, 0x78, 0x35, 0xdc, 0x1e, 0x27, 0x3c, 0x73, 0x7f, 0x0f, 0xd6, + 0x4f, 0xde, 0xe9, 0xb4, 0xb7, 0xe3, 0xf5, 0x72, 0xce, 0x42, 0xf3, 0x91, + 0x5b, 0x84, 0xba, 0xbb, 0xae, 0xf0, 0x87, 0x0f, 0x50, 0xa4, 0x5e, 0x80, + 0x23, 0x57, 0x2b, 0xa0, 0xa3, 0xc3, 0x8a, 0x2f, 0xa8, 0x7a, 0x1a, 0x65, + 0x8f, 0x62, 0xf8, 0x3e, 0xe2, 0xcd, 0xbc, 0x63, 0x56, 0x8e, 0x77, 0xf3, + 0xf9, 0x69, 0x10, 0x57, 0xa8, 0xaf, 0x67, 0x2a, 0x9f, 0x7f, 0x7e, 0xeb, + 0x1d, 0x99, 0xa6, 0x67, 0xcd, 0x9e, 0x42, 0x2e, 0x5e, 0x4e, 0x61, 0x24, + 0xfa, 0xca, 0x2a, 0xeb, 0x62, 0x1f, 0xa3, 0x14, 0x0a, 0x06, 0x4b, 0x77, + 0x78, 0x77, 0x9b, 0xf1, 0x03, 0xcc, 0xb5, 0xfe, 0xfb, 0x7a, 0x77, 0xa6, + 0x82, 0x9f, 0xe5, 0xde, 0x9d, 0x0d, 0x4d, 0x37, 0xc6, 0x12, 0x73, 0x6d, + 0xea, 0xbb, 0x48, 0xf0, 0xd2, 0x81, 0xcc, 0x1a, 0x47, 0xfa, 0xa4, 0xd2, + 0xb2, 0x27, 0xa0, 0xfc, 0x30, 0x04, 0xdb, 0x05, 0xd3, 0x0b, 0xbc, 0x4d, + 0x7a, 0x99, 0xef, 0x7f, 0x26, 0x01, 0xd4, 0x07, 0x0b, 0x1e, 0x99, 0x06, + 0x3c, 0xde, 0x3d, 0x1c, 0x21, 0x82, 0x68, 0x46, 0x35, 0x38, 0x61, 0xea, + 0xd4, 0xc2, 0x65, 0x09, 0x39, 0x87, 0xb4, 0xd3, 0x5d, 0x3c, 0xa3, 0x79, + 0xe4, 0x01, 0x4e, 0xbf, 0x18, 0xba, 0x57, 0x3f, 0xdd, 0xea, 0x0a, 0x6b, + 0x99, 0xfb, 0x93, 0xfa, 0xab, 0xee, 0x08, 0xdf, 0x38, 0x23, 0xae, 0x8d, + 0xa8, 0x03, 0x13, 0xfe, 0x83, 0x88, 0xb0, 0xc2, 0xf9, 0x90, 0xa5, 0x1c, + 0x01, 0x6f, 0x71, 0x91, 0x42, 0x35, 0x81, 0x74, 0x71, 0x6c, 0xba, 0x86, + 0x48, 0xfe, 0x96, 0xd2, 0x88, 0x12, 0x36, 0x4e, 0xa6, 0x2f, 0xd1, 0xdb, + 0xfa, 0xbf, 0xdb, 0x84, 0x01, 0xfc, 0x7d, 0x7a, 0xac, 0x20, 0xae, 0xf5, + 0x95, 0xc9, 0xdc, 0x10, 0x5f, 0x4c, 0xae, 0x85, 0x01, 0x8b, 0xfe, 0x77, + 0x13, 0x01, 0xae, 0x39, 0x59, 0x7e, 0xbc, 0xfd, 0xc9, 0x42, 0xe4, 0x13, + 0x07, 0x3f, 0xa9, 0x74, 0xd9, 0xd5, 0xfc, 0xb9, 0x78, 0xbe, 0x97, 0xf5, + 0xe7, 0x36, 0x7f, 0xfa, 0x23, 0x30, 0xeb, 0xab, 0x92, 0xd3, 0xdc, 0x3f, + 0x7f, 0xc0, 0x77, 0x93, 0xf9, 0x88, 0xe3, 0x4e, 0x13, 0x53, 0x6d, 0x71, + 0x87, 0xe9, 0x24, 0x2b, 0xae, 0x26, 0xbf, 0x62, 0x51, 0x04, 0x42, 0xe1, + 0x13, 0x9d, 0xd8, 0x9f, 0x59, 0x87, 0x3f, 0xfc, 0x94, 0xff, 0xcf, 0x88, + 0x88, 0xe6, 0xeb, 0x6e, 0xc1, 0x96, 0x04, 0x27, 0xc8, 0xda, 0xfa, 0xe8, + 0x2e, 0xbb, 0x2c, 0x6e, 0xf4, 0xb4, 0x00, 0x7d, 0x8d, 0x3b, 0xef, 0x8b, + 0x18, 0xa9, 0x5f, 0x32, 0xa9, 0xf2, 0x3a, 0x7e, 0x65, 0x2d, 0x6e, 0x8d, + 0x75, 0x77, 0xf6, 0xa6, 0xd8, 0xf9, 0x6b, 0x51, 0xe6, 0x66, 0x52, 0x59, + 0x39, 0x97, 0x22, 0xda, 0xb2, 0xd6, 0x82, 0x5a, 0x6e, 0x61, 0x60, 0x16, + 0x48, 0x7b, 0xf1, 0xc3, 0x4d, 0x7f, 0x50, 0xfa, 0x4d, 0x58, 0x27, 0x30, + 0xc8, 0x96, 0xe0, 0x41, 0x4f, 0x6b, 0xeb, 0x88, 0xa2, 0x7a, 0xef, 0x8a, + 0x88, 0xc8, 0x50, 0x4b, 0x55, 0x66, 0xee, 0xbf, 0xc4, 0x01, 0x82, 0x4c, + 0xec, 0xde, 0x37, 0x64, 0xd6, 0x1e, 0xcf, 0x3e, 0x2e, 0xfe, 0x84, 0x68, + 0xbf, 0xa3, 0x68, 0x77, 0xa9, 0x03, 0xe4, 0xf8, 0xd7, 0xb2, 0x6e, 0xa3, + 0xc4, 0xc3, 0x36, 0x53, 0xf3, 0xdd, 0x7e, 0x4c, 0xf0, 0xe9, 0xb2, 0x44, + 0xe6, 0x60, 0x3d, 0x00, 0x9a, 0x08, 0xc3, 0x21, 0x17, 0x49, 0xda, 0x49, + 0xfb, 0x4c, 0x8b, 0xe9, 0x10, 0x66, 0xfe, 0xb7, 0xe0, 0xf9, 0xdd, 0xbf, + 0x41, 0xfe, 0x04, 0x9b, 0x7f, 0xe8, 0xd6, 0x2e, 0x4d, 0x0f, 0x7b, 0x10, + 0x73, 0x4c, 0xa1, 0x3e, 0x43, 0xb7, 0xcf, 0x94, 0x97, 0x7e, 0x24, 0xbb, + 0x87, 0xbf, 0x22, 0xb8, 0x3e, 0xeb, 0x9a, 0x3f, 0xe3, 0x86, 0xee, 0x21, + 0xbc, 0xf5, 0x44, 0xeb, 0x60, 0x2e, 0xe7, 0x8f, 0x89, 0xa4, 0x91, 0x61, + 0x28, 0x90, 0x85, 0x68, 0xe0, 0xa9, 0x62, 0x93, 0x86, 0x5a, 0x15, 0xbe, + 0xb2, 0x76, 0x83, 0xf2, 0x0f, 0x00, 0xc7, 0xb6, 0x57, 0xe9, 0x1f, 0x92, + 0x49, 0xfe, 0x50, 0x85, 0xbf, 0x39, 0x3d, 0xe4, 0x8b, 0x72, 0x2d, 0x49, + 0xbe, 0x05, 0x0a, 0x34, 0x56, 0x80, 0xc6, 0x1f, 0x46, 0x59, 0xc9, 0xfe, + 0x40, 0xfb, 0x78, 0x6d, 0x7a, 0xe5, 0x30, 0xe9, 0x81, 0x55, 0x75, 0x05, + 0x63, 0xd2, 0x22, 0xee, 0x2e, 0x6e, 0xb9, 0x18, 0xe5, 0x8a, 0x5a, 0x66, + 0xbd, 0x74, 0x30, 0xe3, 0x8b, 0x76, 0x22, 0x18, 0x1e, 0xef, 0x69, 0xe8, + 0x9d, 0x07, 0xa7, 0x9a, 0x87, 0x6c, 0x04, 0x4b, 0x74, 0x2b, 0xbe, 0x37, + 0x2f, 0x29, 0x9b, 0x60, 0x9d, 0x8b, 0x57, 0x55, 0x34, 0xca, 0x41, 0x25, + 0xae, 0x56, 0x92, 0x34, 0x1b, 0x9e, 0xbd, 0xfe, 0x74, 0xbd, 0x4e, 0x29, + 0xf0, 0x5e, 0x27, 0x94, 0xb0, 0x9e, 0x23, 0x9f, 0x4a, 0x0f, 0xa1, 0xdf, + 0xe7, 0xc4, 0xdb, 0xbe, 0x0f, 0x1a, 0x0b, 0x6c, 0xb0, 0xe1, 0x06, 0x7c, + 0x5a, 0x5b, 0x81, 0x1c, 0xb6, 0x12, 0xec, 0x6f, 0x3b, 0xbb, 0x84, 0x36, + 0xd5, 0x28, 0x16, 0xea, 0x51, 0xa8, 0x99, 0x24, 0x8f, 0xe7, 0xf8, 0xe9, + 0xce, 0xa1, 0x65, 0x96, 0x6f, 0x4e, 0x2f, 0xb7, 0x6f, 0x65, 0x39, 0xad, + 0xfd, 0x2e, 0xa0, 0x37, 0x32, 0x2f, 0xf3, 0x95, 0xa1, 0x3a, 0xa1, 0x9d, + 0x2c, 0x9e, 0xa1, 0x4b, 0x7e, 0xc9, 0x7e, 0x86, 0xaa, 0x16, 0x00, 0x82, + 0x1d, 0x36, 0xbf, 0x98, 0x0a, 0x82, 0x5b, 0xcc, 0xc4, 0x6a, 0xad, 0xa0, + 0x1f, 0x47, 0x98, 0xde, 0x8d, 0x68, 0x38, 0x3f, 0x33, 0xe2, 0x08, 0x3b, + 0x2a, 0x65, 0xd9, 0x2f, 0x53, 0x68, 0xb8, 0x78, 0xd0, 0x1d, 0xbb, 0x2a, + 0x73, 0x19, 0xba, 0x58, 0xea, 0xf1, 0x0a, 0xaa, 0xa6, 0xbe, 0x27, 0xd6, + 0x00, 0x6b, 0x4e, 0x43, 0x8e, 0x5b, 0x19, 0xc1, 0x37, 0x0f, 0xfb, 0x81, + 0x72, 0x10, 0xb6, 0x20, 0x32, 0xcd, 0xa2, 0x7c, 0x90, 0xd4, 0xf5, 0xcf, + 0x1c, 0xcb, 0x14, 0x24, 0x7a, 0x4d, 0xf5, 0xd5, 0xd9, 0xce, 0x6a, 0x64, + 0xc9, 0xd3, 0xa7, 0x36, 0x6f, 0x1d, 0xf1, 0xe9, 0x71, 0x6c, 0x3d, 0x02, + 0xa4, 0x62, 0xb1, 0x82, 0x5c, 0x13, 0x4b, 0x6b, 0x68, 0xe2, 0x31, 0xef, + 0xe4, 0x46, 0xfd, 0xe5, 0xa8, 0x29, 0xe9, 0x1e, 0xad, 0xff, 0x33, 0xdb, + 0x0b, 0xc0, 0x92, 0xb1, 0xef, 0xeb, 0xb3, 0x6f, 0x96, 0x7b, 0xdf, 0xcd, + 0x07, 0x19, 0x86, 0x60, 0x98, 0xcf, 0x95, 0xfe, 0x98, 0xdd, 0x29, 0xa6, + 0x35, 0x7b, 0x46, 0x13, 0x03, 0xa8, 0xd9, 0x7c, 0xb3, 0xdf, 0x9f, 0x14, + 0xb7, 0x34, 0x5a, 0xc4, 0x12, 0x81, 0xc5, 0x98, 0x25, 0x8d, 0x3e, 0xe3, + 0xd8, 0x2d, 0xe4, 0x54, 0xab, 0xb0, 0x13, 0xfd, 0xd1, 0x3f, 0x3b, 0xbf, + 0xa9, 0x45, 0x28, 0x8a, 0x2f, 0x9c, 0x1e, 0x2d, 0xe5, 0xab, 0x13, 0x95, + 0x97, 0xc3, 0x34, 0x37, 0x8d, 0x93, 0x66, 0x31, 0x81, 0xa0, 0x30, 0x23, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x15, 0x31, + 0x16, 0x04, 0x14, 0xa5, 0x23, 0x9b, 0x7e, 0xe6, 0x45, 0x71, 0xbf, 0x48, + 0xc6, 0x27, 0x3c, 0x96, 0x87, 0x63, 0xbd, 0x1f, 0xde, 0x72, 0x12, 0x30, + 0x79, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x11, 0x01, + 0x31, 0x6c, 0x1e, 0x6a, 0x00, 0x4d, 0x00, 0x69, 0x00, 0x63, 0x00, 0x72, + 0x00, 0x6f, 0x00, 0x73, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x74, 0x00, 0x20, + 0x00, 0x45, 0x00, 0x6e, 0x00, 0x68, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x63, + 0x00, 0x65, 0x00, 0x64, 0x00, 0x20, 0x00, 0x52, 0x00, 0x53, 0x00, 0x41, + 0x00, 0x20, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x20, 0x00, 0x41, + 0x00, 0x45, 0x00, 0x53, 0x00, 0x20, 0x00, 0x43, 0x00, 0x72, 0x00, 0x79, + 0x00, 0x70, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x67, 0x00, 0x72, 0x00, 0x61, + 0x00, 0x70, 0x00, 0x68, 0x00, 0x69, 0x00, 0x63, 0x00, 0x20, 0x00, 0x50, + 0x00, 0x72, 0x00, 0x6f, 0x00, 0x76, 0x00, 0x69, 0x00, 0x64, 0x00, 0x65, + 0x00, 0x72, 0x30, 0x31, 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, + 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14, 0x93, 0xa8, 0xb2, 0x7e, 0xb7, + 0xab, 0xf1, 0x1c, 0x3c, 0x36, 0x58, 0xdc, 0x67, 0x6d, 0x42, 0xa6, 0xfc, + 0x53, 0x01, 0xe6, 0x04, 0x08, 0x77, 0x57, 0x22, 0xa1, 0x7d, 0xb9, 0xa2, + 0x69, 0x02, 0x02, 0x08, 0x00 +}; + +static void test_client_cert_authentication(void) +{ + HINTERNET ses, req, con; + BOOL ret; + CRYPT_DATA_BLOB pfx; + HCERTSTORE store; + const CERT_CONTEXT *cert; + + ses = WinHttpOpen( L"winetest", WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0 ); + ok( ses != NULL, "failed to open session %lu\n", GetLastError() ); + + con = WinHttpConnect( ses, L"test.winehq.org", 443, 0 ); + ok( con != NULL, "failed to open a connection %lu\n", GetLastError() ); + + req = WinHttpOpenRequest( con, NULL, L"/tests/clientcert/", NULL, NULL, NULL, WINHTTP_FLAG_SECURE ); + ok( req != NULL, "failed to open a request %lu\n", GetLastError() ); + + ret = WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 ); + ok( ret || broken(!ret && GetLastError() == ERROR_WINHTTP_SECURE_FAILURE) /* win7 */, + "failed to send request %lu\n", GetLastError() ); + if (!ret) goto done; + + SetLastError( 0xdeadbeef ); + ret = WinHttpReceiveResponse( req, NULL ); + ok( !ret, "unexpected success\n" ); + ok( GetLastError() == ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED, "got %lu\n", GetLastError() ); + + pfx.pbData = (BYTE *)pfxdata; + pfx.cbData = sizeof(pfxdata); + store = PFXImportCertStore( &pfx, NULL, CRYPT_EXPORTABLE|CRYPT_USER_KEYSET|PKCS12_NO_PERSIST_KEY ); + ok( store != NULL, "got %lu\n", GetLastError() ); + + cert = CertFindCertificateInStore( store, X509_ASN_ENCODING, 0, CERT_FIND_ANY, NULL, NULL ); + ok( cert != NULL, "got %lu\n", GetLastError() ); + + ret = WinHttpSetOption( req, WINHTTP_OPTION_CLIENT_CERT_CONTEXT, (void *)cert, sizeof(*cert) ); + ok( ret, "failed to set client cert %lu\n", GetLastError() ); + + ret = WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 ); + ok( ret, "failed to send request %lu\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + ret = WinHttpReceiveResponse( req, NULL ); + todo_wine { + ok( !ret, "unexpected success\n" ); + ok( GetLastError() == ERROR_WINHTTP_SECURE_FAILURE || GetLastError() == SEC_E_CERT_EXPIRED, /* win8 */ + "got %lu\n", GetLastError() ); + } + + CertFreeCertificateContext( cert ); + CertCloseStore( store, 0 ); +done: + WinHttpCloseHandle( req ); + WinHttpCloseHandle( con ); + WinHttpCloseHandle( ses ); +} + +static void test_connection_cache(int port) +{ + HINTERNET ses, con, req; + DWORD status, size; + char buffer[256]; + BOOL ret; + + ses = WinHttpOpen(L"winetest", WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0); + ok(ses != NULL, "failed to open session %lu\n", GetLastError()); + + con = WinHttpConnect(ses, L"localhost", port, 0); + ok(con != NULL, "failed to open a connection %lu\n", GetLastError()); + + req = WinHttpOpenRequest(con, L"GET", L"/cached", NULL, NULL, NULL, 0); + ok(req != NULL, "failed to open a request %lu\n", GetLastError()); + ret = WinHttpSendRequest(req, NULL, 0, NULL, 0, 0, 0); + ok(ret, "failed to send request %lu\n", GetLastError()); + ret = WinHttpReceiveResponse(req, NULL); + ok(ret, "failed to receive response %lu\n", GetLastError()); + size = sizeof(status); + ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL); + ok(ret, "failed to query status code %lu\n", GetLastError()); + ok(status == HTTP_STATUS_OK, "request failed unexpectedly %lu\n", status); + ret = WinHttpReadData(req, buffer, sizeof buffer, &size); + ok(ret, "failed to read data %lu\n", GetLastError()); + ok(!size, "got size %lu.\n", size); + WinHttpCloseHandle(req); + + req = WinHttpOpenRequest(con, L"GET", L"/cached", NULL, NULL, NULL, 0); + ok(req != NULL, "failed to open a request %lu\n", GetLastError()); + ret = WinHttpSendRequest(req, L"Connection: close", ~0u, NULL, 0, 0, 0); + ok(ret, "failed to send request %lu\n", GetLastError()); + ret = WinHttpReceiveResponse(req, NULL); + ok(ret, "failed to receive response %lu\n", GetLastError()); + size = sizeof(status); + ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL); + ok(ret, "failed to query status code %lu\n", GetLastError()); + ok(status == HTTP_STATUS_OK, "request failed unexpectedly %lu\n", status); + ret = WinHttpReadData(req, buffer, sizeof buffer, &size); + ok(ret, "failed to read data %lu\n", GetLastError()); + ok(!size, "got size %lu.\n", size); + WinHttpCloseHandle(req); + + req = WinHttpOpenRequest(con, L"GET", L"/notcached", NULL, NULL, NULL, 0); + ok(req != NULL, "failed to open a request %lu\n", GetLastError()); + ret = WinHttpSendRequest(req, L"Connection: close", ~0u, NULL, 0, 0, 0); + ok(ret, "failed to send request %lu\n", GetLastError()); + ret = WinHttpReceiveResponse(req, NULL); + ok(ret, "failed to receive response %lu\n", GetLastError()); + size = sizeof(status); + ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL); + ok(ret, "failed to query status code %lu\n", GetLastError()); + ok(status == HTTP_STATUS_OK, "request failed unexpectedly %lu\n", status); + WinHttpCloseHandle(req); + + WinHttpCloseHandle(con); + WinHttpCloseHandle(ses); +} + START_TEST (winhttp) { - static const WCHAR basicW[] = {'/','b','a','s','i','c',0}; - static const WCHAR quitW[] = {'/','q','u','i','t',0}; struct server_info si; HANDLE thread; DWORD ret; + HMODULE mod = GetModuleHandleA("winhttp.dll"); + + pWinHttpWebSocketClose = (void *)GetProcAddress(mod, "WinHttpWebSocketClose"); + pWinHttpWebSocketCompleteUpgrade = (void *)GetProcAddress(mod, "WinHttpWebSocketCompleteUpgrade"); + pWinHttpWebSocketQueryCloseStatus = (void *)GetProcAddress(mod, "WinHttpWebSocketQueryCloseStatus"); + pWinHttpWebSocketSend = (void *)GetProcAddress(mod, "WinHttpWebSocketSend"); + pWinHttpWebSocketShutdown = (void *)GetProcAddress(mod, "WinHttpWebSocketShutdown"); + pWinHttpWebSocketReceive = (void *)GetProcAddress(mod, "WinHttpWebSocketReceive"); test_WinHttpOpenRequest(); test_WinHttpSendRequest(); + test_connect_error(); test_WinHttpTimeFromSystemTime(); test_WinHttpTimeToSystemTime(); test_WinHttpAddHeaders(); test_secure_connection(); + test_client_cert_authentication(); test_request_parameter_defaults(); test_WinHttpQueryOption(); test_set_default_proxy_config(); @@ -4861,17 +6280,16 @@ START_TEST (winhttp) test_IWinHttpRequest_Invoke(); test_WinHttpDetectAutoProxyConfigUrl(); test_WinHttpGetIEProxyConfigForCurrentUser(); - test_WinHttpGetProxyForUrl(); test_chunked_read(); + test_max_http_automatic_redirects(); si.event = CreateEventW(NULL, 0, 0, NULL); si.port = 7532; - thread = CreateThread(NULL, 0, server_thread, &si, 0, NULL); - ok(thread != NULL, "failed to create thread %u\n", GetLastError()); + ok(thread != NULL, "failed to create thread %lu\n", GetLastError()); ret = WaitForSingleObject(si.event, 10000); - ok(ret == WAIT_OBJECT_0, "failed to start winhttp test server %u\n", GetLastError()); + ok(ret == WAIT_OBJECT_0, "failed to start winhttp test server %lu\n", GetLastError()); if (ret != WAIT_OBJECT_0) { CloseHandle(thread); @@ -4880,7 +6298,9 @@ START_TEST (winhttp) test_IWinHttpRequest(si.port); test_connection_info(si.port); - test_basic_request(si.port, NULL, basicW); + test_basic_request(si.port, NULL, L"/basic"); + test_basic_request(si.port, L"PUT", L"/test"); + test_chunked_request(si.port); test_no_headers(si.port); test_no_content(si.port); test_head_request(si.port); @@ -4900,18 +6320,26 @@ START_TEST (winhttp) test_cookies(si.port); test_request_path_escapes(si.port); test_passport_auth(si.port); + test_websocket(si.port); + test_redirect(si.port); + test_WinHttpGetProxyForUrl(si.port); + test_connection_cache(si.port); /* send the basic request again to shutdown the server thread */ - test_basic_request(si.port, NULL, quitW); + test_basic_request(si.port, NULL, L"/quit"); } #else test_multiple_reads(si.port); test_cookies(si.port); test_request_path_escapes(si.port); test_passport_auth(si.port); + test_websocket(si.port); + test_redirect(si.port); + test_WinHttpGetProxyForUrl(si.port); + test_connection_cache(si.port); /* send the basic request again to shutdown the server thread */ - test_basic_request(si.port, NULL, quitW); + test_basic_request(si.port, NULL, L"/quit"); #endif WaitForSingleObject(thread, 3000); diff --git a/sdk/include/psdk/winhttp.h b/sdk/include/psdk/winhttp.h index 3ef05ea0bde..e60e8432d67 100644 --- a/sdk/include/psdk/winhttp.h +++ b/sdk/include/psdk/winhttp.h @@ -25,7 +25,12 @@ #include #endif +#ifdef _WINHTTP_INTERNAL_ #define WINHTTPAPI +#else +#define WINHTTPAPI DECLSPEC_IMPORT +#endif + #define BOOLAPI WINHTTPAPI BOOL WINAPI @@ -46,6 +51,8 @@ typedef INTERNET_PORT *LPINTERNET_PORT; typedef int INTERNET_SCHEME, *LPINTERNET_SCHEME; #define ICU_ESCAPE 0x80000000 +#define ICU_ESCAPE_AUTHORITY 0x00002000 +#define ICU_REJECT_USERPWD 0x00004000 /* flags for WinHttpOpen */ #define WINHTTP_FLAG_ASYNC 0x10000000 @@ -62,6 +69,7 @@ typedef int INTERNET_SCHEME, *LPINTERNET_SCHEME; #define WINHTTP_ACCESS_TYPE_DEFAULT_PROXY 0 #define WINHTTP_ACCESS_TYPE_NO_PROXY 1 #define WINHTTP_ACCESS_TYPE_NAMED_PROXY 3 +#define WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY 4 #define WINHTTP_NO_PROXY_NAME NULL #define WINHTTP_NO_PROXY_BYPASS NULL @@ -108,6 +116,7 @@ typedef int INTERNET_SCHEME, *LPINTERNET_SCHEME; #define WINHTTP_OPTION_URL 34 #define WINHTTP_OPTION_SECURITY_KEY_BITNESS 36 #define WINHTTP_OPTION_PROXY 38 +#define WINHTTP_OPTION_PROXY_RESULT_ENTRY 39 #define WINHTTP_OPTION_USER_AGENT 41 #define WINHTTP_OPTION_CONTEXT_VALUE 45 #define WINHTTP_OPTION_CLIENT_CERT_CONTEXT 47 @@ -141,7 +150,35 @@ typedef int INTERNET_SCHEME, *LPINTERNET_SCHEME; #define WINHTTP_OPTION_UNLOAD_NOTIFY_EVENT 99 #define WINHTTP_OPTION_REJECT_USERPWD_IN_URL 100 #define WINHTTP_OPTION_USE_GLOBAL_SERVER_CREDENTIALS 101 -#define WINHTTP_LAST_OPTION WINHTTP_OPTION_USE_GLOBAL_SERVER_CREDENTIALS +#define WINHTTP_OPTION_RECEIVE_PROXY_CONNECT_RESPONSE 103 +#define WINHTTP_OPTION_IS_PROXY_CONNECT_RESPONSE 104 +#define WINHTTP_OPTION_SERVER_SPN_USED 106 +#define WINHTTP_OPTION_PROXY_SPN_USED 107 +#define WINHTTP_OPTION_SERVER_CBT 108 +#define WINHTTP_OPTION_UNSAFE_HEADER_PARSING 110 +#define WINHTTP_OPTION_ASSURED_NON_BLOCKING_CALLBACKS 111 +#define WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET 114 +#define WINHTTP_OPTION_WEB_SOCKET_CLOSE_TIMEOUT 115 +#define WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL 116 +#define WINHTTP_OPTION_DECOMPRESSION 118 +#define WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE 122 +#define WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE 123 +#define WINHTTP_OPTION_TCP_PRIORITY_HINT 128 +#define WINHTTP_OPTION_CONNECTION_FILTER 131 +#define WINHTTP_OPTION_ENABLE_HTTP_PROTOCOL 133 +#define WINHTTP_OPTION_HTTP_PROTOCOL_USED 134 +#define WINHTTP_OPTION_KDC_PROXY_SETTINGS 136 +#define WINHTTP_OPTION_ENCODE_EXTRA 138 +#define WINHTTP_OPTION_DISABLE_STREAM_QUEUE 139 +#define WINHTTP_OPTION_IPV6_FAST_FALLBACK 140 +#define WINHTTP_OPTION_CONNECTION_STATS_V0 141 +#define WINHTTP_OPTION_REQUEST_TIMES 142 +#define WINHTTP_OPTION_EXPIRE_CONNECTION 143 +#define WINHTTP_OPTION_DISABLE_SECURE_PROTOCOL_FALLBACK 144 +#define WINHTTP_OPTION_HTTP_PROTOCOL_REQUIRED 145 +#define WINHTTP_OPTION_REQUEST_STATS 146 +#define WINHTTP_OPTION_SERVER_CERT_CHAIN_CONTEXT 147 +#define WINHTTP_LAST_OPTION WINHTTP_OPTION_SERVER_CERT_CHAIN_CONTEXT #define WINHTTP_OPTION_USERNAME 0x1000 #define WINHTTP_OPTION_PASSWORD 0x1001 #define WINHTTP_OPTION_PROXY_USERNAME 0x1002 @@ -149,6 +186,15 @@ typedef int INTERNET_SCHEME, *LPINTERNET_SCHEME; #define WINHTTP_CONNS_PER_SERVER_UNLIMITED 0xFFFFFFFF +#define WINHTTP_DECOMPRESSION_FLAG_GZIP 0x00000001 +#define WINHTTP_DECOMPRESSION_FLAG_DEFLATE 0x00000002 + +#define WINHTTP_DECOMPRESSION_FLAG_ALL ( WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE ) + +#define WINHTTP_PROTOCOL_FLAG_HTTP2 0x1 +#define WINHTTP_PROTOCOL_FLAG_HTTP3 0x2 +#define WINHTTP_PROTOCOL_MASK (WINHTTP_PROTOCOL_FLAG_HTTP2 | WINHTTP_PROTOCOL_FLAG_HTTP3) + #define WINHTTP_AUTOLOGON_SECURITY_LEVEL_MEDIUM 0 #define WINHTTP_AUTOLOGON_SECURITY_LEVEL_LOW 1 #define WINHTTP_AUTOLOGON_SECURITY_LEVEL_HIGH 2 @@ -223,6 +269,8 @@ typedef int INTERNET_SCHEME, *LPINTERNET_SCHEME; #define ERROR_WINHTTP_SECURE_CERT_REVOKED (WINHTTP_ERROR_BASE + 170) #define ERROR_WINHTTP_NOT_INITIALIZED (WINHTTP_ERROR_BASE + 172) #define ERROR_WINHTTP_SECURE_FAILURE (WINHTTP_ERROR_BASE + 175) +#define ERROR_WINHTTP_UNHANDLED_SCRIPT_TYPE (WINHTTP_ERROR_BASE + 176) +#define ERROR_WINHTTP_SCRIPT_EXECUTION_ERROR (WINHTTP_ERROR_BASE + 177) #define ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR (WINHTTP_ERROR_BASE + 178) #define ERROR_WINHTTP_SECURE_CERT_WRONG_USAGE (WINHTTP_ERROR_BASE + 179) #define ERROR_WINHTTP_AUTODETECTION_FAILED (WINHTTP_ERROR_BASE + 180) @@ -232,7 +280,20 @@ typedef int INTERNET_SCHEME, *LPINTERNET_SCHEME; #define ERROR_WINHTTP_RESPONSE_DRAIN_OVERFLOW (WINHTTP_ERROR_BASE + 184) #define ERROR_WINHTTP_CLIENT_CERT_NO_PRIVATE_KEY (WINHTTP_ERROR_BASE + 185) #define ERROR_WINHTTP_CLIENT_CERT_NO_ACCESS_PRIVATE_KEY (WINHTTP_ERROR_BASE + 186) -#define WINHTTP_ERROR_LAST (WINHTTP_ERROR_BASE + 186) +#define ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED_PROXY (WINHTTP_ERROR_BASE + 187) +#define ERROR_WINHTTP_SECURE_FAILURE_PROXY (WINHTTP_ERROR_BASE + 188) +#define ERROR_WINHTTP_RESERVED_189 (WINHTTP_ERROR_BASE + 189) +#define ERROR_WINHTTP_HTTP_PROTOCOL_MISMATCH (WINHTTP_ERROR_BASE + 190) +#define WINHTTP_ERROR_LAST (WINHTTP_ERROR_BASE + 188) + +#define WINHTTP_RESET_STATE 0x00000001 +#define WINHTTP_RESET_SWPAD_CURRENT_NETWORK 0x00000002 +#define WINHTTP_RESET_SWPAD_ALL 0x00000004 +#define WINHTTP_RESET_SCRIPT_CACHE 0x00000008 +#define WINHTTP_RESET_ALL 0x0000FFFF +#define WINHTTP_RESET_NOTIFY_NETWORK_CHANGED 0x00010000 +#define WINHTTP_RESET_OUT_OF_PROC 0x00020000 +#define WINHTTP_RESET_DISCARD_RESOLVERS 0x00040000 /* WinHttp status codes */ #define HTTP_STATUS_CONTINUE 100 @@ -252,6 +313,7 @@ typedef int INTERNET_SCHEME, *LPINTERNET_SCHEME; #define HTTP_STATUS_NOT_MODIFIED 304 #define HTTP_STATUS_USE_PROXY 305 #define HTTP_STATUS_REDIRECT_KEEP_VERB 307 +#define HTTP_STATUS_PERMANENT_REDIRECT 308 #define HTTP_STATUS_BAD_REQUEST 400 #define HTTP_STATUS_DENIED 401 #define HTTP_STATUS_PAYMENT_REQ 402 @@ -375,6 +437,7 @@ typedef int INTERNET_SCHEME, *LPINTERNET_SCHEME; #define WINHTTP_QUERY_FLAG_REQUEST_HEADERS 0x80000000 #define WINHTTP_QUERY_FLAG_SYSTEMTIME 0x40000000 #define WINHTTP_QUERY_FLAG_NUMBER 0x20000000 +#define WINHTTP_QUERY_FLAG_NUMBER64 0x08000000 /* Callback options */ #define WINHTTP_CALLBACK_STATUS_RESOLVING_NAME 0x00000001 @@ -399,6 +462,11 @@ typedef int INTERNET_SCHEME, *LPINTERNET_SCHEME; #define WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE 0x00100000 #define WINHTTP_CALLBACK_STATUS_REQUEST_ERROR 0x00200000 #define WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE 0x00400000 +#define WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE 0x01000000 +#define WINHTTP_CALLBACK_STATUS_CLOSE_COMPLETE 0x02000000 +#define WINHTTP_CALLBACK_STATUS_SHUTDOWN_COMPLETE 0x04000000 +#define WINHTTP_CALLBACK_STATUS_SETTINGS_WRITE_COMPLETE 0x10000000 +#define WINHTTP_CALLBACK_STATUS_SETTINGS_READ_COMPLETE 0x20000000 #define WINHTTP_CALLBACK_FLAG_RESOLVE_NAME (WINHTTP_CALLBACK_STATUS_RESOLVING_NAME | WINHTTP_CALLBACK_STATUS_NAME_RESOLVED) #define WINHTTP_CALLBACK_FLAG_CONNECT_TO_SERVER (WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER | WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER) #define WINHTTP_CALLBACK_FLAG_SEND_REQUEST (WINHTTP_CALLBACK_STATUS_SENDING_REQUEST | WINHTTP_CALLBACK_STATUS_REQUEST_SENT) @@ -415,9 +483,11 @@ typedef int INTERNET_SCHEME, *LPINTERNET_SCHEME; #define WINHTTP_CALLBACK_FLAG_READ_COMPLETE WINHTTP_CALLBACK_STATUS_READ_COMPLETE #define WINHTTP_CALLBACK_FLAG_WRITE_COMPLETE WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE #define WINHTTP_CALLBACK_FLAG_REQUEST_ERROR WINHTTP_CALLBACK_STATUS_REQUEST_ERROR +#define WINHTTP_CALLBACK_FLAG_GETPROXYFORURL_COMPLETE WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE #define WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS (WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE | WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE \ | WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE | WINHTTP_CALLBACK_STATUS_READ_COMPLETE \ - | WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE | WINHTTP_CALLBACK_STATUS_REQUEST_ERROR) + | WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE | WINHTTP_CALLBACK_STATUS_REQUEST_ERROR \ + | WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE) #define WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS 0xffffffff #define WINHTTP_INVALID_STATUS_CALLBACK ((WINHTTP_STATUS_CALLBACK)(-1)) @@ -426,6 +496,7 @@ typedef int INTERNET_SCHEME, *LPINTERNET_SCHEME; #define API_READ_DATA (3) #define API_WRITE_DATA (4) #define API_SEND_REQUEST (5) +#define API_GET_PROXY_FOR_URL (6) #define WINHTTP_HANDLE_TYPE_SESSION 1 #define WINHTTP_HANDLE_TYPE_CONNECT 2 @@ -445,6 +516,7 @@ typedef int INTERNET_SCHEME, *LPINTERNET_SCHEME; #define WINHTTP_FLAG_SECURE_PROTOCOL_TLS1 0x00000080 #define WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 0x00000200 #define WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2 0x00000800 +#define WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_3 0x00002000 #define WINHTTP_FLAG_SECURE_PROTOCOL_ALL (WINHTTP_FLAG_SECURE_PROTOCOL_SSL2 |\ WINHTTP_FLAG_SECURE_PROTOCOL_SSL3 |\ WINHTTP_FLAG_SECURE_PROTOCOL_TLS1) @@ -524,13 +596,24 @@ typedef VOID _In_ LPVOID, _In_ DWORD); +typedef WINHTTP_STATUS_CALLBACK * LPWINHTTP_STATUS_CALLBACK; + #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_HOST_KEEPCASE 0x00000004 +#define WINHTTP_AUTOPROXY_HOST_LOWERCASE 0x00000008 +#define WINHTTP_AUTOPROXY_ALLOW_AUTOCONFIG 0x00000100 +#define WINHTTP_AUTOPROXY_ALLOW_STATIC 0x00000200 +#define WINHTTP_AUTOPROXY_ALLOW_CM 0x00000400 #define WINHTTP_AUTOPROXY_RUN_INPROCESS 0x00010000 #define WINHTTP_AUTOPROXY_RUN_OUTPROCESS_ONLY 0x00020000 +#define WINHTTP_AUTOPROXY_NO_DIRECTACCESS 0x00040000 +#define WINHTTP_AUTOPROXY_NO_CACHE_CLIENT 0x00080000 +#define WINHTTP_AUTOPROXY_NO_CACHE_SVC 0x00100000 +#define WINHTTP_AUTOPROXY_SORT_RESULTS 0x00400000 typedef struct { @@ -542,6 +625,56 @@ typedef struct BOOL fAutoLogonIfChallenged; } WINHTTP_AUTOPROXY_OPTIONS; +typedef struct _WINHTTP_PROXY_RESULT_ENTRY +{ + BOOL fProxy; + BOOL fBypass; + INTERNET_SCHEME ProxyScheme; + PWSTR pwszProxy; + INTERNET_PORT ProxyPort; +} WINHTTP_PROXY_RESULT_ENTRY; + +typedef struct _WINHTTP_PROXY_RESULT +{ + DWORD cEntries; + WINHTTP_PROXY_RESULT_ENTRY *pEntries; +} WINHTTP_PROXY_RESULT; + +typedef struct _WINHTTP_PROXY_RESULT_EX +{ + DWORD cEntries; + WINHTTP_PROXY_RESULT_ENTRY *pEntries; + HANDLE hProxyDetectionHandle; + DWORD dwProxyInterfaceAffinity; +} WINHTTP_PROXY_RESULT_EX; + +#define NETWORKING_KEY_BUFSIZE 128 + +typedef struct _WinHttpProxyNetworkKey +{ + unsigned char pbBuffer[NETWORKING_KEY_BUFSIZE]; +} WINHTTP_PROXY_NETWORKING_KEY, *PWINHTTP_PROXY_NETWORKING_KEY; + +typedef struct _WINHTTP_PROXY_SETTINGS +{ + DWORD dwStructSize; + DWORD dwFlags; + DWORD dwCurrentSettingsVersion; + PWSTR pwszConnectionName; + PWSTR pwszProxy; + PWSTR pwszProxyBypass; + PWSTR pwszAutoconfigUrl; + PWSTR pwszAutoconfigSecondaryUrl; + DWORD dwAutoDiscoveryFlags; + PWSTR pwszLastKnownGoodAutoConfigUrl; + DWORD dwAutoconfigReloadDelayMins; + FILETIME ftLastKnownDetectTime; + DWORD dwDetectedInterfaceIpCount; + PDWORD pdwDetectedInterfaceIp; + DWORD cNetworkKeys; + PWINHTTP_PROXY_NETWORKING_KEY pNetworkKeys; +} WINHTTP_PROXY_SETTINGS, *PWINHTTP_PROXY_SETTINGS; + typedef struct { DWORD dwMajorVersion; @@ -557,6 +690,139 @@ typedef struct } WINHTTP_CONNECTION_INFO; #endif +typedef enum _WINHTTP_REQUEST_TIME_ENTRY +{ + WinHttpProxyDetectionStart = 0, + WinHttpProxyDetectionEnd, + WinHttpConnectionAcquireStart, + WinHttpConnectionAcquireWaitEnd, + WinHttpConnectionAcquireEnd, + WinHttpNameResolutionStart, + WinHttpNameResolutionEnd, + WinHttpConnectionEstablishmentStart, + WinHttpConnectionEstablishmentEnd, + WinHttpTlsHandshakeClientLeg1Start, + WinHttpTlsHandshakeClientLeg1End, + WinHttpTlsHandshakeClientLeg2Start, + WinHttpTlsHandshakeClientLeg2End, + WinHttpTlsHandshakeClientLeg3Start, + WinHttpTlsHandshakeClientLeg3End, + WinHttpStreamWaitStart, + WinHttpStreamWaitEnd, + WinHttpSendRequestStart, + WinHttpSendRequestHeadersCompressionStart, + WinHttpSendRequestHeadersCompressionEnd, + WinHttpSendRequestHeadersEnd, + WinHttpSendRequestEnd, + WinHttpReceiveResponseStart, + WinHttpReceiveResponseHeadersDecompressionStart, + WinHttpReceiveResponseHeadersDecompressionEnd, + WinHttpReceiveResponseHeadersEnd, + WinHttpReceiveResponseBodyDecompressionDelta, + WinHttpReceiveResponseEnd, + WinHttpProxyTunnelStart, + WinHttpProxyTunnelEnd, + WinHttpProxyTlsHandshakeClientLeg1Start, + WinHttpProxyTlsHandshakeClientLeg1End, + WinHttpProxyTlsHandshakeClientLeg2Start, + WinHttpProxyTlsHandshakeClientLeg2End, + WinHttpProxyTlsHandshakeClientLeg3Start, + WinHttpProxyTlsHandshakeClientLeg3End, + WinHttpRequestTimeLast, + WinHttpRequestTimeMax = 64 +} WINHTTP_REQUEST_TIME_ENTRY; + +typedef struct _WINHTTP_REQUEST_TIMES +{ + ULONG cTimes; + ULONGLONG rgullTimes[WinHttpRequestTimeMax]; +} WINHTTP_REQUEST_TIMES, *PWINHTTP_REQUEST_TIMES; + +typedef enum _WINHTTP_REQUEST_STAT_ENTRY +{ + WinHttpConnectFailureCount = 0, + WinHttpProxyFailureCount, + WinHttpTlsHandshakeClientLeg1Size, + WinHttpTlsHandshakeServerLeg1Size, + WinHttpTlsHandshakeClientLeg2Size, + WinHttpTlsHandshakeServerLeg2Size, + WinHttpRequestHeadersSize, + WinHttpRequestHeadersCompressedSize, + WinHttpResponseHeadersSize, + WinHttpResponseHeadersCompressedSize, + WinHttpResponseBodySize, + WinHttpResponseBodyCompressedSize, + WinHttpProxyTlsHandshakeClientLeg1Size, + WinHttpProxyTlsHandshakeServerLeg1Size, + WinHttpProxyTlsHandshakeClientLeg2Size, + WinHttpProxyTlsHandshakeServerLeg2Size, + WinHttpRequestStatLast, + WinHttpRequestStatMax = 32 +} WINHTTP_REQUEST_STAT_ENTRY; + +#define WINHTTP_REQUEST_STAT_FLAG_TCP_FAST_OPEN 0x00000001 +#define WINHTTP_REQUEST_STAT_FLAG_TLS_SESSION_RESUMPTION 0x00000002 +#define WINHTTP_REQUEST_STAT_FLAG_TLS_FALSE_START 0x00000004 +#define WINHTTP_REQUEST_STAT_FLAG_PROXY_TLS_SESSION_RESUMPTION 0x00000008 +#define WINHTTP_REQUEST_STAT_FLAG_PROXY_TLS_FALSE_START 0x00000010 +#define WINHTTP_REQUEST_STAT_FLAG_FIRST_REQUEST 0x00000020 + +typedef struct _WINHTTP_REQUEST_STATS +{ + ULONGLONG ullFlags; + ULONG ulIndex; + ULONG cStats; + ULONGLONG rgullStats[WinHttpRequestStatMax]; +} WINHTTP_REQUEST_STATS, *PWINHTTP_REQUEST_STATS; + +typedef enum _WINHTTP_WEB_SOCKET_OPERATION +{ + WINHTTP_WEB_SOCKET_SEND_OPERATION = 0, + WINHTTP_WEB_SOCKET_RECEIVE_OPERATION = 1, + WINHTTP_WEB_SOCKET_CLOSE_OPERATION = 2, + WINHTTP_WEB_SOCKET_SHUTDOWN_OPERATION = 3 +} WINHTTP_WEB_SOCKET_OPERATION; + +typedef enum _WINHTTP_WEB_SOCKET_BUFFER_TYPE +{ + WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE = 0, + WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE = 1, + WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE = 2, + WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE = 3, + WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE = 4 +} WINHTTP_WEB_SOCKET_BUFFER_TYPE; + +typedef enum _WINHTTP_WEB_SOCKET_CLOSE_STATUS +{ + WINHTTP_WEB_SOCKET_SUCCESS_CLOSE_STATUS = 1000, + WINHTTP_WEB_SOCKET_ENDPOINT_TERMINATED_CLOSE_STATUS = 1001, + WINHTTP_WEB_SOCKET_PROTOCOL_ERROR_CLOSE_STATUS = 1002, + WINHTTP_WEB_SOCKET_INVALID_DATA_TYPE_CLOSE_STATUS = 1003, + WINHTTP_WEB_SOCKET_EMPTY_CLOSE_STATUS = 1005, + WINHTTP_WEB_SOCKET_ABORTED_CLOSE_STATUS = 1006, + WINHTTP_WEB_SOCKET_INVALID_PAYLOAD_CLOSE_STATUS = 1007, + WINHTTP_WEB_SOCKET_POLICY_VIOLATION_CLOSE_STATUS = 1008, + WINHTTP_WEB_SOCKET_MESSAGE_TOO_BIG_CLOSE_STATUS = 1009, + WINHTTP_WEB_SOCKET_UNSUPPORTED_EXTENSIONS_CLOSE_STATUS = 1010, + WINHTTP_WEB_SOCKET_SERVER_ERROR_CLOSE_STATUS = 1011, + WINHTTP_WEB_SOCKET_SECURE_HANDSHAKE_ERROR_CLOSE_STATUS = 1015 +} WINHTTP_WEB_SOCKET_CLOSE_STATUS; + +typedef struct _WINHTTP_WEB_SOCKET_ASYNC_RESULT +{ + WINHTTP_ASYNC_RESULT AsyncResult; + WINHTTP_WEB_SOCKET_OPERATION Operation; +} WINHTTP_WEB_SOCKET_ASYNC_RESULT; + +typedef struct _WINHTTP_WEB_SOCKET_STATUS +{ + DWORD dwBytesTransferred; + WINHTTP_WEB_SOCKET_BUFFER_TYPE eBufferType; +} WINHTTP_WEB_SOCKET_STATUS; + +#define WINHTTP_WEB_SOCKET_MAX_CLOSE_REASON_LENGTH 123 +#define WINHTTP_WEB_SOCKET_MIN_KEEPALIVE_VALUE 15000 + #ifdef __cplusplus extern "C" { #endif @@ -596,6 +862,13 @@ WinHttpCrackUrl( _In_ DWORD, _Inout_ LPURL_COMPONENTS); +DWORD +WINHTTPAPI +WINAPI +WinHttpCreateProxyResolver( + _Out_ HINTERNET, + _Out_ HINTERNET*); + _Success_(return != 0) BOOL WINAPI @@ -605,6 +878,18 @@ WinHttpCreateUrl( _Out_writes_to_opt_(*pdwUrlLength, *pdwUrlLength) LPWSTR, _Inout_ LPDWORD pdwUrlLength); +void +WINHTTPAPI +WINAPI +WinHttpFreeProxyResult( + _Inout_ WINHTTP_PROXY_RESULT*); + +void +WINHTTPAPI +WINAPI +WinHttpFreeProxyResultEx( + _Inout_ WINHTTP_PROXY_RESULT_EX*); + BOOL WINAPI WinHttpGetDefaultProxyConfiguration( @@ -616,6 +901,7 @@ WinHttpGetIEProxyConfigForCurrentUser( _Inout_ WINHTTP_CURRENT_USER_IE_PROXY_CONFIG*); BOOL +WINHTTPAPI WINAPI WinHttpGetProxyForUrl( _In_ HINTERNET, @@ -623,7 +909,59 @@ WinHttpGetProxyForUrl( _In_ WINHTTP_AUTOPROXY_OPTIONS*, _Out_ WINHTTP_PROXY_INFO*); +DWORD +WINHTTPAPI +WINAPI +WinHttpGetProxyForUrlEx( + _In_ HINTERNET, + _In_ PCWSTR, + _In_ WINHTTP_AUTOPROXY_OPTIONS*, + _Out_ DWORD_PTR); + +DWORD +WINHTTPAPI +WINAPI +WinHttpGetProxyForUrlEx2( + _In_ HINTERNET, + _In_ PCWSTR, + _In_ WINHTTP_AUTOPROXY_OPTIONS*, + DWORD, + BYTE*, + _Out_ DWORD_PTR); + +DWORD +WINHTTPAPI +WINAPI +WinHttpGetProxyResult( + _In_ HINTERNET, + _Out_ WINHTTP_PROXY_RESULT*); + +DWORD +WINHTTPAPI +WINAPI +WinHttpGetProxyResultEx( + _In_ HINTERNET, + _Out_ WINHTTP_PROXY_RESULT_EX*); + +DWORD +WINHTTPAPI +WINAPI +WinHttpGetProxySettingsVersion( + _In_ HINTERNET, + _Out_ DWORD*); + +DWORD +WINHTTPAPI +WINAPI +WinHttpIsHostInProxyBypassList( + _In_ const WINHTTP_PROXY_INFO*, + _In_ PCWSTR, + _In_ INTERNET_SCHEME, + _In_ INTERNET_PORT, + _Inout_ BOOL*); + HINTERNET +WINHTTPAPI WINAPI WinHttpOpen( _In_opt_z_ LPCWSTR, @@ -633,6 +971,7 @@ WinHttpOpen( _In_ DWORD); HINTERNET +WINHTTPAPI WINAPI WinHttpOpenRequest( _In_ HINTERNET, @@ -644,6 +983,7 @@ WinHttpOpenRequest( _In_ DWORD); BOOL +WINHTTPAPI WINAPI WinHttpQueryAuthParams( _In_ HINTERNET, @@ -651,6 +991,7 @@ WinHttpQueryAuthParams( _Out_ LPVOID*); BOOL +WINHTTPAPI WINAPI WinHttpQueryAuthSchemes( _In_ HINTERNET, @@ -659,6 +1000,7 @@ WinHttpQueryAuthSchemes( _Out_ LPDWORD); BOOL +WINHTTPAPI WINAPI WinHttpQueryDataAvailable( _In_ HINTERNET, @@ -666,6 +1008,7 @@ WinHttpQueryDataAvailable( _Success_(return != 0) BOOL +WINHTTPAPI WINAPI WinHttpQueryHeaders( _In_ HINTERNET, @@ -677,6 +1020,7 @@ WinHttpQueryHeaders( _Success_(return != 0) BOOL +WINHTTPAPI WINAPI WinHttpQueryOption( _In_ HINTERNET, @@ -685,6 +1029,7 @@ WinHttpQueryOption( _Inout_ LPDWORD lpdwBufferLength); BOOL +WINHTTPAPI WINAPI WinHttpReadData( _In_ HINTERNET, @@ -692,9 +1037,24 @@ WinHttpReadData( _In_ DWORD dwNumberOfBytesToRead, _Out_ LPDWORD lpdwNumberOfBytesRead); -BOOL WINAPI WinHttpReceiveResponse(_In_ HINTERNET, _Reserved_ LPVOID); +DWORD +WINHTTPAPI +WINAPI +WinHttpReadProxySettings( + _In_ HINTERNET, + PCWSTR, + BOOL, + BOOL, + LPDWORD, + BOOL*, + _Out_ PWINHTTP_PROXY_SETTINGS); + +BOOL WINHTTPAPI WINAPI WinHttpReceiveResponse(_In_ HINTERNET, _Reserved_ LPVOID); + +DWORD WINHTTPAPI WINAPI WinHttpResetAutoProxy(_In_ HINTERNET, _In_ DWORD); BOOL +WINHTTPAPI WINAPI WinHttpSendRequest( _In_ HINTERNET, @@ -706,11 +1066,13 @@ WinHttpSendRequest( _In_ DWORD_PTR); BOOL +WINHTTPAPI WINAPI WinHttpSetDefaultProxyConfiguration( _In_ WINHTTP_PROXY_INFO*); BOOL +WINHTTPAPI WINAPI WinHttpSetCredentials( _In_ HINTERNET, @@ -721,6 +1083,7 @@ WinHttpSetCredentials( _Reserved_ LPVOID); BOOL +WINHTTPAPI WINAPI WinHttpSetOption( _In_opt_ HINTERNET, @@ -741,6 +1104,7 @@ WinHttpSetOption( _In_ DWORD dwBufferLength); WINHTTP_STATUS_CALLBACK +WINHTTPAPI WINAPI WinHttpSetStatusCallback( _In_ HINTERNET, @@ -749,6 +1113,7 @@ WinHttpSetStatusCallback( _Reserved_ DWORD_PTR); BOOL +WINHTTPAPI WINAPI WinHttpSetTimeouts( _In_ HINTERNET, @@ -758,6 +1123,7 @@ WinHttpSetTimeouts( _In_ int); BOOL +WINHTTPAPI WINAPI WinHttpTimeFromSystemTime( _In_ CONST SYSTEMTIME *, @@ -765,7 +1131,62 @@ WinHttpTimeFromSystemTime( BOOL WINAPI WinHttpTimeToSystemTime(_In_z_ LPCWSTR, _Out_ SYSTEMTIME*); +DWORD +WINHTTPAPI +WINAPI +WinHttpWebSocketClose( + _In_ HINTERNET, + _In_ USHORT, + _In_opt_ PVOID, + _In_ DWORD); + +HINTERNET +WINHTTPAPI +WINAPI +WinHttpWebSocketCompleteUpgrade( + _In_ HINTERNET, + _In_opt_ DWORD_PTR); + +DWORD +WINHTTPAPI +WINAPI +WinHttpWebSocketQueryCloseStatus( + _In_ HINTERNET, + _Out_ USHORT*, + _Out_ void*, + _In_ DWORD, + _Out_ DWORD*); + +DWORD +WINHTTPAPI +WINAPI +WinHttpWebSocketReceive( + _In_ HINTERNET, + _Out_ PVOID, + _In_ DWORD, + _Out_ DWORD*, + _Out_ WINHTTP_WEB_SOCKET_BUFFER_TYPE*); + +DWORD +WINHTTPAPI +WINAPI +WinHttpWebSocketSend( + _In_ HINTERNET, + _In_ WINHTTP_WEB_SOCKET_BUFFER_TYPE, + _In_reads_bytes_(dwBufferLength) PVOID pvBuffer, + _In_ DWORD dwBufferLength); + +DWORD +WINHTTPAPI +WINAPI +WinHttpWebSocketShutdown( + _In_ HINTERNET, + _In_ USHORT, + _In_reads_bytes_(dwReasonLength) _In_opt_ void* pvReason, + _In_ DWORD dwReasonLength); + BOOL +WINHTTPAPI WINAPI WinHttpWriteData( _In_ HINTERNET, @@ -773,6 +1194,14 @@ WinHttpWriteData( _In_ DWORD dwNumberOfBytesToWrite, _Out_ LPDWORD); +DWORD +WINHTTPAPI +WINAPI +WinHttpWriteProxySettings( + _In_ HINTERNET, + BOOL, + _In_ PWINHTTP_PROXY_SETTINGS); + #ifdef __cplusplus } #endif diff --git a/sdk/include/psdk/ws2def.h b/sdk/include/psdk/ws2def.h index c252539d9eb..033f0e982d3 100644 --- a/sdk/include/psdk/ws2def.h +++ b/sdk/include/psdk/ws2def.h @@ -308,6 +308,12 @@ typedef USHORT ADDRESS_FAMILY; #define AI_DISABLE_IDN_ENCODING 0x00080000 +#ifndef USE_WS_PREFIX +#define AI_DNS_ONLY 0x00000010 +#else +#define WS_AI_DNS_ONLY 0x00000010 +#endif + #define NS_ALL 0 #define NS_SAP 1 diff --git a/sdk/tools/winesync/winhttp.cfg b/sdk/tools/winesync/winhttp.cfg new file mode 100644 index 00000000000..5ef0626c6e0 --- /dev/null +++ b/sdk/tools/winesync/winhttp.cfg @@ -0,0 +1,7 @@ +directories: + dlls/winhttp: dll/win32/winhttp + dlls/winhttp/tests: modules/rostests/winetests/winhttp +files: + include/winhttp.h: sdk/include/psdk/winhttp.h +tags: + wine: wine-10.0