[2/4] winhttp: Execute asynchronous requests in a separate thread.
Hans Leidekker
hans at codeweavers.com
Tue Aug 2 02:23:20 CDT 2011
Fixes http://bugs.winehq.org/show_bug.cgi?id=27927
---
dlls/winhttp/request.c | 539 +++++++++++++++++++++++++++---------------------
1 files changed, 300 insertions(+), 239 deletions(-)
diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c
index 8753f5b..633d8e8 100644
--- a/dlls/winhttp/request.c
+++ b/dlls/winhttp/request.c
@@ -2147,11 +2147,12 @@ BOOL WINAPI WinHttpWriteData( HINTERNET hrequest, LPCVOID buffer, DWORD to_write
enum request_state
{
- REQUEST_STATE_INVALID,
+ REQUEST_STATE_UNINITIALIZED,
+ REQUEST_STATE_INITIALIZED,
+ REQUEST_STATE_CANCELLED,
REQUEST_STATE_OPEN,
REQUEST_STATE_SENT,
- REQUEST_STATE_RESPONSE_RECEIVED,
- REQUEST_STATE_BODY_RECEIVED
+ REQUEST_STATE_RESPONSE_RECEIVED
};
struct winhttp_request
@@ -2163,7 +2164,9 @@ struct winhttp_request
HINTERNET hsession;
HINTERNET hconnect;
HINTERNET hrequest;
+ VARIANT data;
WCHAR *verb;
+ HANDLE thread;
HANDLE wait;
HANDLE cancel;
char *buffer;
@@ -2190,6 +2193,30 @@ static ULONG WINAPI winhttp_request_AddRef(
return InterlockedIncrement( &request->refs );
}
+/* critical section must be held */
+static void cancel_request( struct winhttp_request *request )
+{
+ if (request->state <= REQUEST_STATE_CANCELLED) return;
+ if (request->thread) SetEvent( request->cancel );
+ request->state = REQUEST_STATE_CANCELLED;
+}
+
+/* critical section must be held */
+static void free_request( struct winhttp_request *request )
+{
+ if (request->state < REQUEST_STATE_INITIALIZED) return;
+ WinHttpCloseHandle( request->hrequest );
+ WinHttpCloseHandle( request->hconnect );
+ WinHttpCloseHandle( request->hsession );
+ CloseHandle( request->thread );
+ CloseHandle( request->wait );
+ CloseHandle( request->cancel );
+ heap_free( (WCHAR *)request->proxy.lpszProxy );
+ heap_free( (WCHAR *)request->proxy.lpszProxyBypass );
+ heap_free( request->buffer );
+ heap_free( request->verb );
+}
+
static ULONG WINAPI winhttp_request_Release(
IWinHttpRequest *iface )
{
@@ -2198,16 +2225,12 @@ static ULONG WINAPI winhttp_request_Release(
if (!refs)
{
TRACE("destroying %p\n", request);
- WinHttpCloseHandle( request->hrequest );
- WinHttpCloseHandle( request->hconnect );
- WinHttpCloseHandle( request->hsession );
+
+ EnterCriticalSection( &request->cs );
+ cancel_request( request );
+ free_request( request );
+ LeaveCriticalSection( &request->cs );
DeleteCriticalSection( &request->cs );
- CloseHandle( request->wait );
- CloseHandle( request->cancel );
- heap_free( (WCHAR *)request->proxy.lpszProxy );
- heap_free( (WCHAR *)request->proxy.lpszProxyBypass );
- heap_free( request->buffer );
- heap_free( request->verb );
heap_free( request );
}
return refs;
@@ -2441,6 +2464,31 @@ done:
return HRESULT_FROM_WIN32( err );
}
+static void initialize_request( struct winhttp_request *request )
+{
+ request->hrequest = NULL;
+ request->hconnect = NULL;
+ request->hsession = NULL;
+ request->thread = NULL;
+ request->wait = NULL;
+ request->cancel = NULL;
+ request->buffer = NULL;
+ request->verb = NULL;
+ request->offset = 0;
+ request->bytes_available = 0;
+ request->bytes_read = 0;
+ request->error = ERROR_SUCCESS;
+ request->proxy.dwAccessType = WINHTTP_ACCESS_TYPE_DEFAULT_PROXY;
+ request->proxy.lpszProxy = NULL;
+ request->proxy.lpszProxyBypass = NULL;
+ request->resolve_timeout = 0;
+ request->connect_timeout = 60000;
+ request->send_timeout = 30000;
+ request->receive_timeout = 30000;
+ VariantInit( &request->data );
+ request->state = REQUEST_STATE_INITIALIZED;
+}
+
static HRESULT WINAPI winhttp_request_Open(
IWinHttpRequest *iface,
BSTR method,
@@ -2457,8 +2505,8 @@ static HRESULT WINAPI winhttp_request_Open(
struct winhttp_request *request = impl_from_IWinHttpRequest( iface );
HINTERNET hsession = NULL, hconnect = NULL, hrequest;
URL_COMPONENTS uc;
- WCHAR *hostname, *path;
- DWORD err, len, flags = 0, request_flags = 0, disable_flags;
+ WCHAR *hostname, *path = NULL, *verb = NULL;
+ DWORD err = ERROR_OUTOFMEMORY, len, flags = 0, request_flags = 0, disable_flags;
TRACE("%p, %s, %s, %s\n", request, debugstr_w(method), debugstr_w(url),
debugstr_variant(&async));
@@ -2474,23 +2522,21 @@ static HRESULT WINAPI winhttp_request_Open(
if (!WinHttpCrackUrl( url, 0, 0, &uc )) return HRESULT_FROM_WIN32( get_last_error() );
EnterCriticalSection( &request->cs );
- if (!(request->verb = strdupW( method )))
+ if (request->state != REQUEST_STATE_INITIALIZED)
{
- LeaveCriticalSection( &request->cs );
- return E_OUTOFMEMORY;
+ cancel_request( request );
+ free_request( request );
+ initialize_request( request );
}
- if (!(hostname = heap_alloc( (uc.dwHostNameLength + 1) * sizeof(WCHAR) ))) return E_OUTOFMEMORY;
+ if (!(hostname = heap_alloc( (uc.dwHostNameLength + 1) * sizeof(WCHAR) ))) goto error;
memcpy( hostname, uc.lpszHostName, uc.dwHostNameLength * sizeof(WCHAR) );
hostname[uc.dwHostNameLength] = 0;
- if (!(path = heap_alloc( (uc.dwUrlPathLength + uc.dwExtraInfoLength + 1) * sizeof(WCHAR) )))
- {
- heap_free( hostname );
- LeaveCriticalSection( &request->cs );
- return E_OUTOFMEMORY;
- }
+
+ if (!(path = heap_alloc( (uc.dwUrlPathLength + uc.dwExtraInfoLength + 1) * sizeof(WCHAR) ))) goto error;
memcpy( path, uc.lpszUrlPath, (uc.dwUrlPathLength + uc.dwExtraInfoLength) * sizeof(WCHAR) );
path[uc.dwUrlPathLength + uc.dwExtraInfoLength] = 0;
+ if (!(verb = strdupW( method ))) goto error;
if (V_BOOL( &async ) == VARIANT_TRUE) flags |= WINHTTP_FLAG_ASYNC;
if (!(hsession = WinHttpOpen( user_agentW, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, NULL, NULL, flags )))
{
@@ -2528,6 +2574,7 @@ static HRESULT WINAPI winhttp_request_Open(
request->hsession = hsession;
request->hconnect = hconnect;
request->hrequest = hrequest;
+ request->verb = verb;
heap_free( hostname );
heap_free( path );
LeaveCriticalSection( &request->cs );
@@ -2538,6 +2585,7 @@ error:
WinHttpCloseHandle( hsession );
heap_free( hostname );
heap_free( path );
+ heap_free( verb );
LeaveCriticalSection( &request->cs );
return HRESULT_FROM_WIN32( err );
}
@@ -2587,76 +2635,6 @@ done:
return HRESULT_FROM_WIN32( err );
}
-static DWORD wait_for_completion( struct winhttp_request *request, DWORD timeout )
-{
- HANDLE handles[2];
-
- if (!request->wait)
- {
- request->error = ERROR_SUCCESS;
- return ERROR_SUCCESS;
- }
- handles[0] = request->wait;
- handles[1] = request->cancel;
- switch (WaitForMultipleObjects( 2, handles, FALSE, timeout ))
- {
- case WAIT_OBJECT_0:
- break;
- case WAIT_OBJECT_0 + 1:
- request->error = ERROR_CANCELLED;
- break;
- case WAIT_TIMEOUT:
- request->error = ERROR_TIMEOUT;
- break;
- default: break;
- }
- return request->error;
-}
-
-static void CALLBACK wait_status_callback( HINTERNET handle, DWORD_PTR context, DWORD status, LPVOID buffer, DWORD size )
-{
- struct winhttp_request *request = (struct winhttp_request *)context;
-
- switch (status)
- {
- case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE:
- request->bytes_available = *(DWORD *)buffer;
- request->error = ERROR_SUCCESS;
- break;
- case WINHTTP_CALLBACK_STATUS_READ_COMPLETE:
- request->bytes_read = size;
- request->error = ERROR_SUCCESS;
- break;
- case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR:
- {
- WINHTTP_ASYNC_RESULT *result = (WINHTTP_ASYNC_RESULT *)buffer;
- request->error = result->dwError;
- break;
- }
- default: break;
- }
- SetEvent( request->wait );
-}
-
-static void wait_set_status_callback( struct winhttp_request *request, DWORD status )
-{
- if (!request->wait) return;
- status |= WINHTTP_CALLBACK_STATUS_REQUEST_ERROR;
- WinHttpSetStatusCallback( request->hrequest, wait_status_callback, status, 0 );
-}
-
-static DWORD request_wait_for_response( struct winhttp_request *request, DWORD timeout )
-{
- if (request->state >= REQUEST_STATE_RESPONSE_RECEIVED) return ERROR_SUCCESS;
-
- wait_set_status_callback( request, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE );
- if (!WinHttpReceiveResponse( request->hrequest, NULL ))
- {
- return get_last_error();
- }
- return wait_for_completion( request, timeout );
-}
-
static HRESULT WINAPI winhttp_request_GetResponseHeader(
IWinHttpRequest *iface,
BSTR header,
@@ -2678,9 +2656,6 @@ static HRESULT WINAPI winhttp_request_GetResponseHeader(
err = ERROR_INVALID_PARAMETER;
goto done;
}
- if ((err = request_wait_for_response( request, INFINITE ))) goto done;
- request->state = REQUEST_STATE_RESPONSE_RECEIVED;
-
size = 0;
if (!WinHttpQueryHeaders( request->hrequest, WINHTTP_QUERY_CUSTOM, header, NULL, &size, NULL ))
{
@@ -2720,9 +2695,6 @@ static HRESULT WINAPI winhttp_request_GetAllResponseHeaders(
err = ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND;
goto done;
}
- if ((err = request_wait_for_response( request, INFINITE ))) goto done;
- request->state = REQUEST_STATE_RESPONSE_RECEIVED;
-
size = 0;
if (!WinHttpQueryHeaders( request->hrequest, WINHTTP_QUERY_RAW_HEADERS_CRLF, NULL, NULL, &size, NULL ))
{
@@ -2745,68 +2717,212 @@ done:
return HRESULT_FROM_WIN32( err );
}
-static HRESULT WINAPI winhttp_request_Send(
- IWinHttpRequest *iface,
- VARIANT body )
+static void CALLBACK wait_status_callback( HINTERNET handle, DWORD_PTR context, DWORD status, LPVOID buffer, DWORD size )
+{
+ struct winhttp_request *request = (struct winhttp_request *)context;
+
+ switch (status)
+ {
+ case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE:
+ request->bytes_available = *(DWORD *)buffer;
+ request->error = ERROR_SUCCESS;
+ break;
+ case WINHTTP_CALLBACK_STATUS_READ_COMPLETE:
+ request->bytes_read = size;
+ request->error = ERROR_SUCCESS;
+ break;
+ case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR:
+ {
+ WINHTTP_ASYNC_RESULT *result = (WINHTTP_ASYNC_RESULT *)buffer;
+ request->error = result->dwError;
+ break;
+ }
+ default: break;
+ }
+ SetEvent( request->wait );
+}
+
+static void wait_set_status_callback( struct winhttp_request *request, DWORD status )
+{
+ if (!request->wait) return;
+ status |= WINHTTP_CALLBACK_STATUS_REQUEST_ERROR;
+ WinHttpSetStatusCallback( request->hrequest, wait_status_callback, status, 0 );
+}
+
+static DWORD wait_for_completion( struct winhttp_request *request )
+{
+ HANDLE handles[2];
+
+ if (!request->wait)
+ {
+ request->error = ERROR_SUCCESS;
+ return ERROR_SUCCESS;
+ }
+ handles[0] = request->wait;
+ handles[1] = request->cancel;
+ switch (WaitForMultipleObjects( 2, handles, FALSE, INFINITE ))
+ {
+ case WAIT_OBJECT_0:
+ break;
+ case WAIT_OBJECT_0 + 1:
+ request->error = ERROR_CANCELLED;
+ break;
+ default:
+ request->error = get_last_error();
+ break;
+ }
+ return request->error;
+}
+
+static HRESULT request_receive( struct winhttp_request *request )
+{
+ DWORD err, size, total_bytes_read, buflen = 4096;
+
+ wait_set_status_callback( request, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE );
+ if (!WinHttpReceiveResponse( request->hrequest, NULL ))
+ {
+ return HRESULT_FROM_WIN32( get_last_error() );
+ }
+ if ((err = wait_for_completion( request ))) return HRESULT_FROM_WIN32( err );
+
+ if (!(request->buffer = heap_alloc( buflen ))) return E_OUTOFMEMORY;
+ request->buffer[0] = 0;
+ size = total_bytes_read = 0;
+ do
+ {
+ wait_set_status_callback( request, WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE );
+ if (!WinHttpQueryDataAvailable( request->hrequest, &request->bytes_available ))
+ {
+ err = get_last_error();
+ goto error;
+ }
+ if ((err = wait_for_completion( request ))) goto error;
+ if (!request->bytes_available) break;
+ size += request->bytes_available;
+ if (buflen < size)
+ {
+ char *tmp;
+ while (buflen < size) buflen *= 2;
+ if (!(tmp = heap_realloc( request->buffer, buflen )))
+ {
+ err = ERROR_OUTOFMEMORY;
+ goto error;
+ }
+ request->buffer = tmp;
+ }
+ wait_set_status_callback( request, WINHTTP_CALLBACK_STATUS_READ_COMPLETE );
+ if (!WinHttpReadData( request->hrequest, request->buffer + request->offset,
+ request->bytes_available, &request->bytes_read ))
+ {
+ err = get_last_error();
+ goto error;
+ }
+ if ((err = wait_for_completion( request ))) goto error;
+ total_bytes_read += request->bytes_read;
+ request->offset += request->bytes_read;
+ } while (request->bytes_read);
+
+ request->state = REQUEST_STATE_RESPONSE_RECEIVED;
+ return S_OK;
+
+error:
+ heap_free( request->buffer );
+ request->buffer = NULL;
+ return HRESULT_FROM_WIN32( err );
+}
+
+static HRESULT request_send( struct winhttp_request *request )
{
- struct winhttp_request *request = impl_from_IWinHttpRequest( iface );
SAFEARRAY *sa = NULL;
- VARIANT array;
+ VARIANT data;
char *ptr = NULL;
LONG size = 0;
HRESULT hr;
BOOL ret;
- DWORD err = ERROR_SUCCESS;
-
- TRACE("%p, %s\n", request, debugstr_variant(&body));
-
- EnterCriticalSection( &request->cs );
- if (request->state < REQUEST_STATE_OPEN)
- {
- err = ERROR_WINHTTP_CANNOT_CALL_BEFORE_OPEN;
- goto done;
- }
- if (request->state >= REQUEST_STATE_SENT) goto done;
+ DWORD err;
if (!WinHttpSetOption( request->hrequest, WINHTTP_OPTION_PROXY, &request->proxy, sizeof(request->proxy) ))
{
- err = get_last_error();
- goto done;
+ return HRESULT_FROM_WIN32( get_last_error() );
}
- if (!WinHttpSetTimeouts( request->hrequest, request->resolve_timeout, request->connect_timeout,
- request->send_timeout, request->receive_timeout ))
+ if (!WinHttpSetTimeouts( request->hrequest,
+ request->resolve_timeout,
+ request->connect_timeout,
+ request->send_timeout,
+ request->receive_timeout ))
{
- err = get_last_error();
- goto done;
+ return HRESULT_FROM_WIN32( get_last_error() );
}
- VariantInit( &array );
- if (strcmpW( request->verb, getW ) && VariantChangeType( &array, &body, 0, VT_ARRAY|VT_UI1 ) == S_OK)
+ VariantInit( &data );
+ if (strcmpW( request->verb, getW ) && VariantChangeType( &data, &request->data, 0, VT_ARRAY|VT_UI1 ) == S_OK)
{
- SAFEARRAY *sa = V_ARRAY( &array );
- if (((hr = SafeArrayAccessData( sa, (void **)&ptr )) != S_OK) ||
- (hr = SafeArrayGetUBound( sa, 1, &size ) != S_OK))
+ SAFEARRAY *sa = V_ARRAY( &data );
+ if ((hr = SafeArrayAccessData( sa, (void **)&ptr )) != S_OK) return hr;
+ if ((hr = SafeArrayGetUBound( sa, 1, &size ) != S_OK))
{
- LeaveCriticalSection( &request->cs );
+ SafeArrayUnaccessData( sa );
return hr;
}
size++;
}
wait_set_status_callback( request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT );
- ret = WinHttpSendRequest( request->hrequest, NULL, 0, ptr, size, size, 0 );
- err = get_last_error();
- if (sa && (hr = SafeArrayUnaccessData( sa )) != S_OK)
+ if (!(ret = WinHttpSendRequest( request->hrequest, NULL, 0, ptr, size, size, 0 )))
+ {
+ err = get_last_error();
+ }
+ if (sa && (hr = SafeArrayUnaccessData( sa )) != S_OK) return hr;
+ if (!ret) return HRESULT_FROM_WIN32( err );
+ if ((err = wait_for_completion( request ))) return HRESULT_FROM_WIN32( err );
+
+ request->state = REQUEST_STATE_SENT;
+ return S_OK;
+}
+
+static HRESULT request_send_and_receive( struct winhttp_request *request )
+{
+ HRESULT hr = request_send( request );
+ if (hr == S_OK) hr = request_receive( request );
+ return hr;
+}
+
+static DWORD CALLBACK send_and_receive_proc( void *arg )
+{
+ struct winhttp_request *request = (struct winhttp_request *)arg;
+ return request_send_and_receive( request );
+}
+
+static HRESULT WINAPI winhttp_request_Send(
+ IWinHttpRequest *iface,
+ VARIANT body )
+{
+ struct winhttp_request *request = impl_from_IWinHttpRequest( iface );
+ HRESULT hr = S_OK;
+
+ TRACE("%p, %s\n", request, debugstr_variant(&body));
+
+ EnterCriticalSection( &request->cs );
+ if (request->state < REQUEST_STATE_OPEN)
{
LeaveCriticalSection( &request->cs );
- return hr;
+ return HRESULT_FROM_WIN32( ERROR_WINHTTP_CANNOT_CALL_BEFORE_OPEN );
}
- if (!ret) goto done;
- if (!(err = wait_for_completion( request, INFINITE )))
+ if (request->state >= REQUEST_STATE_SENT)
{
- request->state = REQUEST_STATE_SENT;
+ LeaveCriticalSection( &request->cs );
+ return S_OK;
}
-done:
+ if (request->wait) /* async request */
+ {
+ request->data = body;
+ if (!(request->thread = CreateThread( NULL, 0, send_and_receive_proc, request, 0, NULL )))
+ {
+ LeaveCriticalSection( &request->cs );
+ return HRESULT_FROM_WIN32( get_last_error() );
+ }
+ }
+ else hr = request_send_and_receive( request );
LeaveCriticalSection( &request->cs );
- return HRESULT_FROM_WIN32( err );
+ return hr;
}
static HRESULT WINAPI winhttp_request_get_Status(
@@ -2826,9 +2942,6 @@ static HRESULT WINAPI winhttp_request_get_Status(
err = ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND;
goto done;
}
- if ((err = request_wait_for_response( request, INFINITE ))) goto done;
- request->state = REQUEST_STATE_RESPONSE_RECEIVED;
-
flags = WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER;
if (!WinHttpQueryHeaders( request->hrequest, flags, NULL, &status_code, &len, &index ))
{
@@ -2858,9 +2971,6 @@ static HRESULT WINAPI winhttp_request_get_StatusText(
err = ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND;
goto done;
}
- if ((err = request_wait_for_response( request, INFINITE ))) goto done;
- request->state = REQUEST_STATE_RESPONSE_RECEIVED;
-
if (!WinHttpQueryHeaders( request->hrequest, WINHTTP_QUERY_STATUS_TEXT, NULL, NULL, &len, &index ))
{
err = get_last_error();
@@ -2883,61 +2993,6 @@ done:
return HRESULT_FROM_WIN32( err );
}
-static DWORD request_read_body( struct winhttp_request *request, DWORD timeout )
-{
- DWORD err, size, total_bytes_read, buflen = 4096;
-
- if (request->state >= REQUEST_STATE_BODY_RECEIVED) return ERROR_SUCCESS;
- if ((err = request_wait_for_response( request, timeout ))) return err;
- request->state = REQUEST_STATE_RESPONSE_RECEIVED;
-
- if (!(request->buffer = heap_alloc( buflen ))) return E_OUTOFMEMORY;
- request->buffer[0] = 0;
- size = total_bytes_read = 0;
- do
- {
- wait_set_status_callback( request, WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE );
- if (!WinHttpQueryDataAvailable( request->hrequest, &request->bytes_available ))
- {
- err = get_last_error();
- goto error;
- }
- if ((err = wait_for_completion( request, timeout ))) goto error;
- if (!request->bytes_available) break;
- size += request->bytes_available;
- if (buflen < size)
- {
- char *tmp;
- while (buflen < size) buflen *= 2;
- if (!(tmp = heap_realloc( request->buffer, buflen )))
- {
- err = ERROR_OUTOFMEMORY;
- goto error;
- }
- request->buffer = tmp;
- }
- wait_set_status_callback( request, WINHTTP_CALLBACK_STATUS_READ_COMPLETE );
- if (!WinHttpReadData( request->hrequest, request->buffer + request->offset,
- request->bytes_available, &request->bytes_read ))
- {
- err = get_last_error();
- goto error;
- }
- if ((err = wait_for_completion( request, timeout ))) goto error;
- total_bytes_read += request->bytes_read;
- request->offset += request->bytes_read;
- } while (request->bytes_read);
-
- request->state = REQUEST_STATE_BODY_RECEIVED;
- return ERROR_SUCCESS;
-
-error:
- heap_free( request->buffer );
- request->buffer = NULL;
- TRACE("error %u\n", err);
- return err;
-}
-
static DWORD request_get_codepage( struct winhttp_request *request, UINT *codepage )
{
static const WCHAR utf8W[] = {'u','t','f','-','8',0};
@@ -2988,9 +3043,7 @@ static HRESULT WINAPI winhttp_request_get_ResponseText(
err = ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND;
goto done;
}
- if ((err = request_read_body( request, INFINITE ))) goto done;
if ((err = request_get_codepage( request, &codepage ))) goto done;
-
len = MultiByteToWideChar( codepage, 0, request->buffer, request->offset, NULL, 0 );
if (!(*body = SysAllocStringLen( NULL, len )))
{
@@ -3020,8 +3073,6 @@ static HRESULT WINAPI winhttp_request_get_ResponseBody(
if (!body) return E_INVALIDARG;
EnterCriticalSection( &request->cs );
- if ((err = request_read_body( request, INFINITE ))) goto done;
-
if (!(sa = SafeArrayCreateVector( VT_UI1, 0, request->offset )))
{
err = ERROR_OUTOFMEMORY;
@@ -3074,6 +3125,39 @@ static HRESULT WINAPI winhttp_request_put_Option(
return E_NOTIMPL;
}
+/* critical section must be held */
+static DWORD wait_for_response( struct winhttp_request *request, DWORD timeout )
+{
+ HANDLE thread = request->thread;
+ DWORD err, ret;
+
+ LeaveCriticalSection( &request->cs );
+ while ((err = MsgWaitForMultipleObjects( 1, &thread, FALSE, timeout, QS_ALLINPUT )) == WAIT_OBJECT_0 + 1)
+ {
+ MSG msg;
+ while (PeekMessageW( &msg, NULL, 0, 0, PM_REMOVE ))
+ {
+ TranslateMessage( &msg );
+ DispatchMessageW( &msg );
+ }
+ }
+ switch (err)
+ {
+ case WAIT_OBJECT_0:
+ ret = ERROR_SUCCESS;
+ break;
+ case WAIT_TIMEOUT:
+ ret = ERROR_TIMEOUT;
+ break;
+ case WAIT_FAILED:
+ default:
+ ret = get_last_error();
+ break;
+ }
+ EnterCriticalSection( &request->cs );
+ return ret;
+}
+
static HRESULT WINAPI winhttp_request_WaitForResponse(
IWinHttpRequest *iface,
VARIANT timeout,
@@ -3085,15 +3169,25 @@ static HRESULT WINAPI winhttp_request_WaitForResponse(
TRACE("%p, %s, %p\n", request, debugstr_variant(&timeout), succeeded);
EnterCriticalSection( &request->cs );
- switch ((err = request_wait_for_response( request, msecs )))
+ if (!request->thread)
+ {
+ LeaveCriticalSection( &request->cs );
+ return S_OK;
+ }
+ if (request->state >= REQUEST_STATE_RESPONSE_RECEIVED)
+ {
+ LeaveCriticalSection( &request->cs );
+ return S_OK;
+ }
+ switch ((err = wait_for_response( request, msecs )))
{
case ERROR_TIMEOUT:
if (succeeded) *succeeded = VARIANT_FALSE;
+ err = ERROR_SUCCESS;
break;
case ERROR_SUCCESS:
if (succeeded) *succeeded = VARIANT_TRUE;
- request->state = REQUEST_STATE_RESPONSE_RECEIVED;
break;
default: break;
@@ -3102,29 +3196,6 @@ static HRESULT WINAPI winhttp_request_WaitForResponse(
return HRESULT_FROM_WIN32( err );
}
-static void initialize_request( struct winhttp_request *request )
-{
- request->state = REQUEST_STATE_INVALID;
- request->hrequest = NULL;
- request->hconnect = NULL;
- request->hsession = NULL;
- request->wait = NULL;
- request->cancel = NULL;
- request->buffer = NULL;
- request->verb = NULL;
- request->offset = 0;
- request->bytes_available = 0;
- request->bytes_read = 0;
- request->error = ERROR_SUCCESS;
- request->proxy.dwAccessType = WINHTTP_ACCESS_TYPE_DEFAULT_PROXY;
- request->proxy.lpszProxy = NULL;
- request->proxy.lpszProxyBypass = NULL;
- request->resolve_timeout = 0;
- request->connect_timeout = 60000;
- request->send_timeout = 30000;
- request->receive_timeout = 30000;
-}
-
static HRESULT WINAPI winhttp_request_Abort(
IWinHttpRequest *iface )
{
@@ -3132,18 +3203,8 @@ static HRESULT WINAPI winhttp_request_Abort(
TRACE("%p\n", request);
- SetEvent( request->cancel );
EnterCriticalSection( &request->cs );
- WinHttpCloseHandle( request->hrequest );
- WinHttpCloseHandle( request->hconnect );
- WinHttpCloseHandle( request->hsession );
- CloseHandle( request->wait );
- CloseHandle( request->cancel );
- heap_free( (WCHAR *)request->proxy.lpszProxy );
- heap_free( (WCHAR *)request->proxy.lpszProxyBypass );
- heap_free( request->buffer );
- heap_free( request->verb );
- initialize_request( request );
+ cancel_request( request );
LeaveCriticalSection( &request->cs );
return S_OK;
}
@@ -3223,8 +3284,8 @@ HRESULT WinHttpRequest_create( IUnknown *unknown, void **obj )
if (!(request = heap_alloc( sizeof(*request) ))) return E_OUTOFMEMORY;
request->IWinHttpRequest_iface.lpVtbl = &winhttp_request_vtbl;
request->refs = 1;
+ request->state = REQUEST_STATE_UNINITIALIZED;
InitializeCriticalSection( &request->cs );
- initialize_request( request );
*obj = &request->IWinHttpRequest_iface;
TRACE("returning iface %p\n", *obj);
--
1.7.4.1
More information about the wine-patches
mailing list