winhttp: Start sending async completion notifications. Add corresponding tests.
This commit is contained in:
parent
78c79ba349
commit
3d8a9564cd
|
@ -867,6 +867,17 @@ BOOL WINAPI WinHttpSendRequest( HINTERNET hrequest, LPCWSTR headers, DWORD heade
|
|||
|
||||
ret = send_request( request, headers, headers_len, optional, optional_len, total_len, context );
|
||||
|
||||
if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC)
|
||||
{
|
||||
if (ret) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE, NULL, 0 );
|
||||
else
|
||||
{
|
||||
WINHTTP_ASYNC_RESULT async;
|
||||
async.dwResult = API_SEND_REQUEST;
|
||||
async.dwError = get_last_error();
|
||||
send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &async, sizeof(async) );
|
||||
}
|
||||
}
|
||||
release_object( &request->hdr );
|
||||
return ret;
|
||||
}
|
||||
|
@ -886,7 +897,7 @@ static void clear_response_headers( request_t *request )
|
|||
}
|
||||
|
||||
#define MAX_REPLY_LEN 1460
|
||||
#define INITIAL_HEADER_BUFFER_SIZE 512
|
||||
#define INITIAL_HEADER_BUFFER_LEN 512
|
||||
|
||||
static BOOL receive_response( request_t *request, BOOL clear )
|
||||
{
|
||||
|
@ -946,7 +957,7 @@ static BOOL receive_response( request_t *request, BOOL clear )
|
|||
heap_free( request->status_text );
|
||||
request->status_text = status_textW;
|
||||
|
||||
len = max( buflen + crlf_len, INITIAL_HEADER_BUFFER_SIZE );
|
||||
len = max( buflen + crlf_len, INITIAL_HEADER_BUFFER_LEN );
|
||||
if (!(raw_headers = heap_alloc( len * sizeof(WCHAR) ))) return FALSE;
|
||||
MultiByteToWideChar( CP_ACP, 0, buffer, buflen, raw_headers, buflen );
|
||||
memcpy( raw_headers + buflen - 1, crlf, sizeof(crlf) );
|
||||
|
@ -1139,6 +1150,17 @@ BOOL WINAPI WinHttpReceiveResponse( HINTERNET hrequest, LPVOID reserved )
|
|||
ret = send_request( request, NULL, 0, NULL, 0, 0, 0 );
|
||||
}
|
||||
|
||||
if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC)
|
||||
{
|
||||
if (ret) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NULL, 0 );
|
||||
else
|
||||
{
|
||||
WINHTTP_ASYNC_RESULT async;
|
||||
async.dwResult = API_RECEIVE_RESPONSE;
|
||||
async.dwError = get_last_error();
|
||||
send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &async, sizeof(async) );
|
||||
}
|
||||
}
|
||||
release_object( &request->hdr );
|
||||
return ret;
|
||||
}
|
||||
|
@ -1254,7 +1276,7 @@ BOOL WINAPI WinHttpReadData( HINTERNET hrequest, LPVOID buffer, DWORD to_read, L
|
|||
{
|
||||
static const WCHAR chunked[] = {'c','h','u','n','k','e','d',0};
|
||||
|
||||
BOOL ret;
|
||||
BOOL ret, async;
|
||||
request_t *request;
|
||||
WCHAR encoding[20];
|
||||
DWORD num_bytes, buflen = sizeof(encoding);
|
||||
|
@ -1273,13 +1295,14 @@ BOOL WINAPI WinHttpReadData( HINTERNET hrequest, LPVOID buffer, DWORD to_read, L
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
async = request->connect->hdr.flags & WINHTTP_FLAG_ASYNC;
|
||||
if (query_headers( request, WINHTTP_QUERY_TRANSFER_ENCODING, NULL, encoding, &buflen, NULL ) &&
|
||||
!strcmpiW( encoding, chunked ))
|
||||
{
|
||||
ret = read_data_chunked( request, buffer, to_read, &num_bytes, request->hdr.flags & WINHTTP_FLAG_ASYNC );
|
||||
ret = read_data_chunked( request, buffer, to_read, &num_bytes, async );
|
||||
}
|
||||
else
|
||||
ret = read_data( request, buffer, to_read, &num_bytes, request->hdr.flags & WINHTTP_FLAG_ASYNC );
|
||||
ret = read_data( request, buffer, to_read, &num_bytes, async );
|
||||
|
||||
if (ret && read) *read = num_bytes;
|
||||
release_object( &request->hdr );
|
||||
|
|
|
@ -36,6 +36,12 @@ void set_last_error( DWORD error )
|
|||
SetLastError( error );
|
||||
}
|
||||
|
||||
DWORD get_last_error( void )
|
||||
{
|
||||
/* FIXME */
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
void send_callback( object_header_t *hdr, DWORD status, LPVOID info, DWORD buflen )
|
||||
{
|
||||
TRACE("%p, 0x%08x, %p, %u\n", hdr, status, info, buflen);
|
||||
|
|
|
@ -50,6 +50,7 @@ struct info
|
|||
const struct notification *test;
|
||||
unsigned int count;
|
||||
unsigned int index;
|
||||
HANDLE wait;
|
||||
};
|
||||
|
||||
static void CALLBACK check_notification( HINTERNET handle, DWORD_PTR context, DWORD status, LPVOID buffer, DWORD buflen )
|
||||
|
@ -75,6 +76,7 @@ static void CALLBACK check_notification( HINTERNET handle, DWORD_PTR context, DW
|
|||
ok(info->test[i].function == info->function, "expected function %u got %u\n", info->test[i].function, info->function);
|
||||
}
|
||||
info->index++;
|
||||
if (status & WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS) SetEvent( info->wait );
|
||||
}
|
||||
|
||||
static const struct notification cache_test[] =
|
||||
|
@ -108,11 +110,12 @@ static void test_connection_cache( void )
|
|||
info.test = cache_test;
|
||||
info.count = sizeof(cache_test) / sizeof(cache_test[0]);
|
||||
info.index = 0;
|
||||
info.wait = NULL;
|
||||
|
||||
ses = WinHttpOpen( user_agent, 0, NULL, NULL, 0 );
|
||||
ok(ses != NULL, "failed to open session %u\n", GetLastError());
|
||||
|
||||
WinHttpSetStatusCallback( ses, check_notification, WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS | WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0 );
|
||||
WinHttpSetStatusCallback( ses, check_notification, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0 );
|
||||
|
||||
ret = WinHttpSetOption( ses, WINHTTP_OPTION_CONTEXT_VALUE, &context, sizeof(struct info *) );
|
||||
ok(ret, "failed to set context value %u\n", GetLastError());
|
||||
|
@ -150,7 +153,7 @@ static void test_connection_cache( void )
|
|||
ses = WinHttpOpen( user_agent, 0, NULL, NULL, 0 );
|
||||
ok(ses != NULL, "failed to open session %u\n", GetLastError());
|
||||
|
||||
WinHttpSetStatusCallback( ses, check_notification, WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS | WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0 );
|
||||
WinHttpSetStatusCallback( ses, check_notification, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0 );
|
||||
|
||||
ret = WinHttpSetOption( ses, WINHTTP_OPTION_CONTEXT_VALUE, &context, sizeof(struct info *) );
|
||||
ok(ret, "failed to set context value %u\n", GetLastError());
|
||||
|
@ -225,11 +228,12 @@ static void test_redirect( void )
|
|||
info.test = redirect_test;
|
||||
info.count = sizeof(redirect_test) / sizeof(redirect_test[0]);
|
||||
info.index = 0;
|
||||
info.wait = NULL;
|
||||
|
||||
ses = WinHttpOpen( user_agent, 0, NULL, NULL, 0 );
|
||||
ok(ses != NULL, "failed to open session %u\n", GetLastError());
|
||||
|
||||
WinHttpSetStatusCallback( ses, check_notification, WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS | WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0 );
|
||||
WinHttpSetStatusCallback( ses, check_notification, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0 );
|
||||
|
||||
ret = WinHttpSetOption( ses, WINHTTP_OPTION_CONTEXT_VALUE, &context, sizeof(struct info *) );
|
||||
ok(ret, "failed to set context value %u\n", GetLastError());
|
||||
|
@ -260,8 +264,93 @@ static void test_redirect( void )
|
|||
WinHttpCloseHandle( ses );
|
||||
}
|
||||
|
||||
static const struct notification async_test[] =
|
||||
{
|
||||
{ winhttp_connect, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, 0 },
|
||||
{ winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, 0 },
|
||||
{ winhttp_send_request, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME, 0 },
|
||||
{ winhttp_send_request, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED, 0 },
|
||||
{ winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, 0 },
|
||||
{ winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, 0 },
|
||||
{ winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST, 0 },
|
||||
{ winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT, 0 },
|
||||
{ winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE, 0 },
|
||||
{ winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, 0 },
|
||||
{ winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, 0 },
|
||||
{ winhttp_receive_response, WINHTTP_CALLBACK_STATUS_REDIRECT, 0 },
|
||||
{ winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME, 0 },
|
||||
{ winhttp_receive_response, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED, 0 },
|
||||
{ winhttp_receive_response, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, 0 },
|
||||
{ winhttp_receive_response, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, 0 },
|
||||
{ winhttp_receive_response, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST, 0 },
|
||||
{ winhttp_receive_response, WINHTTP_CALLBACK_STATUS_REQUEST_SENT, 0 },
|
||||
{ winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, 0 },
|
||||
{ winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, 0 },
|
||||
{ winhttp_receive_response, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, 0 },
|
||||
{ winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION, 0 },
|
||||
{ winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED, 0 },
|
||||
{ winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, 0 },
|
||||
{ winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, 1 },
|
||||
{ winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, 1 }
|
||||
};
|
||||
|
||||
static void test_async( void )
|
||||
{
|
||||
static const WCHAR codeweavers[] = {'c','o','d','e','w','e','a','v','e','r','s','.','c','o','m',0};
|
||||
|
||||
HANDLE ses, con, req;
|
||||
DWORD size, status;
|
||||
BOOL ret;
|
||||
struct info info, *context = &info;
|
||||
|
||||
info.test = async_test;
|
||||
info.count = sizeof(async_test) / sizeof(async_test[0]);
|
||||
info.index = 0;
|
||||
info.wait = CreateEvent( NULL, FALSE, FALSE, NULL );
|
||||
|
||||
ses = WinHttpOpen( user_agent, 0, NULL, NULL, WINHTTP_FLAG_ASYNC );
|
||||
ok(ses != NULL, "failed to open session %u\n", GetLastError());
|
||||
|
||||
WinHttpSetStatusCallback( ses, check_notification, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0 );
|
||||
|
||||
ret = WinHttpSetOption( ses, WINHTTP_OPTION_CONTEXT_VALUE, &context, sizeof(struct info *) );
|
||||
ok(ret, "failed to set context value %u\n", GetLastError());
|
||||
|
||||
info.function = winhttp_connect;
|
||||
con = WinHttpConnect( ses, codeweavers, 0, 0 );
|
||||
ok(con != NULL, "failed to open a connection %u\n", GetLastError());
|
||||
|
||||
info.function = winhttp_open_request;
|
||||
req = WinHttpOpenRequest( con, NULL, NULL, NULL, NULL, NULL, 0 );
|
||||
ok(req != NULL, "failed to open a request %u\n", GetLastError());
|
||||
|
||||
info.function = winhttp_send_request;
|
||||
ret = WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 );
|
||||
ok(ret, "failed to send request %u\n", GetLastError());
|
||||
|
||||
WaitForSingleObject( info.wait, INFINITE );
|
||||
|
||||
info.function = winhttp_receive_response;
|
||||
ret = WinHttpReceiveResponse( req, NULL );
|
||||
ok(ret, "failed to receive response %u\n", GetLastError());
|
||||
|
||||
WaitForSingleObject( info.wait, INFINITE );
|
||||
|
||||
size = sizeof(status);
|
||||
ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL );
|
||||
ok(ret, "failed unexpectedly %u\n", GetLastError());
|
||||
ok(status == 200, "request failed unexpectedly %u\n", status);
|
||||
|
||||
info.function = winhttp_close_handle;
|
||||
WinHttpCloseHandle( req );
|
||||
WinHttpCloseHandle( con );
|
||||
WinHttpCloseHandle( ses );
|
||||
CloseHandle( info.wait );
|
||||
}
|
||||
|
||||
START_TEST (notification)
|
||||
{
|
||||
test_connection_cache();
|
||||
test_redirect();
|
||||
test_async();
|
||||
}
|
||||
|
|
|
@ -128,6 +128,7 @@ HINTERNET alloc_handle( object_header_t * );
|
|||
BOOL free_handle( HINTERNET );
|
||||
|
||||
void set_last_error( DWORD );
|
||||
DWORD get_last_error( void );
|
||||
void send_callback( object_header_t *, DWORD, LPVOID, DWORD );
|
||||
void close_connection( request_t * );
|
||||
|
||||
|
|
Loading…
Reference in New Issue