winhttp: Start sending async completion notifications. Add corresponding tests.

This commit is contained in:
Hans Leidekker 2008-09-07 21:29:44 +02:00 committed by Alexandre Julliard
parent 78c79ba349
commit 3d8a9564cd
4 changed files with 127 additions and 8 deletions

View File

@ -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 );

View File

@ -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);

View File

@ -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();
}

View File

@ -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 * );