winhttp: Cache and reuse persistent HTTP connections.
Signed-off-by: Jacek Caban <jacek@codeweavers.com> Signed-off-by: Hans Leidekker <hans@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
e0e8a3ff77
commit
5226865c53
|
@ -772,6 +772,36 @@ 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 )
|
||||
{
|
||||
char *hostname;
|
||||
|
|
|
@ -1011,15 +1011,25 @@ void release_host( host_t *host )
|
|||
LeaveCriticalSection( &connection_pool_cs );
|
||||
if (ref) return;
|
||||
|
||||
assert( list_empty( &host->connections ) );
|
||||
heap_free( host->hostname );
|
||||
heap_free( host );
|
||||
}
|
||||
|
||||
static void cache_connection( netconn_t *netconn )
|
||||
{
|
||||
TRACE( "caching connection %p\n", netconn );
|
||||
|
||||
EnterCriticalSection( &connection_pool_cs );
|
||||
list_add_head( &netconn->host->connections, &netconn->entry );
|
||||
LeaveCriticalSection( &connection_pool_cs );
|
||||
}
|
||||
|
||||
static BOOL open_connection( request_t *request )
|
||||
{
|
||||
BOOL is_secure = request->hdr.flags & WINHTTP_FLAG_SECURE;
|
||||
host_t *host = NULL, *iter;
|
||||
netconn_t *netconn;
|
||||
netconn_t *netconn = NULL;
|
||||
connect_t *connect;
|
||||
WCHAR *addressW = NULL;
|
||||
INTERNET_PORT port;
|
||||
|
@ -1048,6 +1058,7 @@ static BOOL open_connection( request_t *request )
|
|||
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 );
|
||||
|
@ -1063,6 +1074,29 @@ static BOOL open_connection( request_t *request )
|
|||
|
||||
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;
|
||||
|
@ -1084,6 +1118,8 @@ static BOOL open_connection( request_t *request )
|
|||
send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED, addressW, len );
|
||||
}
|
||||
|
||||
if (!netconn)
|
||||
{
|
||||
if (!addressW && !(addressW = addr_to_str( &connect->sockaddr )))
|
||||
{
|
||||
release_host( host );
|
||||
|
@ -1094,16 +1130,15 @@ static BOOL open_connection( request_t *request )
|
|||
|
||||
send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, addressW, 0 );
|
||||
|
||||
netconn = netconn_create( host, &connect->sockaddr, request->connect_timeout );
|
||||
if (!netconn)
|
||||
if (!(netconn = netconn_create( host, &connect->sockaddr, request->connect_timeout )))
|
||||
{
|
||||
release_host( host );
|
||||
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 (request->hdr.flags & WINHTTP_FLAG_SECURE)
|
||||
if (is_secure)
|
||||
{
|
||||
if (connect->session->proxy_server &&
|
||||
strcmpiW( connect->hostname, connect->servername ))
|
||||
|
@ -1117,14 +1152,23 @@ static BOOL open_connection( request_t *request )
|
|||
}
|
||||
if (!netconn_secure_connect( netconn, connect->hostname, request->security_flags ))
|
||||
{
|
||||
netconn_close( netconn );
|
||||
heap_free( addressW );
|
||||
netconn_close( netconn );
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
request->netconn = netconn;
|
||||
|
||||
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;
|
||||
|
@ -1309,6 +1353,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 ))
|
||||
|
@ -1316,7 +1362,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 */
|
||||
|
|
|
@ -484,8 +484,6 @@ static const struct notification async_test[] =
|
|||
{ winhttp_read_data, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_ALLOW },
|
||||
{ winhttp_read_data, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_ALLOW },
|
||||
{ winhttp_read_data, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, NF_SIGNAL },
|
||||
{ winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION, NF_WINE_ALLOW },
|
||||
{ winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED, NF_WINE_ALLOW },
|
||||
{ winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING },
|
||||
{ winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING },
|
||||
{ winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }
|
||||
|
|
|
@ -102,6 +102,7 @@ typedef struct {
|
|||
WCHAR *hostname;
|
||||
INTERNET_PORT port;
|
||||
BOOL secure;
|
||||
struct list connections;
|
||||
} host_t;
|
||||
|
||||
typedef struct
|
||||
|
@ -137,6 +138,7 @@ typedef struct
|
|||
|
||||
typedef struct
|
||||
{
|
||||
struct list entry;
|
||||
int socket;
|
||||
struct sockaddr_storage sockaddr;
|
||||
BOOL secure; /* SSL active on connection? */
|
||||
|
@ -300,6 +302,7 @@ BOOL netconn_resolve( WCHAR *, INTERNET_PORT, struct sockaddr_storage *, int ) D
|
|||
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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue