diff --git a/reactos/dll/win32/winhttp/CMakeLists.txt b/reactos/dll/win32/winhttp/CMakeLists.txt index f0c4df8be60..9245cfaf5f9 100644 --- a/reactos/dll/win32/winhttp/CMakeLists.txt +++ b/reactos/dll/win32/winhttp/CMakeLists.txt @@ -1,4 +1,7 @@ +remove_definitions(-D_WIN32_WINNT=0x502) +add_definitions(-D_WIN32_WINNT=0x600) + add_definitions( -D__WINESRC__ -D_WINE) @@ -27,7 +30,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 msvcrt kernel32 ntdll) +add_importlibs(winhttp user32 advapi32 ws2_32 jsproxy kernel32_vista msvcrt kernel32 ntdll) add_dependencies(winhttp stdole2) add_pch(winhttp winhttp_private.h SOURCE) add_cd_file(TARGET winhttp DESTINATION reactos/system32 FOR all) diff --git a/reactos/dll/win32/winhttp/inet_ntop.c b/reactos/dll/win32/winhttp/inet_ntop.c index 3ed42ef6bb0..99d5ccdcf19 100644 --- a/reactos/dll/win32/winhttp/inet_ntop.c +++ b/reactos/dll/win32/winhttp/inet_ntop.c @@ -51,16 +51,18 @@ static const char *inet_ntop6(const u_char *src, char *dst, size_t size); * author: * Paul Vixie, 1996. */ -const char * -inet_ntop(int af, const void *src, char *dst, size_t size) + +PCSTR +WSAAPI +inet_ntop(INT Family, PVOID pAddr, PSTR pStringBuf, size_t StringBufSize) { - switch (af) { + switch (Family) { case AF_INET: - return (inet_ntop4(src, dst, size)); + return (inet_ntop4(pAddr, pStringBuf, StringBufSize)); #ifdef INET6 case AF_INET6: - return (inet_ntop6(src, dst, size)); + return (inet_ntop6(pAddr, pStringBuf, StringBufSize)); #endif default: WSASetLastError(WSAEAFNOSUPPORT); diff --git a/reactos/dll/win32/winhttp/main.c b/reactos/dll/win32/winhttp/main.c index f46b59aa8f0..55c601e5d59 100644 --- a/reactos/dll/win32/winhttp/main.c +++ b/reactos/dll/win32/winhttp/main.c @@ -21,7 +21,7 @@ #include #include -static HINSTANCE instance; +HINSTANCE winhttp_instance; /****************************************************************** * DllMain (winhttp.@) @@ -31,7 +31,7 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv) switch(fdwReason) { case DLL_PROCESS_ATTACH: - instance = hInstDLL; + winhttp_instance = hInstDLL; DisableThreadLibraryCalls(hInstDLL); break; case DLL_PROCESS_DETACH: @@ -158,7 +158,7 @@ HRESULT WINAPI DllCanUnloadNow(void) */ HRESULT WINAPI DllRegisterServer(void) { - return __wine_register_resources( instance ); + return __wine_register_resources( winhttp_instance ); } /*********************************************************************** @@ -166,5 +166,5 @@ HRESULT WINAPI DllRegisterServer(void) */ HRESULT WINAPI DllUnregisterServer(void) { - return __wine_unregister_resources( instance ); + return __wine_unregister_resources( winhttp_instance ); } diff --git a/reactos/dll/win32/winhttp/net.c b/reactos/dll/win32/winhttp/net.c index 737d8e59d30..5c4ace898cc 100644 --- a/reactos/dll/win32/winhttp/net.c +++ b/reactos/dll/win32/winhttp/net.c @@ -298,13 +298,6 @@ 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) @@ -319,56 +312,38 @@ void netconn_unload( void ) #endif } -BOOL netconn_connected( netconn_t *conn ) -{ - return (conn->socket != -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 ) ); - return FALSE; - } - return TRUE; -} - -BOOL netconn_close( netconn_t *conn ) -{ - int res; - - if (conn->secure) - { - 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 ) +netconn_t *netconn_create( hostdata_t *host, const struct sockaddr_storage *sockaddr, int timeout ) { + netconn_t *conn; + unsigned int addr_len; BOOL ret = FALSE; int res; ULONG state; + 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) + { + WARN("unable to create socket (%s)\n", strerror(errno)); + set_last_error( sock_get_error( errno ) ); + heap_free(conn); + return NULL; + } + + switch (conn->sockaddr.ss_family) + { + case AF_INET: + addr_len = sizeof(struct sockaddr_in); + break; + case AF_INET6: + addr_len = sizeof(struct sockaddr_in6); + break; + default: + assert(0); + } + if (timeout > 0) { state = 1; @@ -378,7 +353,7 @@ BOOL netconn_connect( netconn_t *conn, const struct sockaddr *sockaddr, unsigned for (;;) { res = 0; - if (connect( conn->socket, sockaddr, addr_len ) < 0) + if (connect( conn->socket, (const struct sockaddr *)&conn->sockaddr, addr_len ) < 0) { res = sock_get_error( errno ); if (res == WSAEWOULDBLOCK || res == WSAEINPROGRESS) @@ -436,11 +411,35 @@ BOOL netconn_connect( netconn_t *conn, const struct sockaddr *sockaddr, unsigned { WARN("unable to connect to host (%d)\n", res); set_last_error( res ); + netconn_close( conn ); + return NULL; } - return ret; + return conn; } -BOOL netconn_secure_connect( netconn_t *conn, WCHAR *hostname ) +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 ) { 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}; @@ -540,7 +539,7 @@ BOOL netconn_secure_connect( netconn_t *conn, WCHAR *hostname ) status = QueryContextAttributesW(&ctx, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (void*)&cert); if(status == SEC_E_OK) { - res = netconn_verify_cert(cert, hostname, conn->security_flags); + res = netconn_verify_cert(cert, hostname, security_flags); CertFreeCertificateContext(cert); if(res != ERROR_SUCCESS) { WARN("cert verify failed: %u\n", res); @@ -605,7 +604,6 @@ 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; @@ -729,7 +727,6 @@ 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) @@ -786,13 +783,7 @@ BOOL netconn_recv( netconn_t *conn, void *buf, size_t len, int flags, int *recvd ULONG netconn_query_data_available( netconn_t *conn ) { - if(!netconn_connected(conn)) - return 0; - - if(conn->secure) - return conn->peek_len; - - return 0; + return conn->secure ? conn->peek_len : 0; } DWORD netconn_set_timeout( netconn_t *netconn, BOOL send, int value ) @@ -811,7 +802,37 @@ DWORD netconn_set_timeout( netconn_t *netconn, BOOL send, int value ) return ERROR_SUCCESS; } -static DWORD resolve_hostname( const WCHAR *hostnameW, INTERNET_PORT port, struct sockaddr *sa, socklen_t *sa_len ) +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 ) { char *hostname; #ifdef HAVE_GETADDRINFO @@ -845,13 +866,6 @@ 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) @@ -877,13 +891,6 @@ 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; @@ -896,19 +903,18 @@ static DWORD resolve_hostname( const WCHAR *hostnameW, INTERNET_PORT port, struc struct resolve_args { - const WCHAR *hostname; - INTERNET_PORT port; - struct sockaddr *sa; - socklen_t *sa_len; + 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, ra->sa_len ); + return resolve_hostname( ra->hostname, ra->port, ra->sa ); } -BOOL netconn_resolve( WCHAR *hostname, INTERNET_PORT port, struct sockaddr *sa, socklen_t *sa_len, int timeout ) +BOOL netconn_resolve( WCHAR *hostname, INTERNET_PORT port, struct sockaddr_storage *sa, int timeout ) { DWORD ret; @@ -921,7 +927,6 @@ BOOL netconn_resolve( WCHAR *hostname, INTERNET_PORT port, struct sockaddr *sa, 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; @@ -931,7 +936,7 @@ BOOL netconn_resolve( WCHAR *hostname, INTERNET_PORT port, struct sockaddr *sa, else ret = ERROR_WINHTTP_TIMEOUT; CloseHandle( thread ); } - else ret = resolve_hostname( hostname, port, sa, sa_len ); + else ret = resolve_hostname( hostname, port, sa ); if (ret) { diff --git a/reactos/dll/win32/winhttp/request.c b/reactos/dll/win32/winhttp/request.c index d42f7dbb810..128d5cb14cc 100644 --- a/reactos/dll/win32/winhttp/request.c +++ b/reactos/dll/win32/winhttp/request.c @@ -32,6 +32,8 @@ #include "inet_ntop.c" +#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}; @@ -540,7 +542,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.secure ? https : http; + LPCWSTR scheme = (request->netconn ? request->netconn->secure : (request->hdr.flags & WINHTTP_FLAG_SECURE)) ? https : http; int len; len = strlenW( scheme ) + strlenW( request->connect->hostname ); @@ -945,7 +947,7 @@ static BOOL secure_proxy_connect( request_t *request ) { int len = strlen( req_ascii ), bytes_sent; - ret = netconn_send( &request->netconn, req_ascii, len, &bytes_sent ); + ret = netconn_send( request->netconn, req_ascii, len, &bytes_sent ); heap_free( req_ascii ); if (ret) ret = read_reply( request ); @@ -959,12 +961,12 @@ static BOOL secure_proxy_connect( request_t *request ) #define INET6_ADDRSTRLEN 46 #endif -static WCHAR *addr_to_str( struct sockaddr *addr ) +static WCHAR *addr_to_str( struct sockaddr_storage *addr ) { char buf[INET6_ADDRSTRLEN]; void *src; - switch (addr->sa_family) + switch (addr->ss_family) { case AF_INET: src = &((struct sockaddr_in *)addr)->sin_addr; @@ -973,79 +975,258 @@ static WCHAR *addr_to_str( struct sockaddr *addr ) src = &((struct sockaddr_in6 *)addr)->sin6_addr; break; default: - WARN("unsupported address family %d\n", addr->sa_family); + WARN("unsupported address family %d\n", addr->ss_family); return NULL; } - if (!inet_ntop( addr->sa_family, src, buf, sizeof(buf) )) 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 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; - socklen_t slen; - struct sockaddr *saddr; DWORD len; - if (netconn_connected( &request->netconn )) goto done; + if (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); + + 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( connect->servername ) + 1; - send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME, connect->servername, len ); + len = strlenW( host->hostname ) + 1; + send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME, host->hostname, len ); - if (!netconn_resolve( connect->servername, port, saddr, &slen, request->resolve_timeout )) return FALSE; + if (!netconn_resolve( host->hostname, port, &connect->sockaddr, request->resolve_timeout )) + { + release_host( host ); + return FALSE; + } connect->resolved = TRUE; - if (!(addressW = addr_to_str( saddr ))) return FALSE; + 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 (!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 )) + if (!netconn) { - 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 (!addressW && !(addressW = addr_to_str( &connect->sockaddr ))) { - if (!secure_proxy_connect( request )) + 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 (!netconn_secure_connect( netconn, connect->hostname, request->security_flags )) { heap_free( addressW ); + netconn_close( netconn ); 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 ); + 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; @@ -1058,10 +1239,11 @@ done: void close_connection( request_t *request ) { - if (!netconn_connected( &request->netconn )) return; + if (!request->netconn) return; send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION, 0, 0 ); - netconn_close( &request->netconn ); + netconn_close( request->netconn ); + request->netconn = NULL; send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED, 0, 0 ); } @@ -1127,7 +1309,7 @@ static BOOL read_more_data( request_t *request, int maxlen, BOOL notify ) if (notify) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NULL, 0 ); - ret = netconn_recv( &request->netconn, request->read_buf + request->read_size, + 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) ); @@ -1229,6 +1411,8 @@ static void finished_reading( request_t *request ) 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 )) @@ -1236,7 +1420,14 @@ static void finished_reading( request_t *request ) if (!strcmpiW( connection, closeW )) close = TRUE; } else if (!strcmpW( request->version, http1_0 )) close = TRUE; - if (close) close_connection( request ); + if (close) + { + close_connection( request ); + return; + } + + cache_connection( request->netconn ); + request->netconn = NULL; } /* return the size of data available to be read immediately */ @@ -1291,13 +1482,20 @@ done: /* read any content returned by the server so that the connection can be reused */ static void drain_content( request_t *request ) { - DWORD bytes_read; + DWORD size, bytes_read, bytes_total = 0, bytes_left = request->content_length - request->content_read; char buffer[2048]; refill_buffer( request, FALSE ); for (;;) { - if (!read_data( request, buffer, sizeof(buffer), &bytes_read, FALSE ) || !bytes_read) return; + 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; } } @@ -1362,13 +1560,13 @@ static BOOL send_request( request_t *request, LPCWSTR headers, DWORD headers_len send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST, NULL, 0 ); - ret = netconn_send( &request->netconn, req_ascii, len, &bytes_sent ); + 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; + if (!netconn_send( request->netconn, optional, optional_len, &bytes_sent )) goto end; request->optional = optional; request->optional_len = optional_len; len += optional_len; @@ -2145,7 +2343,7 @@ static BOOL read_reply( request_t *request ) WCHAR *versionW, *status_textW, *raw_headers; WCHAR status_codeW[4]; /* sizeof("nnn") */ - if (!netconn_connected( &request->netconn )) return FALSE; + if (!request->netconn) return FALSE; do { @@ -2331,11 +2529,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 ); - if (!(ret = netconn_init( &request->netconn ))) goto end; + netconn_close( request->netconn ); + request->netconn = NULL; + request->content_length = request->content_read = 0; request->read_pos = request->read_size = 0; - request->read_chunked = FALSE; - request->read_chunked_eof = FALSE; + request->read_chunked = request->read_chunked_eof = FALSE; } else heap_free( hostname ); @@ -2483,14 +2681,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) - count += netconn_query_data_available( &request->netconn ); + if (!request->read_chunked && request->netconn) + count += netconn_query_data_available( request->netconn ); if (!count) { refill_buffer( request, async ); count = get_available_data( request ); - if (!request->read_chunked) - count += netconn_query_data_available( &request->netconn ); + if (!request->read_chunked && request->netconn) + count += netconn_query_data_available( request->netconn ); } done: @@ -2603,7 +2801,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/reactos/dll/win32/winhttp/session.c b/reactos/dll/win32/winhttp/session.c index 7b310f4605a..429f5059143 100644 --- a/reactos/dll/win32/winhttp/session.c +++ b/reactos/dll/win32/winhttp/session.c @@ -685,7 +685,7 @@ static BOOL request_query_option( object_header_t *hdr, DWORD option, LPVOID buf { case WINHTTP_OPTION_SECURITY_FLAGS: { - DWORD flags; + DWORD flags = 0; int bits; if (!buffer || *buflen < sizeof(flags)) @@ -697,14 +697,17 @@ 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->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; + 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; + } *(DWORD *)buffer = flags; *buflen = sizeof(flags); return TRUE; @@ -720,7 +723,7 @@ static BOOL request_query_option( object_header_t *hdr, DWORD option, LPVOID buf return FALSE; } - if (!(cert = netconn_get_certificate( &request->netconn ))) return FALSE; + if (!request->netconn || !(cert = netconn_get_certificate( request->netconn ))) return FALSE; *(CERT_CONTEXT **)buffer = (CERT_CONTEXT *)cert; *buflen = sizeof(cert); return TRUE; @@ -739,7 +742,7 @@ static BOOL request_query_option( object_header_t *hdr, DWORD option, LPVOID buf set_last_error( ERROR_INSUFFICIENT_BUFFER ); return FALSE; } - if (!(cert = netconn_get_certificate( &request->netconn ))) return FALSE; + if (!request->netconn || !(cert = netconn_get_certificate( request->netconn ))) return FALSE; ci->ftExpiry = cert->pCertInfo->NotAfter; ci->ftStart = cert->pCertInfo->NotBefore; @@ -754,7 +757,7 @@ static BOOL request_query_option( object_header_t *hdr, DWORD option, LPVOID buf else ci->lpszSignatureAlgName = NULL; ci->lpszEncryptionAlgName = NULL; - ci->dwKeySize = netconn_get_cipher_strength( &request->netconn ); + ci->dwKeySize = request->netconn ? netconn_get_cipher_strength( request->netconn ) : 0; CertFreeCertificateContext( cert ); *buflen = sizeof(*ci); @@ -769,7 +772,7 @@ static BOOL request_query_option( object_header_t *hdr, DWORD option, LPVOID buf return FALSE; } - *(DWORD *)buffer = netconn_get_cipher_strength( &request->netconn ); + *(DWORD *)buffer = request->netconn ? netconn_get_cipher_strength( request->netconn ) : 0; *buflen = sizeof(DWORD); return TRUE; } @@ -786,12 +789,12 @@ static BOOL request_query_option( object_header_t *hdr, DWORD option, LPVOID buf set_last_error( ERROR_INSUFFICIENT_BUFFER ); return FALSE; } - if (!netconn_connected( &request->netconn )) + if (!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); @@ -927,7 +930,7 @@ static BOOL request_set_option( object_header_t *hdr, DWORD option, LPVOID buffe set_last_error( ERROR_INVALID_PARAMETER ); return FALSE; } - request->netconn.security_flags = flags; + request->security_flags = flags; return TRUE; } case WINHTTP_OPTION_RESOLVE_TIMEOUT: @@ -1064,7 +1067,6 @@ 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; @@ -2047,10 +2049,10 @@ BOOL WINAPI WinHttpSetTimeouts( HINTERNET handle, int resolve, int connect, int if (receive < 0) receive = 0; request->recv_timeout = receive; - if (netconn_connected( &request->netconn )) + if (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/reactos/dll/win32/winhttp/winhttp_private.h b/reactos/dll/win32/winhttp/winhttp_private.h index ee97a4c9f98..7e80dcab4e9 100644 --- a/reactos/dll/win32/winhttp/winhttp_private.h +++ b/reactos/dll/win32/winhttp/winhttp_private.h @@ -111,6 +111,15 @@ 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; @@ -144,8 +153,12 @@ 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; @@ -154,7 +167,6 @@ typedef struct char *peek_msg; char *peek_msg_mem; size_t peek_len; - DWORD security_flags; } netconn_t; typedef struct @@ -206,7 +218,8 @@ typedef struct LPWSTR raw_headers; void *optional; DWORD optional_len; - netconn_t netconn; + netconn_t *netconn; + DWORD security_flags; int resolve_timeout; int connect_timeout; int send_timeout; @@ -295,17 +308,15 @@ 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; -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; +netconn_t *netconn_create( hostdata_t *, const struct sockaddr_storage *, int ) 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 *, socklen_t *, int ) DECLSPEC_HIDDEN; -BOOL netconn_secure_connect( netconn_t *, WCHAR * ) DECLSPEC_HIDDEN; +BOOL netconn_resolve( WCHAR *, INTERNET_PORT, struct sockaddr_storage *, int ) DECLSPEC_HIDDEN; +BOOL netconn_secure_connect( netconn_t *, WCHAR *, DWORD ) 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,6 +327,8 @@ 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; @@ -395,4 +408,6 @@ static inline char *strdupWA_sized( const WCHAR *src, DWORD size ) return dst; } +extern HINSTANCE winhttp_instance DECLSPEC_HIDDEN; + #endif /* _WINE_WINHTTP_PRIVATE_H_ */ diff --git a/reactos/media/doc/README.WINE b/reactos/media/doc/README.WINE index 43992e96f54..396ca32ca7a 100644 --- a/reactos/media/doc/README.WINE +++ b/reactos/media/doc/README.WINE @@ -200,7 +200,7 @@ reactos/dll/win32/windowscodecs # Synced to WineStaging-2.9 reactos/dll/win32/windowscodecsext # Synced to WineStaging-2.9 reactos/dll/win32/winemp3.acm # Synced to WineStaging-2.16 reactos/dll/win32/wing32 # Synced to WineStaging-2.9 -reactos/dll/win32/winhttp # Synced to WineStaging-2.9 +reactos/dll/win32/winhttp # Synced to WineStaging-2.16 reactos/dll/win32/wininet # Synced to WineStaging-2.9 reactos/dll/win32/winmm # Forked at Wine-20050628 reactos/dll/win32/winmm/midimap # Forked at Wine-20050628