Commit 8a1df203 authored by Jacek Caban's avatar Jacek Caban Committed by Alexandre Julliard

wininet: Added support for persistent HTTP connections.

parent 28c8e228
......@@ -574,7 +574,7 @@ static void call_continue(PROTOCOLDATA *protocol_data)
CLEAR_CALLED(ReportProgress_FINDINGRESOURCE);
CLEAR_CALLED(ReportProgress_CONNECTING);
CLEAR_CALLED(ReportProgress_PROXYDETECTING);
}else todo_wine {
}else {
CHECK_NOT_CALLED(ReportProgress_FINDINGRESOURCE);
/* IE7 does call this */
CLEAR_CALLED(ReportProgress_CONNECTING);
......
......@@ -1795,7 +1795,7 @@ static HRESULT WINAPI statusclb_OnStopBinding(IBindStatusCallbackEx *iface, HRES
if(filedwl_api)
ok(SUCCEEDED(hresult), "binding failed: %08x\n", hresult);
else if(invalid_cn_accepted)
todo_wine ok(hresult == binding_hres, "binding failed: %08x, expected %08x\n", hresult, binding_hres);
ok(hresult == binding_hres, "binding failed: %08x, expected %08x\n", hresult, binding_hres);
else
ok(hresult == binding_hres, "binding failed: %08x, expected %08x\n", hresult, binding_hres);
ok(szError == NULL, "szError should be NULL\n");
......@@ -2876,14 +2876,12 @@ static void test_BindToStorage(int protocol, DWORD flags, DWORD t)
ok(hres == binding_hres, "Got %08x\n", hres);
ok(unk == NULL, "Got %p\n", unk);
}else if((flags & BINDTEST_INVALID_CN) && invalid_cn_accepted) {
todo_wine {
ok(hres == S_OK, "IMoniker_BindToStorage failed: %08x\n", hres);
ok(unk != NULL, "unk == NULL\n");
if(unk == NULL) {
ok(0, "Expected security problem to be ignored.\n");
invalid_cn_accepted = FALSE;
binding_hres = INET_E_INVALID_CERTIFICATE;
}
ok(hres == S_OK, "IMoniker_BindToStorage failed: %08x\n", hres);
ok(unk != NULL, "unk == NULL\n");
if(unk == NULL) {
ok(0, "Expected security problem to be ignored.\n");
invalid_cn_accepted = FALSE;
binding_hres = INET_E_INVALID_CERTIFICATE;
}
}else {
ok(hres == S_OK, "IMoniker_BindToStorage failed: %08x\n", hres);
......@@ -2958,11 +2956,9 @@ static void test_BindToStorage(int protocol, DWORD flags, DWORD t)
CLEAR_CALLED(OnProgress_CONNECTING);
}
}else if(!abort_start) {
todo_wine {
CHECK_NOT_CALLED(OnProgress_FINDINGRESOURCE);
/* IE7 does call this */
CLEAR_CALLED(OnProgress_CONNECTING);
}
CHECK_NOT_CALLED(OnProgress_FINDINGRESOURCE);
/* IE7 does call this */
CLEAR_CALLED(OnProgress_CONNECTING);
}
if((flags & BINDTEST_INVALID_CN) && !invalid_cn_accepted) {
CHECK_CALLED(QueryInterface_IHttpSecurity);
......@@ -3186,7 +3182,7 @@ static void test_BindToObject(int protocol, DWORD flags)
if(http_is_first) {
CHECK_CALLED(Obj_OnProgress_FINDINGRESOURCE);
CHECK_CALLED(Obj_OnProgress_CONNECTING);
}else todo_wine {
}else {
CHECK_NOT_CALLED(Obj_OnProgress_FINDINGRESOURCE);
/* IE7 does call this */
CLEAR_CALLED(Obj_OnProgress_CONNECTING);
......
......@@ -308,7 +308,7 @@ BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
break;
case DLL_PROCESS_DETACH:
collect_connections(TRUE);
NETCON_unload();
URLCacheContainers_DeleteAll();
......
......@@ -49,13 +49,40 @@
extern HMODULE WININET_hModule;
#ifndef INET6_ADDRSTRLEN
#define INET6_ADDRSTRLEN 46
#endif
typedef struct {
WCHAR *name;
INTERNET_PORT port;
struct sockaddr_storage addr;
socklen_t addr_len;
char addr_str[INET6_ADDRSTRLEN];
LONG ref;
DWORD64 keep_until;
struct list entry;
struct list conn_pool;
} server_t;
void server_addref(server_t*);
void server_release(server_t*);
BOOL collect_connections(BOOL);
/* used for netconnection.c stuff */
typedef struct
{
BOOL useSSL;
int socketFD;
void *ssl_s;
server_t *server;
DWORD security_flags;
BOOL keep_alive;
DWORD64 keep_until;
struct list pool_entry;
} netconn_t;
static inline void * __WINE_ALLOC_SIZE(1) heap_alloc(size_t len)
......@@ -228,7 +255,6 @@ typedef struct
DWORD accessType;
} appinfo_t;
typedef struct
{
object_header_t hdr;
......@@ -239,8 +265,6 @@ typedef struct
LPWSTR password;
INTERNET_PORT hostPort; /* the final destination port of the request */
INTERNET_PORT serverPort; /* the port of the server we directly connect to */
struct sockaddr_storage socketAddress;
socklen_t sa_len;
} http_session_t;
#define HDR_ISREQUEST 0x0001
......@@ -279,7 +303,8 @@ typedef struct
LPWSTR path;
LPWSTR verb;
LPWSTR rawHeaders;
netconn_t netConnection;
netconn_t *netconn;
DWORD security_flags;
LPWSTR version;
LPWSTR statusText;
DWORD bytesToWrite;
......@@ -487,20 +512,16 @@ VOID INTERNET_SendCallback(object_header_t *hdr, DWORD_PTR dwContext,
DWORD dwStatusInfoLength) DECLSPEC_HIDDEN;
BOOL INTERNET_FindProxyForProtocol(LPCWSTR szProxy, LPCWSTR proto, WCHAR *foundProxy, DWORD *foundProxyLen) DECLSPEC_HIDDEN;
BOOL NETCON_connected(netconn_t *connection) DECLSPEC_HIDDEN;
DWORD NETCON_init(netconn_t *connnection, BOOL useSSL) DECLSPEC_HIDDEN;
DWORD create_netconn(BOOL,server_t*,DWORD,netconn_t**) DECLSPEC_HIDDEN;
void free_netconn(netconn_t*) DECLSPEC_HIDDEN;
void NETCON_unload(void) DECLSPEC_HIDDEN;
DWORD NETCON_create(netconn_t *connection, int domain,
int type, int protocol) DECLSPEC_HIDDEN;
DWORD NETCON_close(netconn_t *connection) DECLSPEC_HIDDEN;
DWORD NETCON_connect(netconn_t *connection, const struct sockaddr *serv_addr,
unsigned int addrlen) DECLSPEC_HIDDEN;
DWORD NETCON_secure_connect(netconn_t *connection, LPWSTR hostname) DECLSPEC_HIDDEN;
DWORD NETCON_send(netconn_t *connection, const void *msg, size_t len, int flags,
int *sent /* out */) DECLSPEC_HIDDEN;
DWORD NETCON_recv(netconn_t *connection, void *buf, size_t len, int flags,
int *recvd /* out */) DECLSPEC_HIDDEN;
BOOL NETCON_query_data_available(netconn_t *connection, DWORD *available) DECLSPEC_HIDDEN;
BOOL NETCON_is_alive(netconn_t*) DECLSPEC_HIDDEN;
LPCVOID NETCON_GetCert(netconn_t *connection) DECLSPEC_HIDDEN;
int NETCON_GetCipherStrength(netconn_t*) DECLSPEC_HIDDEN;
DWORD NETCON_set_timeout(netconn_t *connection, BOOL send, int value) DECLSPEC_HIDDEN;
......
......@@ -70,6 +70,7 @@
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <assert.h>
#include "wine/library.h"
#include "windef.h"
......@@ -493,22 +494,64 @@ static DWORD init_openssl(void)
#endif
}
DWORD NETCON_init(netconn_t *connection, BOOL useSSL)
DWORD create_netconn(BOOL useSSL, server_t *server, DWORD security_flags, netconn_t **ret)
{
DWORD res = ERROR_SUCCESS;
netconn_t *netconn;
int result;
connection->useSSL = useSSL;
connection->socketFD = -1;
if(useSSL) {
DWORD res;
if (useSSL) {
TRACE("using SSL connection\n");
EnterCriticalSection(&init_ssl_cs);
res = init_openssl();
LeaveCriticalSection(&init_ssl_cs);
if(res != ERROR_SUCCESS)
return res;
}
return res;
netconn = heap_alloc_zero(sizeof(*netconn));
if(!netconn)
return ERROR_OUTOFMEMORY;
netconn->useSSL = useSSL;
netconn->socketFD = -1;
netconn->security_flags = security_flags;
list_init(&netconn->pool_entry);
assert(server->addr_len);
result = netconn->socketFD = socket(server->addr.ss_family, SOCK_STREAM, 0);
if(result != -1) {
result = connect(netconn->socketFD, (struct sockaddr*)&server->addr, server->addr_len);
if(result == -1)
closesocket(netconn->socketFD);
}
if(result == -1) {
heap_free(netconn);
return sock_get_error(errno);
}
server_addref(server);
netconn->server = server;
*ret = netconn;
return ERROR_SUCCESS;
}
void free_netconn(netconn_t *netconn)
{
server_release(netconn->server);
#ifdef SONAME_LIBSSL
if (netconn->ssl_s) {
pSSL_shutdown(netconn->ssl_s);
pSSL_free(netconn->ssl_s);
}
#endif
closesocket(netconn->socketFD);
heap_free(netconn);
}
void NETCON_unload(void)
......@@ -534,11 +577,6 @@ void NETCON_unload(void)
#endif
}
BOOL NETCON_connected(netconn_t *connection)
{
return connection->socketFD != -1;
}
/* translate a unix error code into a winsock one */
int sock_get_error( int err )
{
......@@ -607,52 +645,6 @@ int sock_get_error( int err )
}
/******************************************************************************
* NETCON_create
* Basically calls 'socket()'
*/
DWORD NETCON_create(netconn_t *connection, int domain,
int type, int protocol)
{
#ifdef SONAME_LIBSSL
if (connection->ssl_s)
return ERROR_NOT_SUPPORTED;
#endif
connection->socketFD = socket(domain, type, protocol);
if (connection->socketFD == -1)
return sock_get_error(errno);
return ERROR_SUCCESS;
}
/******************************************************************************
* NETCON_close
* Basically calls 'close()' unless we should use SSL
*/
DWORD NETCON_close(netconn_t *connection)
{
int result;
if (!NETCON_connected(connection)) return ERROR_SUCCESS;
#ifdef SONAME_LIBSSL
if (connection->ssl_s)
{
pSSL_shutdown(connection->ssl_s);
pSSL_free(connection->ssl_s);
connection->ssl_s = NULL;
}
#endif
result = closesocket(connection->socketFD);
connection->socketFD = -1;
if (result == -1)
return sock_get_error(errno);
return ERROR_SUCCESS;
}
/******************************************************************************
* NETCON_secure_connect
* Initiates a secure connection over an existing plaintext connection.
*/
......@@ -722,28 +714,6 @@ fail:
}
/******************************************************************************
* NETCON_connect
* Connects to the specified address.
*/
DWORD NETCON_connect(netconn_t *connection, const struct sockaddr *serv_addr,
unsigned int addrlen)
{
int result;
result = connect(connection->socketFD, serv_addr, addrlen);
if (result == -1)
{
WARN("Unable to connect to host (%s)\n", strerror(errno));
closesocket(connection->socketFD);
connection->socketFD = -1;
return sock_get_error(errno);
}
return ERROR_SUCCESS;
}
/******************************************************************************
* NETCON_send
* Basically calls 'send()' unless we should use SSL
* number of chars send is put in *sent
......@@ -751,7 +721,6 @@ DWORD NETCON_connect(netconn_t *connection, const struct sockaddr *serv_addr,
DWORD NETCON_send(netconn_t *connection, const void *msg, size_t len, int flags,
int *sent /* out */)
{
if (!NETCON_connected(connection)) return ERROR_INTERNET_CONNECTION_ABORTED;
if (!connection->useSSL)
{
*sent = send(connection->socketFD, msg, len, flags);
......@@ -787,14 +756,11 @@ DWORD NETCON_recv(netconn_t *connection, void *buf, size_t len, int flags,
int *recvd /* out */)
{
*recvd = 0;
if (!NETCON_connected(connection)) return ERROR_INTERNET_CONNECTION_ABORTED;
if (!len)
return ERROR_SUCCESS;
if (!connection->useSSL)
{
*recvd = recv(connection->socketFD, buf, len, flags);
if(!*recvd)
NETCON_close(connection);
return *recvd == -1 ? sock_get_error(errno) : ERROR_SUCCESS;
}
else
......@@ -808,10 +774,8 @@ DWORD NETCON_recv(netconn_t *connection, void *buf, size_t len, int flags,
/* Check if EOF was received */
if(!*recvd && (pSSL_get_error(connection->ssl_s, *recvd)==SSL_ERROR_ZERO_RETURN
|| pSSL_get_error(connection->ssl_s, *recvd)==SSL_ERROR_SYSCALL)) {
NETCON_close(connection);
|| pSSL_get_error(connection->ssl_s, *recvd)==SSL_ERROR_SYSCALL))
return ERROR_SUCCESS;
}
return *recvd > 0 ? ERROR_SUCCESS : ERROR_INTERNET_CONNECTION_ABORTED;
#else
......@@ -828,8 +792,6 @@ DWORD NETCON_recv(netconn_t *connection, void *buf, size_t len, int flags,
BOOL NETCON_query_data_available(netconn_t *connection, DWORD *available)
{
*available = 0;
if (!NETCON_connected(connection))
return FALSE;
if (!connection->useSSL)
{
......@@ -852,6 +814,36 @@ BOOL NETCON_query_data_available(netconn_t *connection, DWORD *available)
return TRUE;
}
BOOL NETCON_is_alive(netconn_t *netconn)
{
#ifdef MSG_DONTWAIT
ssize_t len;
BYTE b;
len = recv(netconn->socketFD, &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->socketFD, FIONBIO, &mode))
return FALSE;
len = recv(netconn->socketFD, &b, 1, MSG_PEEK);
mode = 0;
if(!ioctlsocket(netconn->socketFD, FIONBIO, &mode))
return FALSE;
return len == 1 || (len == -1 && errno == WSAEWOULDBLOCK);
#else
FIXME("not supported on this platform\n");
return TRUE;
#endif
}
LPCVOID NETCON_GetCert(netconn_t *connection)
{
#ifdef SONAME_LIBSSL
......
......@@ -386,17 +386,8 @@ static void InternetReadFile_test(int flags, const test_data_t *test)
{
SET_EXPECT(INTERNET_STATUS_RESOLVING_NAME);
SET_EXPECT(INTERNET_STATUS_NAME_RESOLVED);
SET_WINE_ALLOW(INTERNET_STATUS_RESOLVING_NAME);
SET_WINE_ALLOW(INTERNET_STATUS_NAME_RESOLVED);
}
else
{
SET_WINE_ALLOW2(INTERNET_STATUS_RESOLVING_NAME,2);
SET_WINE_ALLOW2(INTERNET_STATUS_NAME_RESOLVED,2);
}
SET_WINE_ALLOW(INTERNET_STATUS_CONNECTING_TO_SERVER);
SET_EXPECT(INTERNET_STATUS_CONNECTING_TO_SERVER);
SET_WINE_ALLOW(INTERNET_STATUS_CONNECTED_TO_SERVER);
SET_EXPECT(INTERNET_STATUS_CONNECTED_TO_SERVER);
SET_EXPECT2(INTERNET_STATUS_SENDING_REQUEST, (test->flags & TESTF_REDIRECT) ? 2 : 1);
SET_EXPECT2(INTERNET_STATUS_REQUEST_SENT, (test->flags & TESTF_REDIRECT) ? 2 : 1);
......@@ -461,7 +452,7 @@ static void InternetReadFile_test(int flags, const test_data_t *test)
CLEAR_NOTIFIED(INTERNET_STATUS_NAME_RESOLVED);
}
}
else todo_wine
else
{
CHECK_NOT_NOTIFIED(INTERNET_STATUS_RESOLVING_NAME);
CHECK_NOT_NOTIFIED(INTERNET_STATUS_NAME_RESOLVED);
......@@ -582,8 +573,6 @@ abort:
trace("aborting\n");
SET_EXPECT2(INTERNET_STATUS_HANDLE_CLOSING, (hor != 0x0) + (hic != 0x0));
if (hor != 0x0) {
SET_WINE_ALLOW(INTERNET_STATUS_CLOSING_CONNECTION);
SET_WINE_ALLOW(INTERNET_STATUS_CONNECTION_CLOSED);
SetLastError(0xdeadbeef);
trace("closing\n");
res = InternetCloseHandle(hor);
......@@ -608,7 +597,7 @@ abort:
Sleep(100);
}
CHECK_NOTIFIED2(INTERNET_STATUS_HANDLE_CLOSING, (hor != 0x0) + (hic != 0x0));
if (hor != 0x0) todo_wine
if (hor != 0x0)
{
CHECK_NOT_NOTIFIED(INTERNET_STATUS_CLOSING_CONNECTION);
CHECK_NOT_NOTIFIED(INTERNET_STATUS_CONNECTION_CLOSED);
......@@ -791,17 +780,8 @@ static void InternetReadFileExA_test(int flags)
{
SET_EXPECT(INTERNET_STATUS_RESOLVING_NAME);
SET_EXPECT(INTERNET_STATUS_NAME_RESOLVED);
SET_WINE_ALLOW(INTERNET_STATUS_RESOLVING_NAME);
SET_WINE_ALLOW(INTERNET_STATUS_NAME_RESOLVED);
}
else
{
SET_WINE_ALLOW2(INTERNET_STATUS_RESOLVING_NAME,2);
SET_WINE_ALLOW2(INTERNET_STATUS_NAME_RESOLVED,2);
}
SET_WINE_ALLOW(INTERNET_STATUS_CONNECTING_TO_SERVER);
SET_EXPECT(INTERNET_STATUS_CONNECTING_TO_SERVER);
SET_WINE_ALLOW(INTERNET_STATUS_CONNECTED_TO_SERVER);
SET_EXPECT(INTERNET_STATUS_CONNECTED_TO_SERVER);
SET_EXPECT2(INTERNET_STATUS_SENDING_REQUEST, 2);
SET_EXPECT2(INTERNET_STATUS_REQUEST_SENT, 2);
......@@ -836,7 +816,7 @@ static void InternetReadFileExA_test(int flags)
CHECK_NOTIFIED(INTERNET_STATUS_RESOLVING_NAME);
CHECK_NOTIFIED(INTERNET_STATUS_NAME_RESOLVED);
}
else todo_wine
else
{
CHECK_NOT_NOTIFIED(INTERNET_STATUS_RESOLVING_NAME);
CHECK_NOT_NOTIFIED(INTERNET_STATUS_NAME_RESOLVED);
......@@ -975,8 +955,6 @@ static void InternetReadFileExA_test(int flags)
abort:
SET_EXPECT2(INTERNET_STATUS_HANDLE_CLOSING, (hor != 0x0) + (hic != 0x0));
if (hor) {
SET_WINE_ALLOW(INTERNET_STATUS_CLOSING_CONNECTION);
SET_WINE_ALLOW(INTERNET_STATUS_CONNECTION_CLOSED);
rc = InternetCloseHandle(hor);
ok ((rc != 0), "InternetCloseHandle of handle opened by HttpOpenRequestA failed\n");
rc = InternetCloseHandle(hor);
......@@ -2640,7 +2618,7 @@ static void test_url_caching(int port, int *num_retrievals)
r = HttpSendRequest(hr, NULL, 0, NULL, 0);
ok(r, "HttpSendRequest failed\n");
ok(*num_retrievals == 1, "expected 1 retrievals\n");
ok(*num_retrievals == 1, "expected 1 retrievals, got %d\n", *num_retrievals);
count = 0;
memset(buffer, 0, sizeof buffer);
......@@ -3406,7 +3384,7 @@ START_TEST(http)
pInternetSetStatusCallbackA = (void*)GetProcAddress(hdll, "InternetSetStatusCallbackA");
init_status_tests();
if(0)test_InternetCloseHandle();
test_InternetCloseHandle();
InternetReadFile_test(INTERNET_FLAG_ASYNC, &test_data[0]);
InternetReadFile_test(INTERNET_FLAG_ASYNC, &test_data[1]);
InternetReadFile_test(0, &test_data[1]);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment