From d33b71e9d4427aa5beea3a5f5dfbf5b30a09a060 Mon Sep 17 00:00:00 2001 From: Joachim Henze Date: Sat, 26 May 2018 17:00:47 +0200 Subject: [PATCH] [0.4.9] [WINHTTP] Revert to SVN r75943 to fix regression CORE-13952 Our RCs were still affected by that regression. The revert allows to run the current Online! setup of Flash-Player 29.0.0.171 to download. (I was able to watch a flash video in Opera 12.18 afterwards.) --- dll/win32/winhttp/CMakeLists.txt | 9 +- dll/win32/winhttp/cookie.c | 14 +- dll/win32/winhttp/handle.c | 12 - dll/win32/winhttp/inet_ntop.c | 12 +- dll/win32/winhttp/main.c | 23 +- dll/win32/winhttp/net.c | 252 ++--- dll/win32/winhttp/precomp.h | 26 - dll/win32/winhttp/request.c | 1517 +++++++++++---------------- dll/win32/winhttp/session.c | 90 +- dll/win32/winhttp/url.c | 13 - dll/win32/winhttp/winhttp_private.h | 86 +- 11 files changed, 857 insertions(+), 1197 deletions(-) delete mode 100644 dll/win32/winhttp/precomp.h diff --git a/dll/win32/winhttp/CMakeLists.txt b/dll/win32/winhttp/CMakeLists.txt index 988c769b0b0..f0c4df8be60 100644 --- a/dll/win32/winhttp/CMakeLists.txt +++ b/dll/win32/winhttp/CMakeLists.txt @@ -1,7 +1,4 @@ -remove_definitions(-D_WIN32_WINNT=0x502) -add_definitions(-D_WIN32_WINNT=0x600) - add_definitions( -D__WINESRC__ -D_WINE) @@ -17,7 +14,7 @@ list(APPEND SOURCE request.c session.c url.c - precomp.h) + winhttp_private.h) set_source_files_properties(rsrc.rc PROPERTIES OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/winhttp_tlb.tlb) add_typelib(winhttp_tlb.idl) @@ -30,7 +27,7 @@ add_library(winhttp SHARED set_module_type(winhttp win32dll) target_link_libraries(winhttp uuid wine) add_delay_importlibs(winhttp oleaut32 ole32 crypt32 secur32) -add_importlibs(winhttp user32 advapi32 ws2_32 jsproxy kernel32_vista msvcrt kernel32 ntdll) +add_importlibs(winhttp user32 advapi32 ws2_32 jsproxy msvcrt kernel32 ntdll) add_dependencies(winhttp stdole2) -add_pch(winhttp precomp.h SOURCE) +add_pch(winhttp winhttp_private.h SOURCE) add_cd_file(TARGET winhttp DESTINATION reactos/system32 FOR all) diff --git a/dll/win32/winhttp/cookie.c b/dll/win32/winhttp/cookie.c index b4b25304f7f..eb37d6f8526 100644 --- a/dll/win32/winhttp/cookie.c +++ b/dll/win32/winhttp/cookie.c @@ -16,20 +16,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include "config.h" -#include - -#include "wine/debug.h" -#include "wine/list.h" - -#include "windef.h" -#include "winbase.h" -#include "winhttp.h" - #include "winhttp_private.h" -WINE_DEFAULT_DEBUG_CHANNEL(winhttp); - static domain_t *add_domain( session_t *session, WCHAR *name ) { domain_t *domain; @@ -152,7 +140,7 @@ static cookie_t *parse_cookie( const WCHAR *string ) if (*p++ == '=') { - while (*p == ' ') p++; + while (*p && *p == ' ') p++; len = strlenW( p ); while (len && p[len - 1] == ' ') len--; diff --git a/dll/win32/winhttp/handle.c b/dll/win32/winhttp/handle.c index 6026a496103..e67e5e3eba3 100644 --- a/dll/win32/winhttp/handle.c +++ b/dll/win32/winhttp/handle.c @@ -18,20 +18,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include "config.h" -#include "wine/port.h" -#include "wine/debug.h" - -#include - -#include "windef.h" -#include "winbase.h" -#include "winhttp.h" - #include "winhttp_private.h" -WINE_DEFAULT_DEBUG_CHANNEL(winhttp); - #define HANDLE_CHUNK_SIZE 0x10 static CRITICAL_SECTION handle_cs; diff --git a/dll/win32/winhttp/inet_ntop.c b/dll/win32/winhttp/inet_ntop.c index 99d5ccdcf19..3ed42ef6bb0 100644 --- a/dll/win32/winhttp/inet_ntop.c +++ b/dll/win32/winhttp/inet_ntop.c @@ -51,18 +51,16 @@ static const char *inet_ntop6(const u_char *src, char *dst, size_t size); * author: * Paul Vixie, 1996. */ - -PCSTR -WSAAPI -inet_ntop(INT Family, PVOID pAddr, PSTR pStringBuf, size_t StringBufSize) +const char * +inet_ntop(int af, const void *src, char *dst, size_t size) { - switch (Family) { + switch (af) { case AF_INET: - return (inet_ntop4(pAddr, pStringBuf, StringBufSize)); + return (inet_ntop4(src, dst, size)); #ifdef INET6 case AF_INET6: - return (inet_ntop6(pAddr, pStringBuf, StringBufSize)); + return (inet_ntop6(src, dst, size)); #endif default: WSASetLastError(WSAEAFNOSUPPORT); diff --git a/dll/win32/winhttp/main.c b/dll/win32/winhttp/main.c index a63f28cf108..f46b59aa8f0 100644 --- a/dll/win32/winhttp/main.c +++ b/dll/win32/winhttp/main.c @@ -16,23 +16,12 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#define COBJMACROS -#include "config.h" -#include - -#include "windef.h" -#include "winbase.h" -#include "objbase.h" -#include "rpcproxy.h" -#include "httprequest.h" -#include "winhttp.h" - -#include "wine/debug.h" #include "winhttp_private.h" -HINSTANCE winhttp_instance; +#include +#include -WINE_DEFAULT_DEBUG_CHANNEL(winhttp); +static HINSTANCE instance; /****************************************************************** * DllMain (winhttp.@) @@ -42,7 +31,7 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv) switch(fdwReason) { case DLL_PROCESS_ATTACH: - winhttp_instance = hInstDLL; + instance = hInstDLL; DisableThreadLibraryCalls(hInstDLL); break; case DLL_PROCESS_DETACH: @@ -169,7 +158,7 @@ HRESULT WINAPI DllCanUnloadNow(void) */ HRESULT WINAPI DllRegisterServer(void) { - return __wine_register_resources( winhttp_instance ); + return __wine_register_resources( instance ); } /*********************************************************************** @@ -177,5 +166,5 @@ HRESULT WINAPI DllRegisterServer(void) */ HRESULT WINAPI DllUnregisterServer(void) { - return __wine_unregister_resources( winhttp_instance ); + return __wine_unregister_resources( instance ); } diff --git a/dll/win32/winhttp/net.c b/dll/win32/winhttp/net.c index e9ff86a165a..737d8e59d30 100644 --- a/dll/win32/winhttp/net.c +++ b/dll/win32/winhttp/net.c @@ -17,15 +17,11 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include "config.h" -#include "wine/port.h" +#include "winhttp_private.h" -#include -#include -#include #include +#include -#include #ifdef HAVE_SYS_SOCKET_H # include #endif @@ -39,25 +35,6 @@ # include #endif -#define NONAMELESSUNION - -#include "wine/debug.h" -#include "wine/library.h" - -#include "windef.h" -#include "winbase.h" -#include "winhttp.h" -#include "wincrypt.h" -#include "schannel.h" - -#include "winhttp_private.h" - -/* to avoid conflicts with the Unix socket headers */ -#define USE_WS_PREFIX -#include "winsock2.h" - -WINE_DEFAULT_DEBUG_CHANNEL(winhttp); - #ifndef HAVE_GETADDRINFO /* critical section to protect non-reentrant gethostbyname() */ @@ -154,7 +131,7 @@ static int sock_send(int fd, const void *msg, size_t len, int flags) int ret; do { - if ((ret = send(fd, msg, len, flags)) == -1) WARN("send error %s\n", strerror(errno)); + ret = send(fd, msg, len, flags); } while(ret == -1 && errno == EINTR); return ret; @@ -165,7 +142,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 %s\n", strerror(errno)); + ret = recv(fd, msg, len, flags); } while(ret == -1 && errno == EINTR); return ret; @@ -264,6 +241,41 @@ static DWORD netconn_verify_cert( PCCERT_CONTEXT cert, WCHAR *server, DWORD secu return err; } +static SecHandle cred_handle; +static BOOL cred_handle_initialized; + +static CRITICAL_SECTION init_sechandle_cs; +static CRITICAL_SECTION_DEBUG init_sechandle_cs_debug = { + 0, 0, &init_sechandle_cs, + { &init_sechandle_cs_debug.ProcessLocksList, + &init_sechandle_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": init_sechandle_cs") } +}; +static CRITICAL_SECTION init_sechandle_cs = { &init_sechandle_cs_debug, -1, 0, 0, 0, 0 }; + +static BOOL ensure_cred_handle(void) +{ + BOOL ret = TRUE; + + EnterCriticalSection(&init_sechandle_cs); + + if(!cred_handle_initialized) { + SECURITY_STATUS res; + + res = AcquireCredentialsHandleW(NULL, (WCHAR*)UNISP_NAME_W, SECPKG_CRED_OUTBOUND, NULL, NULL, + NULL, NULL, &cred_handle, NULL); + if(res == SEC_E_OK) { + cred_handle_initialized = TRUE; + }else { + WARN("AcquireCredentialsHandleW failed: %u\n", res); + ret = FALSE; + } + } + + LeaveCriticalSection(&init_sechandle_cs); + return ret; +} + #ifdef __REACTOS__ static BOOL winsock_initialized = FALSE; BOOL netconn_init_winsock() @@ -286,8 +298,18 @@ BOOL netconn_init_winsock() #endif +BOOL netconn_init( netconn_t *conn ) +{ + memset(conn, 0, sizeof(*conn)); + conn->socket = -1; + return TRUE; +} + void netconn_unload( void ) { + if(cred_handle_initialized) + FreeCredentialsHandle(&cred_handle); + DeleteCriticalSection(&init_sechandle_cs); #ifndef HAVE_GETADDRINFO DeleteCriticalSection(&cs_gethostbyname); #endif @@ -297,37 +319,55 @@ void netconn_unload( void ) #endif } -netconn_t *netconn_create( hostdata_t *host, const struct sockaddr_storage *sockaddr, int timeout ) +BOOL netconn_connected( netconn_t *conn ) { - netconn_t *conn; - unsigned int addr_len; - BOOL ret = FALSE; - int res; - ULONG state; + return (conn->socket != -1); +} - conn = heap_alloc_zero(sizeof(*conn)); - if (!conn) return NULL; - conn->host = host; - conn->sockaddr = *sockaddr; - if ((conn->socket = socket( sockaddr->ss_family, SOCK_STREAM, 0 )) == -1) +BOOL netconn_create( netconn_t *conn, int domain, int type, int protocol ) +{ + if ((conn->socket = socket( domain, type, protocol )) == -1) { WARN("unable to create socket (%s)\n", strerror(errno)); set_last_error( sock_get_error( errno ) ); - heap_free(conn); - return NULL; + return FALSE; } + return TRUE; +} - switch (conn->sockaddr.ss_family) +BOOL netconn_close( netconn_t *conn ) +{ + int res; + + if (conn->secure) { - case AF_INET: - addr_len = sizeof(struct sockaddr_in); - break; - case AF_INET6: - addr_len = sizeof(struct sockaddr_in6); - break; - default: - assert(0); + heap_free( conn->peek_msg_mem ); + conn->peek_msg_mem = NULL; + conn->peek_msg = NULL; + conn->peek_len = 0; + heap_free(conn->ssl_buf); + conn->ssl_buf = NULL; + heap_free(conn->extra_buf); + conn->extra_buf = NULL; + conn->extra_len = 0; + DeleteSecurityContext(&conn->ssl_ctx); + conn->secure = FALSE; } + res = closesocket( conn->socket ); + conn->socket = -1; + if (res == -1) + { + set_last_error( sock_get_error( errno ) ); + return FALSE; + } + return TRUE; +} + +BOOL netconn_connect( netconn_t *conn, const struct sockaddr *sockaddr, unsigned int addr_len, int timeout ) +{ + BOOL ret = FALSE; + int res; + ULONG state; if (timeout > 0) { @@ -338,7 +378,7 @@ netconn_t *netconn_create( hostdata_t *host, const struct sockaddr_storage *sock for (;;) { res = 0; - if (connect( conn->socket, (const struct sockaddr *)&conn->sockaddr, addr_len ) < 0) + if (connect( conn->socket, sockaddr, addr_len ) < 0) { res = sock_get_error( errno ); if (res == WSAEWOULDBLOCK || res == WSAEINPROGRESS) @@ -396,35 +436,11 @@ netconn_t *netconn_create( hostdata_t *host, const struct sockaddr_storage *sock { WARN("unable to connect to host (%d)\n", res); set_last_error( res ); - netconn_close( conn ); - return NULL; } - return conn; + return ret; } -BOOL netconn_close( netconn_t *conn ) -{ - int res; - - if (conn->secure) - { - heap_free( conn->peek_msg_mem ); - heap_free(conn->ssl_buf); - heap_free(conn->extra_buf); - DeleteSecurityContext(&conn->ssl_ctx); - } - res = closesocket( conn->socket ); - release_host( conn->host ); - heap_free(conn); - if (res == -1) - { - set_last_error( sock_get_error( errno ) ); - return FALSE; - } - return TRUE; -} - -BOOL netconn_secure_connect( netconn_t *conn, WCHAR *hostname, DWORD security_flags, CredHandle *cred_handle ) +BOOL netconn_secure_connect( netconn_t *conn, WCHAR *hostname ) { 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}; @@ -440,11 +456,14 @@ BOOL netconn_secure_connect( netconn_t *conn, WCHAR *hostname, DWORD security_fl 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; + if(!ensure_cred_handle()) + return FALSE; + read_buf = heap_alloc(read_buf_size); if(!read_buf) return FALSE; - status = InitializeSecurityContextW(cred_handle, NULL, hostname, isc_req_flags, 0, 0, NULL, 0, + status = InitializeSecurityContextW(&cred_handle, NULL, hostname, isc_req_flags, 0, 0, NULL, 0, &ctx, &out_desc, &attrs, NULL); assert(status != SEC_E_OK); @@ -496,6 +515,7 @@ BOOL netconn_secure_connect( netconn_t *conn, WCHAR *hostname, DWORD security_fl size = sock_recv(conn->socket, read_buf+in_bufs[0].cbBuffer, read_buf_size-in_bufs[0].cbBuffer, 0); if(size < 1) { + WARN("recv error\n"); status = ERROR_WINHTTP_SECURE_CHANNEL_ERROR; break; } @@ -504,7 +524,7 @@ BOOL netconn_secure_connect( netconn_t *conn, WCHAR *hostname, DWORD security_fl in_bufs[0].cbBuffer += size; in_bufs[0].pvBuffer = read_buf; - status = InitializeSecurityContextW(cred_handle, &ctx, hostname, isc_req_flags, 0, 0, &in_desc, + 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); @@ -520,7 +540,7 @@ BOOL netconn_secure_connect( netconn_t *conn, WCHAR *hostname, DWORD security_fl status = QueryContextAttributesW(&ctx, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (void*)&cert); if(status == SEC_E_OK) { - res = netconn_verify_cert(cert, hostname, security_flags); + res = netconn_verify_cert(cert, hostname, conn->security_flags); CertFreeCertificateContext(cert); if(res != ERROR_SUCCESS) { WARN("cert verify failed: %u\n", res); @@ -585,6 +605,7 @@ static BOOL send_ssl_chunk(netconn_t *conn, const void *msg, size_t size) BOOL netconn_send( netconn_t *conn, const void *msg, size_t len, int *sent ) { + if (!netconn_connected( conn )) return FALSE; if (conn->secure) { const BYTE *ptr = msg; @@ -631,8 +652,10 @@ static BOOL read_ssl_chunk(netconn_t *conn, void *buf, SIZE_T buf_size, SIZE_T * 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) + if(buf_len < 0) { + WARN("recv failed\n"); return FALSE; + } if(!buf_len) { *eof = TRUE; @@ -706,6 +729,7 @@ static BOOL read_ssl_chunk(netconn_t *conn, void *buf, SIZE_T buf_size, SIZE_T * BOOL netconn_recv( netconn_t *conn, void *buf, size_t len, int flags, int *recvd ) { *recvd = 0; + if (!netconn_connected( conn )) return FALSE; if (!len) return TRUE; if (conn->secure) @@ -762,7 +786,13 @@ BOOL netconn_recv( netconn_t *conn, void *buf, size_t len, int flags, int *recvd ULONG netconn_query_data_available( netconn_t *conn ) { - return conn->secure ? conn->peek_len : 0; + if(!netconn_connected(conn)) + return 0; + + if(conn->secure) + return conn->peek_len; + + return 0; } DWORD netconn_set_timeout( netconn_t *netconn, BOOL send, int value ) @@ -781,37 +811,7 @@ DWORD netconn_set_timeout( netconn_t *netconn, BOOL send, int value ) return ERROR_SUCCESS; } -BOOL netconn_is_alive( netconn_t *netconn ) -{ -#ifdef MSG_DONTWAIT - ssize_t len; - BYTE b; - - len = recv( netconn->socket, &b, 1, MSG_PEEK | MSG_DONTWAIT ); - return len == 1 || (len == -1 && errno == EWOULDBLOCK); -#elif defined(__MINGW32__) || defined(_MSC_VER) - ULONG mode; - int len; - char b; - - mode = 1; - if(!ioctlsocket(netconn->socket, FIONBIO, &mode)) - return FALSE; - - len = recv(netconn->socket, &b, 1, MSG_PEEK); - - mode = 0; - if(!ioctlsocket(netconn->socket, FIONBIO, &mode)) - return FALSE; - - return len == 1 || (len == -1 && WSAGetLastError() == WSAEWOULDBLOCK); -#else - FIXME("not supported on this platform\n"); - return TRUE; -#endif -} - -static DWORD resolve_hostname( const WCHAR *hostnameW, INTERNET_PORT port, struct sockaddr_storage *sa ) +static DWORD resolve_hostname( const WCHAR *hostnameW, INTERNET_PORT port, struct sockaddr *sa, socklen_t *sa_len ) { char *hostname; #ifdef HAVE_GETADDRINFO @@ -845,6 +845,13 @@ static DWORD resolve_hostname( const WCHAR *hostnameW, INTERNET_PORT port, struc } } heap_free( hostname ); + if (*sa_len < res->ai_addrlen) + { + WARN("address too small\n"); + freeaddrinfo( res ); + return ERROR_WINHTTP_NAME_NOT_RESOLVED; + } + *sa_len = res->ai_addrlen; memcpy( sa, res->ai_addr, res->ai_addrlen ); /* Copy port */ switch (res->ai_family) @@ -870,6 +877,13 @@ static DWORD resolve_hostname( const WCHAR *hostnameW, INTERNET_PORT port, struc LeaveCriticalSection( &cs_gethostbyname ); return ERROR_WINHTTP_NAME_NOT_RESOLVED; } + if (*sa_len < sizeof(struct sockaddr_in)) + { + WARN("address too small\n"); + LeaveCriticalSection( &cs_gethostbyname ); + return ERROR_WINHTTP_NAME_NOT_RESOLVED; + } + *sa_len = sizeof(struct sockaddr_in); memset( sa, 0, sizeof(struct sockaddr_in) ); memcpy( &sin->sin_addr, he->h_addr, he->h_length ); sin->sin_family = he->h_addrtype; @@ -882,18 +896,19 @@ static DWORD resolve_hostname( const WCHAR *hostnameW, INTERNET_PORT port, struc struct resolve_args { - const WCHAR *hostname; - INTERNET_PORT port; - struct sockaddr_storage *sa; + const WCHAR *hostname; + INTERNET_PORT port; + struct sockaddr *sa; + socklen_t *sa_len; }; static DWORD CALLBACK resolve_proc( LPVOID arg ) { struct resolve_args *ra = arg; - return resolve_hostname( ra->hostname, ra->port, ra->sa ); + return resolve_hostname( ra->hostname, ra->port, ra->sa, ra->sa_len ); } -BOOL netconn_resolve( WCHAR *hostname, INTERNET_PORT port, struct sockaddr_storage *sa, int timeout ) +BOOL netconn_resolve( WCHAR *hostname, INTERNET_PORT port, struct sockaddr *sa, socklen_t *sa_len, int timeout ) { DWORD ret; @@ -906,6 +921,7 @@ BOOL netconn_resolve( WCHAR *hostname, INTERNET_PORT port, struct sockaddr_stora ra.hostname = hostname; ra.port = port; ra.sa = sa; + ra.sa_len = sa_len; thread = CreateThread( NULL, 0, resolve_proc, &ra, 0, NULL ); if (!thread) return FALSE; @@ -915,7 +931,7 @@ BOOL netconn_resolve( WCHAR *hostname, INTERNET_PORT port, struct sockaddr_stora else ret = ERROR_WINHTTP_TIMEOUT; CloseHandle( thread ); } - else ret = resolve_hostname( hostname, port, sa ); + else ret = resolve_hostname( hostname, port, sa, sa_len ); if (ret) { diff --git a/dll/win32/winhttp/precomp.h b/dll/win32/winhttp/precomp.h deleted file mode 100644 index 53f0b1365dc..00000000000 --- a/dll/win32/winhttp/precomp.h +++ /dev/null @@ -1,26 +0,0 @@ - -#ifndef _WINHTTP_PRECOMP_H_ -#define _WINHTTP_PRECOMP_H_ - -#include - -#include - -#define WIN32_NO_STATUS -#define _INC_WINDOWS -#define COM_NO_WINDOWS_H - -#define COBJMACROS -#define NONAMELESSUNION - -#include -#include -#include -#include -#include - -#include - -#include "winhttp_private.h" - -#endif /* !_WINHTTP_PRECOMP_H_ */ diff --git a/dll/win32/winhttp/request.c b/dll/win32/winhttp/request.c index 5bb5b093373..d42f7dbb810 100644 --- a/dll/win32/winhttp/request.c +++ b/dll/win32/winhttp/request.c @@ -19,36 +19,18 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#define COBJMACROS -#include "config.h" -#include "wine/port.h" +#include "winhttp_private.h" -#include -#include #ifdef HAVE_ARPA_INET_H # include #endif -#include "windef.h" -#include "winbase.h" -#include "ole2.h" -#include "initguid.h" -#include "httprequest.h" -#include "httprequestid.h" -#include "schannel.h" -#include "winhttp.h" +#include +#include +#include +#include -#include "winhttp_private.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(winhttp); - -#ifdef __REACTOS__ #include "inet_ntop.c" -#endif - -#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}; @@ -523,7 +505,7 @@ BOOL WINAPI WinHttpAddRequestHeaders( HINTERNET hrequest, LPCWSTR headers, DWORD BOOL ret; request_t *request; - TRACE("%p, %s, %u, 0x%08x\n", hrequest, debugstr_wn(headers, len), len, flags); + TRACE("%p, %s, 0x%x, 0x%08x\n", hrequest, debugstr_w(headers), len, flags); if (!headers || !len) { @@ -558,7 +540,7 @@ static WCHAR *build_request_path( request_t *request ) 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 }; - LPCWSTR scheme = (request->netconn ? request->netconn->secure : (request->hdr.flags & WINHTTP_FLAG_SECURE)) ? https : http; + LPCWSTR scheme = request->netconn.secure ? https : http; int len; len = strlenW( scheme ) + strlenW( request->connect->hostname ); @@ -854,6 +836,619 @@ BOOL WINAPI WinHttpQueryHeaders( HINTERNET hrequest, DWORD level, LPCWSTR name, return ret; } +static LPWSTR concatenate_string_list( LPCWSTR *list, int len ) +{ + LPCWSTR *t; + LPWSTR str; + + for( t = list; *t ; t++ ) + len += strlenW( *t ); + len++; + + str = heap_alloc( len * sizeof(WCHAR) ); + if (!str) return NULL; + *str = 0; + + for( t = list; *t ; t++ ) + strcatW( str, *t ); + + return str; +} + +static LPWSTR build_header_request_string( request_t *request, LPCWSTR verb, + LPCWSTR path, LPCWSTR version ) +{ + static const WCHAR crlf[] = {'\r','\n',0}; + static const WCHAR space[] = { ' ',0 }; + static const WCHAR colon[] = { ':',' ',0 }; + static const WCHAR twocrlf[] = {'\r','\n','\r','\n', 0}; + LPWSTR requestString; + DWORD len, n; + LPCWSTR *req; + UINT i; + LPWSTR p; + + /* allocate space for an array of all the string pointers to be added */ + len = (request->num_headers) * 4 + 10; + req = heap_alloc( len * sizeof(LPCWSTR) ); + if (!req) return NULL; + + /* add the verb, path and HTTP version string */ + n = 0; + req[n++] = verb; + req[n++] = space; + req[n++] = path; + req[n++] = space; + req[n++] = version; + + /* Append custom request headers */ + for (i = 0; i < request->num_headers; i++) + { + if (request->headers[i].is_request) + { + req[n++] = crlf; + req[n++] = request->headers[i].field; + req[n++] = colon; + req[n++] = request->headers[i].value; + + TRACE("Adding custom header %s (%s)\n", + debugstr_w(request->headers[i].field), + debugstr_w(request->headers[i].value)); + } + } + + if( n >= len ) + ERR("oops. buffer overrun\n"); + + req[n] = NULL; + requestString = concatenate_string_list( req, 4 ); + heap_free( req ); + if (!requestString) return NULL; + + /* + * Set (header) termination string for request + * Make sure there are exactly two new lines at the end of the request + */ + p = &requestString[strlenW(requestString)-1]; + while ( (*p == '\n') || (*p == '\r') ) + p--; + strcpyW( p+1, twocrlf ); + + return requestString; +} + +static BOOL read_reply( request_t *request ); + +static BOOL secure_proxy_connect( request_t *request ) +{ + static const WCHAR verbConnect[] = {'C','O','N','N','E','C','T',0}; + static const WCHAR fmt[] = {'%','s',':','%','u',0}; + BOOL ret = FALSE; + LPWSTR path; + connect_t *connect = request->connect; + + path = heap_alloc( (strlenW( connect->hostname ) + 13) * sizeof(WCHAR) ); + if (path) + { + LPWSTR requestString; + + sprintfW( path, fmt, connect->hostname, connect->hostport ); + requestString = build_header_request_string( request, verbConnect, + path, http1_1 ); + heap_free( path ); + if (requestString) + { + LPSTR req_ascii = strdupWA( requestString ); + + heap_free( requestString ); + if (req_ascii) + { + int len = strlen( req_ascii ), bytes_sent; + + ret = netconn_send( &request->netconn, req_ascii, len, &bytes_sent ); + heap_free( req_ascii ); + if (ret) + ret = read_reply( request ); + } + } + } + return ret; +} + +#ifndef INET6_ADDRSTRLEN +#define INET6_ADDRSTRLEN 46 +#endif + +static WCHAR *addr_to_str( struct sockaddr *addr ) +{ + char buf[INET6_ADDRSTRLEN]; + void *src; + + switch (addr->sa_family) + { + case AF_INET: + src = &((struct sockaddr_in *)addr)->sin_addr; + break; + case AF_INET6: + src = &((struct sockaddr_in6 *)addr)->sin6_addr; + break; + default: + WARN("unsupported address family %d\n", addr->sa_family); + return NULL; + } + if (!inet_ntop( addr->sa_family, src, buf, sizeof(buf) )) return NULL; + return strdupAW( buf ); +} + +static BOOL open_connection( request_t *request ) +{ + connect_t *connect; + WCHAR *addressW = NULL; + INTERNET_PORT port; + socklen_t slen; + struct sockaddr *saddr; + DWORD len; + + if (netconn_connected( &request->netconn )) goto done; + + connect = request->connect; + port = connect->serverport ? connect->serverport : (request->hdr.flags & WINHTTP_FLAG_SECURE ? 443 : 80); + saddr = (struct sockaddr *)&connect->sockaddr; + slen = sizeof(struct sockaddr); + + if (!connect->resolved) + { + len = strlenW( connect->servername ) + 1; + send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME, connect->servername, len ); + + if (!netconn_resolve( connect->servername, port, saddr, &slen, request->resolve_timeout )) return FALSE; + connect->resolved = TRUE; + + if (!(addressW = addr_to_str( saddr ))) return FALSE; + len = strlenW( addressW ) + 1; + send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED, addressW, len ); + } + if (!addressW && !(addressW = addr_to_str( saddr ))) return FALSE; + TRACE("connecting to %s:%u\n", debugstr_w(addressW), port); + + send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, addressW, 0 ); + + if (!netconn_create( &request->netconn, saddr->sa_family, SOCK_STREAM, 0 )) + { + heap_free( addressW ); + return FALSE; + } + netconn_set_timeout( &request->netconn, TRUE, request->send_timeout ); + netconn_set_timeout( &request->netconn, FALSE, request->recv_timeout ); + if (!netconn_connect( &request->netconn, saddr, slen, request->connect_timeout )) + { + netconn_close( &request->netconn ); + heap_free( addressW ); + return FALSE; + } + if (request->hdr.flags & WINHTTP_FLAG_SECURE) + { + if (connect->session->proxy_server && + strcmpiW( connect->hostname, connect->servername )) + { + if (!secure_proxy_connect( request )) + { + heap_free( addressW ); + return FALSE; + } + } + if (!netconn_secure_connect( &request->netconn, connect->hostname )) + { + netconn_close( &request->netconn ); + heap_free( addressW ); + return FALSE; + } + } + + send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, addressW, strlenW(addressW) + 1 ); + +done: + request->read_pos = request->read_size = 0; + request->read_chunked = FALSE; + request->read_chunked_size = ~0u; + request->read_chunked_eof = FALSE; + heap_free( addressW ); + return TRUE; +} + +void close_connection( request_t *request ) +{ + if (!netconn_connected( &request->netconn )) return; + + send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION, 0, 0 ); + netconn_close( &request->netconn ); + send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED, 0, 0 ); +} + +static BOOL add_host_header( request_t *request, DWORD modifier ) +{ + BOOL ret; + DWORD len; + WCHAR *host; + static const WCHAR fmt[] = {'%','s',':','%','u',0}; + connect_t *connect = request->connect; + INTERNET_PORT port; + + port = connect->hostport ? connect->hostport : (request->hdr.flags & WINHTTP_FLAG_SECURE ? 443 : 80); + + if (port == INTERNET_DEFAULT_HTTP_PORT || port == INTERNET_DEFAULT_HTTPS_PORT) + { + return process_header( request, attr_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 ); + return ret; +} + +static void clear_response_headers( request_t *request ) +{ + unsigned int i; + + for (i = 0; i < request->num_headers; i++) + { + if (!request->headers[i].field) continue; + if (!request->headers[i].value) continue; + if (request->headers[i].is_request) continue; + delete_header( request, i ); + i--; + } +} + +/* remove some amount of data from the read buffer */ +static void remove_data( request_t *request, int count ) +{ + if (!(request->read_size -= count)) request->read_pos = 0; + else request->read_pos += count; +} + +/* read some more data into the read buffer */ +static BOOL read_more_data( request_t *request, int maxlen, BOOL notify ) +{ + int len; + BOOL ret; + + if (request->read_chunked_eof) return FALSE; + + if (request->read_size && request->read_pos) + { + /* move existing data to the start of the buffer */ + memmove( request->read_buf, request->read_buf + request->read_pos, request->read_size ); + request->read_pos = 0; + } + if (maxlen == -1) maxlen = sizeof(request->read_buf); + + if (notify) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NULL, 0 ); + + ret = netconn_recv( &request->netconn, request->read_buf + request->read_size, + maxlen - request->read_size, 0, &len ); + + if (notify) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, &len, sizeof(len) ); + + request->read_size += len; + return ret; +} + +/* discard data contents until we reach end of line */ +static BOOL discard_eol( request_t *request, BOOL notify ) +{ + do + { + char *eol = memchr( request->read_buf + request->read_pos, '\n', request->read_size ); + if (eol) + { + remove_data( request, (eol + 1) - (request->read_buf + request->read_pos) ); + break; + } + request->read_pos = request->read_size = 0; /* discard everything */ + if (!read_more_data( request, -1, notify )) return FALSE; + } while (request->read_size); + return TRUE; +} + +/* read the size of the next chunk */ +static BOOL start_next_chunk( request_t *request, BOOL notify ) +{ + DWORD chunk_size = 0; + + assert(!request->read_chunked_size || request->read_chunked_size == ~0u); + + if (request->read_chunked_eof) return FALSE; + + /* read terminator for the previous chunk */ + if (!request->read_chunked_size && !discard_eol( request, notify )) return FALSE; + + 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') + { + TRACE("reading %u byte chunk\n", chunk_size); + + if (request->content_length == ~0u) request->content_length = chunk_size; + else request->content_length += chunk_size; + + request->read_chunked_size = chunk_size; + if (!chunk_size) request->read_chunked_eof = TRUE; + + return discard_eol( request, notify ); + } + remove_data( request, 1 ); + } + if (!read_more_data( request, -1, notify )) return FALSE; + if (!request->read_size) + { + request->content_length = request->content_read = 0; + request->read_chunked_size = 0; + return TRUE; + } + } +} + +static BOOL refill_buffer( request_t *request, BOOL notify ) +{ + int len = sizeof(request->read_buf); + + if (request->read_chunked) + { + if (request->read_chunked_eof) return FALSE; + if (request->read_chunked_size == ~0u || !request->read_chunked_size) + { + if (!start_next_chunk( request, notify )) return FALSE; + } + len = min( len, request->read_chunked_size ); + } + else if (request->content_length != ~0u) + { + 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 (!request->read_size) request->content_length = request->content_read = 0; + return TRUE; +} + +static void finished_reading( request_t *request ) +{ + static const WCHAR closeW[] = {'c','l','o','s','e',0}; + + BOOL close = FALSE; + WCHAR connection[20]; + DWORD size = sizeof(connection); + + 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 the size of data available to be read immediately */ +static DWORD get_available_data( request_t *request ) +{ + if (request->read_chunked) return min( request->read_chunked_size, request->read_size ); + return request->read_size; +} + +/* check if we have reached the end of the data to read */ +static BOOL end_of_read_data( request_t *request ) +{ + if (!request->content_length) return TRUE; + if (request->read_chunked) return request->read_chunked_eof; + if (request->content_length == ~0u) return FALSE; + return (request->content_length == request->content_read); +} + +static BOOL read_data( request_t *request, void *buffer, DWORD size, DWORD *read, BOOL async ) +{ + int count, bytes_read = 0; + + if (end_of_read_data( request )) goto done; + + while (size) + { + if (!(count = get_available_data( request ))) + { + if (!refill_buffer( request, async )) goto done; + if (!(count = get_available_data( request ))) goto done; + } + count = min( count, size ); + memcpy( (char *)buffer + bytes_read, request->read_buf + request->read_pos, count ); + remove_data( request, count ); + if (request->read_chunked) request->read_chunked_size -= count; + size -= count; + bytes_read += count; + request->content_read += count; + if (end_of_read_data( request )) goto done; + } + if (request->read_chunked && !request->read_chunked_size) refill_buffer( request, async ); + +done: + TRACE( "retrieved %u bytes (%u/%u)\n", bytes_read, request->content_read, request->content_length ); + + if (async) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, buffer, bytes_read ); + if (read) *read = bytes_read; + if (end_of_read_data( request )) finished_reading( request ); + return TRUE; +} + +/* read any content returned by the server so that the connection can be reused */ +static void drain_content( request_t *request ) +{ + DWORD bytes_read; + char buffer[2048]; + + refill_buffer( request, FALSE ); + for (;;) + { + if (!read_data( request, buffer, sizeof(buffer), &bytes_read, FALSE ) || !bytes_read) return; + } +} + +static BOOL send_request( request_t *request, LPCWSTR headers, DWORD headers_len, LPVOID optional, + DWORD optional_len, DWORD total_len, DWORD_PTR context, BOOL async ) +{ + 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}; + + BOOL ret = FALSE; + connect_t *connect = request->connect; + session_t *session = connect->session; + WCHAR *req = NULL; + char *req_ascii; + int bytes_sent; + DWORD len; + + clear_response_headers( request ); + drain_content( request ); + + if (session->agent) + process_header( request, attr_user_agent, session->agent, WINHTTP_ADDREQ_FLAG_ADD_IF_NEW, TRUE ); + + if (connect->hostname) + add_host_header( request, WINHTTP_ADDREQ_FLAG_ADD_IF_NEW ); + + if (total_len || (request->verb && !strcmpW( request->verb, postW ))) + { + 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 ); + } + if (!(request->hdr.disable_flags & WINHTTP_DISABLE_KEEP_ALIVE)) + { + process_header( request, attr_connection, 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 ); + } + if (headers && !add_request_headers( request, headers, headers_len, WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE )) + { + TRACE("failed to add request headers\n"); + return FALSE; + } + if (!(request->hdr.disable_flags & WINHTTP_DISABLE_COOKIES) && !add_cookie_headers( request )) + { + WARN("failed to add cookie headers\n"); + return FALSE; + } + + if (context) request->hdr.context = context; + + if (!(ret = open_connection( request ))) goto end; + if (!(req = build_request_string( request ))) goto end; + + if (!(req_ascii = strdupWA( req ))) goto end; + TRACE("full request: %s\n", debugstr_a(req_ascii)); + len = strlen(req_ascii); + + send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST, NULL, 0 ); + + ret = netconn_send( &request->netconn, req_ascii, len, &bytes_sent ); + heap_free( req_ascii ); + if (!ret) goto end; + + if (optional_len) + { + if (!netconn_send( &request->netconn, optional, optional_len, &bytes_sent )) 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) ); + +end: + if (async) + { + 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 = get_last_error(); + send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &result, sizeof(result) ); + } + } + heap_free( req ); + return ret; +} + +static void task_send_request( task_header_t *task ) +{ + send_request_t *s = (send_request_t *)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 ); +} + +/*********************************************************************** + * WinHttpSendRequest (winhttp.@) + */ +BOOL WINAPI WinHttpSendRequest( HINTERNET hrequest, LPCWSTR headers, DWORD headers_len, + LPVOID optional, DWORD optional_len, DWORD total_len, DWORD_PTR context ) +{ + BOOL ret; + request_t *request; + + TRACE("%p, %s, 0x%x, %u, %u, %lx\n", + hrequest, debugstr_w(headers), headers_len, optional_len, total_len, context); + + if (!(request = (request_t *)grab_object( hrequest ))) + { + set_last_error( ERROR_INVALID_HANDLE ); + return FALSE; + } + if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST) + { + release_object( &request->hdr ); + set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE ); + return FALSE; + } + + if (headers && !headers_len) headers_len = strlenW( headers ); + + if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC) + { + send_request_t *s; + + if (!(s = heap_alloc( sizeof(send_request_t) ))) return FALSE; + s->hdr.request = request; + s->hdr.proc = task_send_request; + s->headers = strdupW( 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( (task_header_t *)s ); + } + else + ret = send_request( request, headers, headers_len, optional, optional_len, total_len, context, FALSE ); + + release_object( &request->hdr ); + if (ret) set_last_error( ERROR_SUCCESS ); + return ret; +} + #undef ARRAYSIZE #define ARRAYSIZE(array) (sizeof(array) / sizeof((array)[0])) @@ -1146,25 +1741,24 @@ static BOOL do_authorization( request_t *request, DWORD target, DWORD scheme_fla const WCHAR *auth_target, *username, *password; WCHAR auth_value[2048], *auth_reply; DWORD len = sizeof(auth_value), len_scheme, flags; - BOOL ret, has_auth_value; + BOOL ret; if (scheme == SCHEME_INVALID) return FALSE; switch (target) { case WINHTTP_AUTH_TARGET_SERVER: - has_auth_value = get_authvalue( request, WINHTTP_QUERY_WWW_AUTHENTICATE, scheme_flag, auth_value, len ); + if (!get_authvalue( request, WINHTTP_QUERY_WWW_AUTHENTICATE, scheme_flag, auth_value, len )) + return FALSE; auth_ptr = &request->authinfo; auth_target = attr_authorization; if (request->creds[TARGET_SERVER][scheme].username) { - if (scheme != SCHEME_BASIC && !has_auth_value) return FALSE; username = request->creds[TARGET_SERVER][scheme].username; password = request->creds[TARGET_SERVER][scheme].password; } else { - if (!has_auth_value) return FALSE; username = request->connect->username; password = request->connect->password; } @@ -1368,851 +1962,6 @@ static BOOL do_authorization( request_t *request, DWORD target, DWORD scheme_fla return ret; } -static LPWSTR concatenate_string_list( LPCWSTR *list, int len ) -{ - LPCWSTR *t; - LPWSTR str; - - for( t = list; *t ; t++ ) - len += strlenW( *t ); - len++; - - str = heap_alloc( len * sizeof(WCHAR) ); - if (!str) return NULL; - *str = 0; - - for( t = list; *t ; t++ ) - strcatW( str, *t ); - - return str; -} - -static LPWSTR build_header_request_string( request_t *request, LPCWSTR verb, - LPCWSTR path, LPCWSTR version ) -{ - static const WCHAR crlf[] = {'\r','\n',0}; - static const WCHAR space[] = { ' ',0 }; - static const WCHAR colon[] = { ':',' ',0 }; - static const WCHAR twocrlf[] = {'\r','\n','\r','\n', 0}; - LPWSTR requestString; - DWORD len, n; - LPCWSTR *req; - UINT i; - LPWSTR p; - - /* allocate space for an array of all the string pointers to be added */ - len = (request->num_headers) * 4 + 10; - req = heap_alloc( len * sizeof(LPCWSTR) ); - if (!req) return NULL; - - /* add the verb, path and HTTP version string */ - n = 0; - req[n++] = verb; - req[n++] = space; - req[n++] = path; - req[n++] = space; - req[n++] = version; - - /* Append custom request headers */ - for (i = 0; i < request->num_headers; i++) - { - if (request->headers[i].is_request) - { - req[n++] = crlf; - req[n++] = request->headers[i].field; - req[n++] = colon; - req[n++] = request->headers[i].value; - - TRACE("Adding custom header %s (%s)\n", - debugstr_w(request->headers[i].field), - debugstr_w(request->headers[i].value)); - } - } - - if( n >= len ) - ERR("oops. buffer overrun\n"); - - req[n] = NULL; - requestString = concatenate_string_list( req, 4 ); - heap_free( req ); - if (!requestString) return NULL; - - /* - * Set (header) termination string for request - * Make sure there are exactly two new lines at the end of the request - */ - p = &requestString[strlenW(requestString)-1]; - while ( (*p == '\n') || (*p == '\r') ) - p--; - strcpyW( p+1, twocrlf ); - - return requestString; -} - -static BOOL read_reply( request_t *request ); - -static BOOL secure_proxy_connect( request_t *request ) -{ - static const WCHAR verbConnect[] = {'C','O','N','N','E','C','T',0}; - static const WCHAR fmt[] = {'%','s',':','%','u',0}; - BOOL ret = FALSE; - LPWSTR path; - connect_t *connect = request->connect; - - path = heap_alloc( (strlenW( connect->hostname ) + 13) * sizeof(WCHAR) ); - if (path) - { - LPWSTR requestString; - - sprintfW( path, fmt, connect->hostname, connect->hostport ); - requestString = build_header_request_string( request, verbConnect, - path, http1_1 ); - heap_free( path ); - if (requestString) - { - LPSTR req_ascii = strdupWA( requestString ); - - heap_free( requestString ); - if (req_ascii) - { - int len = strlen( req_ascii ), bytes_sent; - - ret = netconn_send( request->netconn, req_ascii, len, &bytes_sent ); - heap_free( req_ascii ); - if (ret) - ret = read_reply( request ); - } - } - } - return ret; -} - -#ifndef INET6_ADDRSTRLEN -#define INET6_ADDRSTRLEN 46 -#endif - -static WCHAR *addr_to_str( struct sockaddr_storage *addr ) -{ - char buf[INET6_ADDRSTRLEN]; - void *src; - - switch (addr->ss_family) - { - case AF_INET: - src = &((struct sockaddr_in *)addr)->sin_addr; - break; - case AF_INET6: - src = &((struct sockaddr_in6 *)addr)->sin6_addr; - break; - default: - WARN("unsupported address family %d\n", addr->ss_family); - return NULL; - } - if (!inet_ntop( addr->ss_family, src, buf, sizeof(buf) )) return NULL; - return strdupAW( buf ); -} - -static CRITICAL_SECTION connection_pool_cs; -static CRITICAL_SECTION_DEBUG connection_pool_debug = -{ - 0, 0, &connection_pool_cs, - { &connection_pool_debug.ProcessLocksList, &connection_pool_debug.ProcessLocksList }, - 0, 0, { (DWORD_PTR)(__FILE__ ": connection_pool_cs") } -}; -static CRITICAL_SECTION connection_pool_cs = { &connection_pool_debug, -1, 0, 0, 0, 0 }; - -static struct list connection_pool = LIST_INIT( connection_pool ); - -void release_host( hostdata_t *host ) -{ - LONG ref; - - EnterCriticalSection( &connection_pool_cs ); - if (!(ref = --host->ref)) list_remove( &host->entry ); - LeaveCriticalSection( &connection_pool_cs ); - if (ref) return; - - assert( list_empty( &host->connections ) ); - heap_free( host->hostname ); - heap_free( host ); -} - -static BOOL connection_collector_running; - -static DWORD WINAPI connection_collector(void *arg) -{ - unsigned int remaining_connections; - netconn_t *netconn, *next_netconn; - hostdata_t *host, *next_host; - ULONGLONG now; - - do - { - /* FIXME: Use more sophisticated method */ - Sleep(5000); - remaining_connections = 0; - now = GetTickCount64(); - - EnterCriticalSection(&connection_pool_cs); - - LIST_FOR_EACH_ENTRY_SAFE(host, next_host, &connection_pool, hostdata_t, entry) - { - LIST_FOR_EACH_ENTRY_SAFE(netconn, next_netconn, &host->connections, netconn_t, entry) - { - if (netconn->keep_until < now) - { - TRACE("freeing %p\n", netconn); - list_remove(&netconn->entry); - netconn_close(netconn); - } - else - { - remaining_connections++; - } - } - } - - if (!remaining_connections) connection_collector_running = FALSE; - - LeaveCriticalSection(&connection_pool_cs); - } while(remaining_connections); - - FreeLibraryAndExitThread( winhttp_instance, 0 ); -} - -static void cache_connection( netconn_t *netconn ) -{ - TRACE( "caching connection %p\n", netconn ); - - EnterCriticalSection( &connection_pool_cs ); - - netconn->keep_until = GetTickCount64() + DEFAULT_KEEP_ALIVE_TIMEOUT; - list_add_head( &netconn->host->connections, &netconn->entry ); - - if (!connection_collector_running) - { - HMODULE module; - HANDLE thread; - - GetModuleHandleExW( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const WCHAR*)winhttp_instance, &module ); - - thread = CreateThread(NULL, 0, connection_collector, NULL, 0, NULL); - if (thread) - { - CloseHandle( thread ); - connection_collector_running = TRUE; - } - else - { - FreeLibrary( winhttp_instance ); - } - } - - LeaveCriticalSection( &connection_pool_cs ); -} - -static DWORD map_secure_protocols( DWORD mask ) -{ - DWORD ret = 0; - if (mask & WINHTTP_FLAG_SECURE_PROTOCOL_SSL2) ret |= SP_PROT_SSL2_CLIENT; - if (mask & WINHTTP_FLAG_SECURE_PROTOCOL_SSL3) ret |= SP_PROT_SSL3_CLIENT; - if (mask & WINHTTP_FLAG_SECURE_PROTOCOL_TLS1) ret |= SP_PROT_TLS1_CLIENT; - if (mask & WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1) ret |= SP_PROT_TLS1_1_CLIENT; - if (mask & WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2) ret |= SP_PROT_TLS1_2_CLIENT; - return ret; -} - -static BOOL ensure_cred_handle( session_t *session ) -{ - SCHANNEL_CRED cred; - SECURITY_STATUS status; - - if (session->cred_handle_initialized) return TRUE; - - memset( &cred, 0, sizeof(cred) ); - cred.dwVersion = SCHANNEL_CRED_VERSION; - cred.grbitEnabledProtocols = map_secure_protocols( session->secure_protocols ); - if ((status = AcquireCredentialsHandleW( NULL, (WCHAR *)UNISP_NAME_W, SECPKG_CRED_OUTBOUND, NULL, &cred, - NULL, NULL, &session->cred_handle, NULL )) != SEC_E_OK) - { - WARN( "AcquireCredentialsHandleW failed: 0x%08x\n", status ); - return FALSE; - } - session->cred_handle_initialized = TRUE; - return TRUE; -} - -static BOOL open_connection( request_t *request ) -{ - BOOL is_secure = request->hdr.flags & WINHTTP_FLAG_SECURE; - hostdata_t *host = NULL, *iter; - netconn_t *netconn = NULL; - connect_t *connect; - WCHAR *addressW = NULL; - INTERNET_PORT port; - DWORD len; - - if (request->netconn) goto done; - - connect = request->connect; - port = connect->serverport ? connect->serverport : (request->hdr.flags & WINHTTP_FLAG_SECURE ? 443 : 80); - - EnterCriticalSection( &connection_pool_cs ); - - LIST_FOR_EACH_ENTRY( iter, &connection_pool, hostdata_t, entry ) - { - if (iter->port == port && !strcmpW( connect->servername, iter->hostname ) && !is_secure == !iter->secure) - { - host = iter; - host->ref++; - break; - } - } - - if (!host) - { - if ((host = heap_alloc( sizeof(*host) ))) - { - host->ref = 1; - host->secure = is_secure; - host->port = port; - list_init( &host->connections ); - if ((host->hostname = strdupW( connect->servername ))) - { - list_add_head( &connection_pool, &host->entry ); - } - else - { - heap_free( host ); - host = NULL; - } - } - } - - LeaveCriticalSection( &connection_pool_cs ); - - if (!host) return FALSE; - - for (;;) - { - EnterCriticalSection( &connection_pool_cs ); - if (!list_empty( &host->connections )) - { - netconn = LIST_ENTRY( list_head( &host->connections ), netconn_t, entry ); - list_remove( &netconn->entry ); - } - LeaveCriticalSection( &connection_pool_cs ); - if (!netconn) break; - - if (netconn_is_alive( netconn )) break; - TRACE("connection %p no longer alive, closing\n", netconn); - netconn_close( netconn ); - netconn = NULL; - } - - if (!connect->resolved && netconn) - { - connect->sockaddr = netconn->sockaddr; - connect->resolved = TRUE; - } - - if (!connect->resolved) - { - len = strlenW( 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 )) - { - release_host( host ); - return FALSE; - } - connect->resolved = TRUE; - - if (!(addressW = addr_to_str( &connect->sockaddr ))) - { - release_host( host ); - return FALSE; - } - len = strlenW( addressW ) + 1; - send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED, addressW, len ); - } - - if (!netconn) - { - if (!addressW && !(addressW = addr_to_str( &connect->sockaddr ))) - { - release_host( host ); - return FALSE; - } - - TRACE("connecting to %s:%u\n", debugstr_w(addressW), port); - - send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, addressW, 0 ); - - if (!(netconn = netconn_create( host, &connect->sockaddr, request->connect_timeout ))) - { - heap_free( addressW ); - release_host( host ); - return FALSE; - } - netconn_set_timeout( netconn, TRUE, request->send_timeout ); - netconn_set_timeout( netconn, FALSE, request->recv_timeout ); - if (is_secure) - { - if (connect->session->proxy_server && - strcmpiW( connect->hostname, connect->servername )) - { - if (!secure_proxy_connect( request )) - { - heap_free( addressW ); - netconn_close( netconn ); - return FALSE; - } - } - if (!ensure_cred_handle( connect->session ) || - !netconn_secure_connect( netconn, connect->hostname, request->security_flags, - &connect->session->cred_handle )) - { - heap_free( addressW ); - netconn_close( netconn ); - return FALSE; - } - } - - request->netconn = netconn; - send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, addressW, strlenW(addressW) + 1 ); - } - else - { - TRACE("using connection %p\n", netconn); - - netconn_set_timeout( netconn, TRUE, request->send_timeout ); - netconn_set_timeout( netconn, FALSE, request->recv_timeout ); - request->netconn = netconn; - } - -done: - request->read_pos = request->read_size = 0; - request->read_chunked = FALSE; - request->read_chunked_size = ~0u; - request->read_chunked_eof = FALSE; - heap_free( addressW ); - return TRUE; -} - -void close_connection( request_t *request ) -{ - if (!request->netconn) return; - - send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION, 0, 0 ); - netconn_close( request->netconn ); - request->netconn = NULL; - send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED, 0, 0 ); -} - -static BOOL add_host_header( request_t *request, DWORD modifier ) -{ - BOOL ret; - DWORD len; - WCHAR *host; - static const WCHAR fmt[] = {'%','s',':','%','u',0}; - connect_t *connect = request->connect; - INTERNET_PORT port; - - port = connect->hostport ? connect->hostport : (request->hdr.flags & WINHTTP_FLAG_SECURE ? 443 : 80); - - if (port == INTERNET_DEFAULT_HTTP_PORT || port == INTERNET_DEFAULT_HTTPS_PORT) - { - return process_header( request, attr_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 ); - return ret; -} - -static void clear_response_headers( request_t *request ) -{ - unsigned int i; - - for (i = 0; i < request->num_headers; i++) - { - if (!request->headers[i].field) continue; - if (!request->headers[i].value) continue; - if (request->headers[i].is_request) continue; - delete_header( request, i ); - i--; - } -} - -/* remove some amount of data from the read buffer */ -static void remove_data( request_t *request, int count ) -{ - if (!(request->read_size -= count)) request->read_pos = 0; - else request->read_pos += count; -} - -/* read some more data into the read buffer */ -static BOOL read_more_data( request_t *request, int maxlen, BOOL notify ) -{ - int len; - BOOL ret; - - if (request->read_chunked_eof) return FALSE; - - if (request->read_size && request->read_pos) - { - /* move existing data to the start of the buffer */ - memmove( request->read_buf, request->read_buf + request->read_pos, request->read_size ); - request->read_pos = 0; - } - if (maxlen == -1) maxlen = sizeof(request->read_buf); - - if (notify) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NULL, 0 ); - - ret = netconn_recv( request->netconn, request->read_buf + request->read_size, - maxlen - request->read_size, 0, &len ); - - if (notify) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, &len, sizeof(len) ); - - request->read_size += len; - return ret; -} - -/* discard data contents until we reach end of line */ -static BOOL discard_eol( request_t *request, BOOL notify ) -{ - do - { - char *eol = memchr( request->read_buf + request->read_pos, '\n', request->read_size ); - if (eol) - { - remove_data( request, (eol + 1) - (request->read_buf + request->read_pos) ); - break; - } - request->read_pos = request->read_size = 0; /* discard everything */ - if (!read_more_data( request, -1, notify )) return FALSE; - } while (request->read_size); - return TRUE; -} - -/* read the size of the next chunk */ -static BOOL start_next_chunk( request_t *request, BOOL notify ) -{ - DWORD chunk_size = 0; - - assert(!request->read_chunked_size || request->read_chunked_size == ~0u); - - if (request->read_chunked_eof) return FALSE; - - /* read terminator for the previous chunk */ - if (!request->read_chunked_size && !discard_eol( request, notify )) return FALSE; - - 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') - { - TRACE("reading %u byte chunk\n", chunk_size); - - if (request->content_length == ~0u) request->content_length = chunk_size; - else request->content_length += chunk_size; - - request->read_chunked_size = chunk_size; - if (!chunk_size) request->read_chunked_eof = TRUE; - - return discard_eol( request, notify ); - } - remove_data( request, 1 ); - } - if (!read_more_data( request, -1, notify )) return FALSE; - if (!request->read_size) - { - request->content_length = request->content_read = 0; - request->read_chunked_size = 0; - return TRUE; - } - } -} - -static BOOL refill_buffer( request_t *request, BOOL notify ) -{ - int len = sizeof(request->read_buf); - - if (request->read_chunked) - { - if (request->read_chunked_eof) return FALSE; - if (request->read_chunked_size == ~0u || !request->read_chunked_size) - { - if (!start_next_chunk( request, notify )) return FALSE; - } - len = min( len, request->read_chunked_size ); - } - else if (request->content_length != ~0u) - { - 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 (!request->read_size) request->content_length = request->content_read = 0; - return TRUE; -} - -static void finished_reading( request_t *request ) -{ - static const WCHAR closeW[] = {'c','l','o','s','e',0}; - - BOOL close = FALSE; - 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 (!strcmpiW( connection, closeW )) close = TRUE; - } - else if (!strcmpW( request->version, http1_0 )) close = TRUE; - if (close) - { - close_connection( request ); - return; - } - - cache_connection( request->netconn ); - request->netconn = NULL; -} - -/* return the size of data available to be read immediately */ -static DWORD get_available_data( request_t *request ) -{ - if (request->read_chunked) return min( request->read_chunked_size, request->read_size ); - return request->read_size; -} - -/* check if we have reached the end of the data to read */ -static BOOL end_of_read_data( request_t *request ) -{ - if (!request->content_length) return TRUE; - if (request->read_chunked) return request->read_chunked_eof; - if (request->content_length == ~0u) return FALSE; - return (request->content_length == request->content_read); -} - -static BOOL read_data( request_t *request, void *buffer, DWORD size, DWORD *read, BOOL async ) -{ - int count, bytes_read = 0; - - if (end_of_read_data( request )) goto done; - - while (size) - { - if (!(count = get_available_data( request ))) - { - if (!refill_buffer( request, async )) goto done; - if (!(count = get_available_data( request ))) goto done; - } - count = min( count, size ); - memcpy( (char *)buffer + bytes_read, request->read_buf + request->read_pos, count ); - remove_data( request, count ); - if (request->read_chunked) request->read_chunked_size -= count; - size -= count; - bytes_read += count; - request->content_read += count; - if (end_of_read_data( request )) goto done; - } - if (request->read_chunked && !request->read_chunked_size) refill_buffer( request, async ); - -done: - TRACE( "retrieved %u bytes (%u/%u)\n", bytes_read, request->content_read, request->content_length ); - - if (async) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, buffer, bytes_read ); - if (read) *read = bytes_read; - if (end_of_read_data( request )) finished_reading( request ); - return TRUE; -} - -/* read any content returned by the server so that the connection can be reused */ -static void drain_content( request_t *request ) -{ - DWORD size, bytes_read, bytes_total = 0, bytes_left = request->content_length - request->content_read; - char buffer[2048]; - - refill_buffer( request, FALSE ); - 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; - bytes_total += bytes_read; - } -} - -static BOOL send_request( request_t *request, LPCWSTR headers, DWORD headers_len, LPVOID optional, - DWORD optional_len, DWORD total_len, DWORD_PTR context, BOOL async ) -{ - 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}; - - BOOL ret = FALSE; - connect_t *connect = request->connect; - session_t *session = connect->session; - WCHAR *req = NULL; - char *req_ascii; - int bytes_sent; - DWORD len; - - clear_response_headers( request ); - drain_content( request ); - - if (session->agent) - process_header( request, attr_user_agent, session->agent, WINHTTP_ADDREQ_FLAG_ADD_IF_NEW, TRUE ); - - if (connect->hostname) - add_host_header( request, WINHTTP_ADDREQ_FLAG_ADD_IF_NEW ); - - 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 ))) - { - 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 ); - } - if (!(request->hdr.disable_flags & WINHTTP_DISABLE_KEEP_ALIVE)) - { - process_header( request, attr_connection, 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 ); - } - if (headers && !add_request_headers( request, headers, headers_len, WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE )) - { - TRACE("failed to add request headers\n"); - return FALSE; - } - if (!(request->hdr.disable_flags & WINHTTP_DISABLE_COOKIES) && !add_cookie_headers( request )) - { - WARN("failed to add cookie headers\n"); - return FALSE; - } - - if (context) request->hdr.context = context; - - if (!(ret = open_connection( request ))) goto end; - if (!(req = build_request_string( request ))) goto end; - - if (!(req_ascii = strdupWA( req ))) goto end; - TRACE("full request: %s\n", debugstr_a(req_ascii)); - len = strlen(req_ascii); - - send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST, NULL, 0 ); - - ret = netconn_send( request->netconn, req_ascii, len, &bytes_sent ); - heap_free( req_ascii ); - if (!ret) goto end; - - if (optional_len) - { - if (!netconn_send( request->netconn, optional, optional_len, &bytes_sent )) 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) ); - -end: - if (async) - { - 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 = get_last_error(); - send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &result, sizeof(result) ); - } - } - heap_free( req ); - return ret; -} - -static void task_send_request( task_header_t *task ) -{ - send_request_t *s = (send_request_t *)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 ); -} - -/*********************************************************************** - * WinHttpSendRequest (winhttp.@) - */ -BOOL WINAPI WinHttpSendRequest( HINTERNET hrequest, LPCWSTR headers, DWORD headers_len, - LPVOID optional, DWORD optional_len, DWORD total_len, DWORD_PTR context ) -{ - BOOL ret; - request_t *request; - - TRACE("%p, %s, %u, %u, %u, %lx\n", hrequest, debugstr_wn(headers, headers_len), headers_len, optional_len, - total_len, context); - - if (!(request = (request_t *)grab_object( hrequest ))) - { - set_last_error( ERROR_INVALID_HANDLE ); - return FALSE; - } - if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST) - { - release_object( &request->hdr ); - set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE ); - return FALSE; - } - - if (headers && !headers_len) headers_len = strlenW( headers ); - - if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC) - { - send_request_t *s; - - if (!(s = heap_alloc( sizeof(send_request_t) ))) return FALSE; - s->hdr.request = request; - s->hdr.proc = task_send_request; - s->headers = strdupW( 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( (task_header_t *)s ); - } - else - ret = send_request( request, headers, headers_len, optional, optional_len, total_len, context, FALSE ); - - release_object( &request->hdr ); - if (ret) set_last_error( ERROR_SUCCESS ); - return ret; -} - static BOOL set_credentials( request_t *request, DWORD target, DWORD scheme_flag, const WCHAR *username, const WCHAR *password ) { @@ -2396,7 +2145,7 @@ static BOOL read_reply( request_t *request ) WCHAR *versionW, *status_textW, *raw_headers; WCHAR status_codeW[4]; /* sizeof("nnn") */ - if (!request->netconn) return FALSE; + if (!netconn_connected( &request->netconn )) return FALSE; do { @@ -2582,11 +2331,11 @@ static BOOL handle_redirect( request_t *request, DWORD status ) connect->hostport = port; if (!(ret = set_server_for_hostname( connect, hostname, port ))) goto end; - netconn_close( request->netconn ); - request->netconn = NULL; - request->content_length = request->content_read = 0; + netconn_close( &request->netconn ); + if (!(ret = netconn_init( &request->netconn ))) goto end; request->read_pos = request->read_size = 0; - request->read_chunked = request->read_chunked_eof = FALSE; + request->read_chunked = FALSE; + request->read_chunked_eof = FALSE; } else heap_free( hostname ); @@ -2734,14 +2483,14 @@ static BOOL query_data_available( request_t *request, DWORD *available, BOOL asy if (end_of_read_data( request )) goto done; count = get_available_data( request ); - if (!request->read_chunked && request->netconn) - count += netconn_query_data_available( request->netconn ); + if (!request->read_chunked) + count += netconn_query_data_available( &request->netconn ); if (!count) { refill_buffer( request, async ); count = get_available_data( request ); - if (!request->read_chunked && request->netconn) - count += netconn_query_data_available( request->netconn ); + if (!request->read_chunked) + count += netconn_query_data_available( &request->netconn ); } done: @@ -2854,7 +2603,7 @@ static BOOL write_data( request_t *request, LPCVOID buffer, DWORD to_write, LPDW BOOL ret; int num_bytes; - ret = netconn_send( request->netconn, buffer, to_write, &num_bytes ); + ret = netconn_send( &request->netconn, buffer, to_write, &num_bytes ); if (async) { diff --git a/dll/win32/winhttp/session.c b/dll/win32/winhttp/session.c index cef533f1c02..7b310f4605a 100644 --- a/dll/win32/winhttp/session.c +++ b/dll/win32/winhttp/session.c @@ -16,40 +16,12 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include "config.h" -#include "wine/port.h" -#include "wine/debug.h" - -#include -#include - -#ifdef HAVE_CORESERVICES_CORESERVICES_H -#define GetCurrentThread MacGetCurrentThread -#define LoadResource MacLoadResource -#include -#undef GetCurrentThread -#undef LoadResource -#undef DPRINTF -#endif - -#include "windef.h" -#include "winbase.h" -#ifndef __MINGW32__ -#define USE_WS_PREFIX -#endif -#include "winsock2.h" -#include "ws2ipdef.h" -#include "winhttp.h" -#include "wincrypt.h" -#include "winreg.h" -#define COBJMACROS -#include "ole2.h" -#include "dispex.h" -#include "activscp.h" - #include "winhttp_private.h" -WINE_DEFAULT_DEBUG_CHANNEL(winhttp); +#include +#include +#include +#include #define DEFAULT_RESOLVE_TIMEOUT 0 #define DEFAULT_CONNECT_TIMEOUT 20000 @@ -99,7 +71,6 @@ static void session_destroy( object_header_t *hdr ) TRACE("%p\n", session); if (session->unload_event) SetEvent( session->unload_event ); - if (session->cred_handle_initialized) FreeCredentialsHandle( &session->cred_handle ); LIST_FOR_EACH_SAFE( item, next, &session->cookie_cache ) { @@ -184,17 +155,6 @@ static BOOL session_set_option( object_header_t *hdr, DWORD option, LPVOID buffe hdr->redirect_policy = policy; return TRUE; } - case WINHTTP_OPTION_SECURE_PROTOCOLS: - { - if (buflen != sizeof(session->secure_protocols)) - { - set_last_error( ERROR_INSUFFICIENT_BUFFER ); - return FALSE; - } - session->secure_protocols = *(DWORD *)buffer; - TRACE("0x%x\n", session->secure_protocols); - return TRUE; - } case WINHTTP_OPTION_DISABLE_FEATURE: set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE ); return FALSE; @@ -725,7 +685,7 @@ static BOOL request_query_option( object_header_t *hdr, DWORD option, LPVOID buf { case WINHTTP_OPTION_SECURITY_FLAGS: { - DWORD flags = 0; + DWORD flags; int bits; if (!buffer || *buflen < sizeof(flags)) @@ -737,17 +697,14 @@ static BOOL request_query_option( object_header_t *hdr, DWORD option, LPVOID buf flags = 0; if (hdr->flags & WINHTTP_FLAG_SECURE) flags |= SECURITY_FLAG_SECURE; - flags |= request->security_flags; - if (request->netconn) - { - bits = netconn_get_cipher_strength( request->netconn ); - if (bits >= 128) - flags |= SECURITY_FLAG_STRENGTH_STRONG; - else if (bits >= 56) - flags |= SECURITY_FLAG_STRENGTH_MEDIUM; - else - flags |= SECURITY_FLAG_STRENGTH_WEAK; - } + flags |= request->netconn.security_flags; + bits = netconn_get_cipher_strength( &request->netconn ); + if (bits >= 128) + flags |= SECURITY_FLAG_STRENGTH_STRONG; + else if (bits >= 56) + flags |= SECURITY_FLAG_STRENGTH_MEDIUM; + else + flags |= SECURITY_FLAG_STRENGTH_WEAK; *(DWORD *)buffer = flags; *buflen = sizeof(flags); return TRUE; @@ -763,7 +720,7 @@ static BOOL request_query_option( object_header_t *hdr, DWORD option, LPVOID buf return FALSE; } - if (!request->netconn || !(cert = netconn_get_certificate( request->netconn ))) return FALSE; + if (!(cert = netconn_get_certificate( &request->netconn ))) return FALSE; *(CERT_CONTEXT **)buffer = (CERT_CONTEXT *)cert; *buflen = sizeof(cert); return TRUE; @@ -782,7 +739,7 @@ static BOOL request_query_option( object_header_t *hdr, DWORD option, LPVOID buf set_last_error( ERROR_INSUFFICIENT_BUFFER ); return FALSE; } - if (!request->netconn || !(cert = netconn_get_certificate( request->netconn ))) return FALSE; + if (!(cert = netconn_get_certificate( &request->netconn ))) return FALSE; ci->ftExpiry = cert->pCertInfo->NotAfter; ci->ftStart = cert->pCertInfo->NotBefore; @@ -797,7 +754,7 @@ static BOOL request_query_option( object_header_t *hdr, DWORD option, LPVOID buf else ci->lpszSignatureAlgName = NULL; ci->lpszEncryptionAlgName = NULL; - ci->dwKeySize = request->netconn ? netconn_get_cipher_strength( request->netconn ) : 0; + ci->dwKeySize = netconn_get_cipher_strength( &request->netconn ); CertFreeCertificateContext( cert ); *buflen = sizeof(*ci); @@ -812,7 +769,7 @@ static BOOL request_query_option( object_header_t *hdr, DWORD option, LPVOID buf return FALSE; } - *(DWORD *)buffer = request->netconn ? netconn_get_cipher_strength( request->netconn ) : 0; + *(DWORD *)buffer = netconn_get_cipher_strength( &request->netconn ); *buflen = sizeof(DWORD); return TRUE; } @@ -829,12 +786,12 @@ static BOOL request_query_option( object_header_t *hdr, DWORD option, LPVOID buf set_last_error( ERROR_INSUFFICIENT_BUFFER ); return FALSE; } - if (!request->netconn) + if (!netconn_connected( &request->netconn )) { set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_STATE ); return FALSE; } - if (getsockname( request->netconn->socket, &local, &len )) return FALSE; + if (getsockname( request->netconn.socket, &local, &len )) return FALSE; if (!convert_sockaddr( &local, &info->LocalAddress )) return FALSE; if (!convert_sockaddr( remote, &info->RemoteAddress )) return FALSE; info->cbSize = sizeof(*info); @@ -970,7 +927,7 @@ static BOOL request_set_option( object_header_t *hdr, DWORD option, LPVOID buffe set_last_error( ERROR_INVALID_PARAMETER ); return FALSE; } - request->security_flags = flags; + request->netconn.security_flags = flags; return TRUE; } case WINHTTP_OPTION_RESOLVE_TIMEOUT: @@ -1107,6 +1064,7 @@ HINTERNET WINAPI WinHttpOpenRequest( HINTERNET hconnect, LPCWSTR verb, LPCWSTR o request->connect = connect; list_add_head( &connect->hdr.children, &request->hdr.entry ); + if (!netconn_init( &request->netconn )) goto end; request->resolve_timeout = connect->session->resolve_timeout; request->connect_timeout = connect->session->connect_timeout; request->send_timeout = connect->session->send_timeout; @@ -2089,10 +2047,10 @@ BOOL WINAPI WinHttpSetTimeouts( HINTERNET handle, int resolve, int connect, int if (receive < 0) receive = 0; request->recv_timeout = receive; - if (request->netconn) + if (netconn_connected( &request->netconn )) { - if (netconn_set_timeout( request->netconn, TRUE, send )) ret = FALSE; - if (netconn_set_timeout( request->netconn, FALSE, receive )) ret = FALSE; + if (netconn_set_timeout( &request->netconn, TRUE, send )) ret = FALSE; + if (netconn_set_timeout( &request->netconn, FALSE, receive )) ret = FALSE; } break; diff --git a/dll/win32/winhttp/url.c b/dll/win32/winhttp/url.c index 32b30da0ce6..e21dbfc81cf 100644 --- a/dll/win32/winhttp/url.c +++ b/dll/win32/winhttp/url.c @@ -16,21 +16,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include "config.h" -#include - -#include "wine/debug.h" - -#include "windef.h" -#include "winbase.h" -#include "winreg.h" -#include "winhttp.h" -#include "shlwapi.h" - #include "winhttp_private.h" -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}; diff --git a/dll/win32/winhttp/winhttp_private.h b/dll/win32/winhttp/winhttp_private.h index d5ec9ca4f9c..ee97a4c9f98 100644 --- a/dll/win32/winhttp/winhttp_private.h +++ b/dll/win32/winhttp/winhttp_private.h @@ -19,15 +19,27 @@ #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 -#include "wine/heap.h" -#include "wine/list.h" -#include "wine/unicode.h" +#include + +#define WIN32_NO_STATUS +#define _INC_WINDOWS +#define COM_NO_WINDOWS_H + +#define COBJMACROS +#define NONAMELESSUNION + +#include +#include +#include +#include +#include +#include + +#include +#include -#include #ifdef HAVE_SYS_SOCKET_H # include #endif @@ -44,8 +56,10 @@ # define ioctlsocket ioctl #endif -#include "ole2.h" -#include "sspi.h" +#include + +#include +WINE_DEFAULT_DEBUG_CHANNEL(winhttp); static const WCHAR getW[] = {'G','E','T',0}; static const WCHAR postW[] = {'P','O','S','T',0}; @@ -97,15 +111,6 @@ typedef struct WCHAR *path; } cookie_t; -typedef struct { - struct list entry; - LONG ref; - WCHAR *hostname; - INTERNET_PORT port; - BOOL secure; - struct list connections; -} hostdata_t; - typedef struct { object_header_t hdr; @@ -121,9 +126,6 @@ typedef struct LPWSTR proxy_password; struct list cookie_cache; HANDLE unload_event; - CredHandle cred_handle; - BOOL cred_handle_initialized; - DWORD secure_protocols; } session_t; typedef struct @@ -142,12 +144,8 @@ typedef struct typedef struct { - struct list entry; int socket; - struct sockaddr_storage sockaddr; BOOL secure; /* SSL active on connection? */ - hostdata_t *host; - ULONGLONG keep_until; CtxtHandle ssl_ctx; SecPkgContext_StreamSizes ssl_sizes; char *ssl_buf; @@ -156,6 +154,7 @@ typedef struct char *peek_msg; char *peek_msg_mem; size_t peek_len; + DWORD security_flags; } netconn_t; typedef struct @@ -207,8 +206,7 @@ typedef struct LPWSTR raw_headers; void *optional; DWORD optional_len; - netconn_t *netconn; - DWORD security_flags; + netconn_t netconn; int resolve_timeout; int connect_timeout; int send_timeout; @@ -297,15 +295,17 @@ void send_callback( object_header_t *, DWORD, LPVOID, DWORD ) DECLSPEC_HIDDEN; void close_connection( request_t * ) DECLSPEC_HIDDEN; BOOL netconn_close( netconn_t * ) DECLSPEC_HIDDEN; -netconn_t *netconn_create( hostdata_t *, const struct sockaddr_storage *, int ) DECLSPEC_HIDDEN; +BOOL netconn_connect( netconn_t *, const struct sockaddr *, unsigned int, int ) DECLSPEC_HIDDEN; +BOOL netconn_connected( netconn_t * ) DECLSPEC_HIDDEN; +BOOL netconn_create( netconn_t *, int, int, int ) DECLSPEC_HIDDEN; +BOOL netconn_init( netconn_t * ) DECLSPEC_HIDDEN; void netconn_unload( void ) DECLSPEC_HIDDEN; ULONG netconn_query_data_available( netconn_t * ) DECLSPEC_HIDDEN; BOOL netconn_recv( netconn_t *, void *, size_t, int, int * ) DECLSPEC_HIDDEN; -BOOL netconn_resolve( WCHAR *, INTERNET_PORT, struct sockaddr_storage *, int ) DECLSPEC_HIDDEN; -BOOL netconn_secure_connect( netconn_t *, WCHAR *, DWORD, CredHandle * ) DECLSPEC_HIDDEN; +BOOL netconn_resolve( WCHAR *, INTERNET_PORT, struct sockaddr *, socklen_t *, int ) DECLSPEC_HIDDEN; +BOOL netconn_secure_connect( netconn_t *, WCHAR * ) DECLSPEC_HIDDEN; BOOL netconn_send( netconn_t *, const void *, size_t, int * ) DECLSPEC_HIDDEN; DWORD netconn_set_timeout( netconn_t *, BOOL, int ) DECLSPEC_HIDDEN; -BOOL netconn_is_alive( netconn_t * ) DECLSPEC_HIDDEN; const void *netconn_get_certificate( netconn_t * ) DECLSPEC_HIDDEN; int netconn_get_cipher_strength( netconn_t * ) DECLSPEC_HIDDEN; @@ -316,18 +316,36 @@ void delete_domain( domain_t * ) DECLSPEC_HIDDEN; BOOL set_server_for_hostname( connect_t *, LPCWSTR, INTERNET_PORT ) DECLSPEC_HIDDEN; void destroy_authinfo( struct authinfo * ) DECLSPEC_HIDDEN; -void release_host( hostdata_t *host ) DECLSPEC_HIDDEN; - BOOL process_header( request_t *request, LPCWSTR field, LPCWSTR value, DWORD flags, BOOL request_only ) DECLSPEC_HIDDEN; extern HRESULT WinHttpRequest_create( void ** ) DECLSPEC_HIDDEN; void release_typelib( void ) DECLSPEC_HIDDEN; +static inline void* __WINE_ALLOC_SIZE(1) heap_alloc( SIZE_T size ) +{ + return HeapAlloc( GetProcessHeap(), 0, size ); +} + +static inline void* __WINE_ALLOC_SIZE(1) heap_alloc_zero( SIZE_T size ) +{ + return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size ); +} + +static inline void* __WINE_ALLOC_SIZE(2) heap_realloc( LPVOID mem, SIZE_T size ) +{ + return HeapReAlloc( GetProcessHeap(), 0, mem, size ); +} + static inline void* __WINE_ALLOC_SIZE(2) heap_realloc_zero( LPVOID mem, SIZE_T size ) { return HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, mem, size ); } +static inline BOOL heap_free( LPVOID mem ) +{ + return HeapFree( GetProcessHeap(), 0, mem ); +} + static inline WCHAR *strdupW( const WCHAR *src ) { WCHAR *dst; @@ -377,6 +395,4 @@ static inline char *strdupWA_sized( const WCHAR *src, DWORD size ) return dst; } -extern HINSTANCE winhttp_instance DECLSPEC_HIDDEN; - #endif /* _WINE_WINHTTP_PRIVATE_H_ */