[1/6] winhttp: Start sending async completion notifications. Add corresponding tests.
Hans Leidekker
hans at codeweavers.com
Sun Sep 7 14:29:44 CDT 2008
This patch set enables Google Chrome to retrieve and render a page.
Supersedes my previous patch with the same title.
-Hans
diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c
index 72f9eb5..e2c00df 100644
--- a/dlls/winhttp/request.c
+++ b/dlls/winhttp/request.c
@@ -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 );
diff --git a/dlls/winhttp/session.c b/dlls/winhttp/session.c
index 8725f7e..29510fc 100644
--- a/dlls/winhttp/session.c
+++ b/dlls/winhttp/session.c
@@ -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);
diff --git a/dlls/winhttp/tests/notification.c b/dlls/winhttp/tests/notification.c
index da605b0..8b11e06 100644
--- a/dlls/winhttp/tests/notification.c
+++ b/dlls/winhttp/tests/notification.c
@@ -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();
}
diff --git a/dlls/winhttp/winhttp_private.h b/dlls/winhttp/winhttp_private.h
index 9bf48d4..7cec99b 100644
--- a/dlls/winhttp/winhttp_private.h
+++ b/dlls/winhttp/winhttp_private.h
@@ -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 * );
More information about the wine-patches
mailing list