[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