It turns out that WinHttpReceiveResponse() completes synchronously in async mode (unless recursive request for handling authorization or redirect is involved). Some apps depend on that and do not wait for WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, calling WinHttpQueryHeaders() or WinHttpWebSocketCompleteUpgrade() right after calling WinHttpReceiveResponse, relying on that to finish synchronously.
My initial out of tree testing shows that no network communication is performed during WinHttpReceiveResponse() call (when recursive request is not involved). I tested that by inserting a wait between WinHttpSendRequest and WinHttpReceiveResponse and disabling network connection during the wait. WinHttpReceiveResponse still succeeds on Windows.
I think the above means that the actual response receiving from server is performed during WinHttpSendRequest. WinHttpReceiveResponse is not a complete no-op however. As shown by the existing tests the notifications related to receiving response are still delivered during WinHttpReceiveResponse (albeit in the same thread). Also WinHttpReceiveResponse affects request state: querying headers or upgrading to websocket without calling WinHttpReceiveResponse does not succeed.
When redirect is involved, all the WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED and WINHTTP_CALLBACK_STATUS_REDIRECT notifications are delivered synchronously from the calling thread. Then, the new request send notifications and response receiving notifications are delivered from the new thread.
An interesting case is when WinHttpReceiveResponse is called from SendRequest callbacks in async mode. If WinHttpReceiveResponse is called from WINHTTP_CALLBACK_STATUS_SENDING_REQUEST or WINHTTP_CALLBACK_STATUS_REQUEST_SENT (i. e., when request is not complete yet), calling WinHttpReceiveResponse() suddenly succeeds an shows the following message sequence (that is partially reflected in the tests I am adding): - calling WinHttpReceiveResponse from WINHTTP_CALLBACK_STATUS_SENDING_REQUEST (which is already called on the async thread on Win10, thread A). Win8 queues WINHTTP_CALLBACK_STATUS_SENDING_REQUEST synchronously and goes async a bit later. - WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, thread A; - WinHttpReceiveResponse() returns to the caller WINHTTP_CALLBACK_STATUS_REQUEST_SENT callback; returning from user callback; - WINHTTP_CALLBACK_STATUS_REQUEST_SENT, thread A; - WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE (another thread, although the sequence is probably synced; I am not implementing this part and calling this callback from the same thread A); - WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED in thread A; - WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE in thread A.
So the receive_response() state RECEIVE_RESPONSE_SEND_INCOMPLETE is primarily needed to handle this case.
-- v2: winhttp/tests: Test calling WinHttpReceiveResponse() recursively from various send callbacks. winhttp/tests: Test WinHttpReceiveResponse() synchronous behaviour. winhttp: Execute receive_response() synchronously when possible. winhttp: Wait for WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE in request_send(). winhttp: Call receive_response() recursively instead of looping. winhttp: Factor out queue_receive_response(). winhttp: Receive server reply in send_request(). winhttp: Send notifications from receive_response() directly. winhttp: Don't refill buffer after receiving server response. winhttp: Do not open connection in handle_redirect().
From: Paul Gofman pgofman@codeweavers.com
Let send_request() do it. --- dlls/winhttp/request.c | 1 - 1 file changed, 1 deletion(-)
diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c index 1a9b4e14ee8..e04d5a04e9d 100644 --- a/dlls/winhttp/request.c +++ b/dlls/winhttp/request.c @@ -2733,7 +2733,6 @@ static DWORD handle_redirect( struct request *request, DWORD status ) else free( hostname );
if ((ret = add_host_header( request, WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE ))) goto end; - if ((ret = open_connection( request ))) goto end;
free( request->path ); request->path = NULL;
From: Paul Gofman pgofman@codeweavers.com
--- dlls/winhttp/request.c | 49 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 6 deletions(-)
diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c index e04d5a04e9d..37508f1c81c 100644 --- a/dlls/winhttp/request.c +++ b/dlls/winhttp/request.c @@ -1795,6 +1795,38 @@ static DWORD discard_eol( struct request *request, BOOL notify ) return ERROR_SUCCESS; }
+static void update_value_from_digit( DWORD *value, char ch ) +{ + if (ch >= '0' && ch <= '9') *value = *value * 16 + ch - '0'; + else if (ch >= 'a' && ch <= 'f') *value = *value * 16 + ch - 'a' + 10; + else if (ch >= 'A' && ch <= 'F') *value = *value * 16 + ch - 'A' + 10; +} + +/* read chunk size if already in the read buffer */ +static BOOL get_chunk_size( struct request *request ) +{ + DWORD chunk_size; + char *p, *eol; + + if (request->read_chunked_size != ~0ul) return TRUE; + + eol = memchr( request->read_buf + request->read_pos, '\n', request->read_size ); + if (!eol) return FALSE; + + chunk_size = 0; + for (p = request->read_buf + request->read_pos; p != eol; ++p) + { + if (*p == ';' || *p == '\r') break; + update_value_from_digit( &chunk_size, *p ); + } + + request->read_chunked_size = chunk_size; + if (!chunk_size) request->read_chunked_eof = TRUE; + + remove_data( request, (eol + 1) - (request->read_buf + request->read_pos) ); + return TRUE; +} + /* read the size of the next chunk */ static DWORD start_next_chunk( struct request *request, BOOL notify ) { @@ -1812,10 +1844,8 @@ static DWORD start_next_chunk( struct request *request, BOOL notify ) while (request->read_size) { char ch = request->read_buf[request->read_pos]; - if (ch >= '0' && ch <= '9') chunk_size = chunk_size * 16 + ch - '0'; - else if (ch >= 'a' && ch <= 'f') chunk_size = chunk_size * 16 + ch - 'a' + 10; - else if (ch >= 'A' && ch <= 'F') chunk_size = chunk_size * 16 + ch - 'A' + 10; - else if (ch == ';' || ch == '\r' || ch == '\n') + + if (ch == ';' || ch == '\r' || ch == '\n') { TRACE( "reading %lu byte chunk\n", chunk_size );
@@ -1827,6 +1857,7 @@ static DWORD start_next_chunk( struct request *request, BOOL notify )
return discard_eol( request, notify ); } + update_value_from_digit( &chunk_size, ch ); remove_data( request, 1 ); } if ((ret = read_more_data( request, -1, notify ))) return ret; @@ -1902,7 +1933,11 @@ static void finished_reading( struct request *request ) /* return the size of data available to be read immediately */ static DWORD get_available_data( struct request *request ) { - if (request->read_chunked) return min( request->read_chunked_size, request->read_size ); + if (request->read_chunked) + { + if (!get_chunk_size( request )) return 0; + return min( request->read_chunked_size, request->read_size ); + } return request->read_size; }
@@ -1920,6 +1955,9 @@ static DWORD read_data( struct request *request, void *buffer, DWORD size, DWORD int count, bytes_read = 0; DWORD ret = ERROR_SUCCESS;
+ if (request->read_chunked && request->read_chunked_size == ~0u + && (ret = start_next_chunk( request, async ))) goto done; + if (end_of_read_data( request )) goto done;
while (size) @@ -2842,7 +2880,6 @@ static DWORD receive_response( struct request *request, BOOL async ) }
if (request->netconn) netconn_set_timeout( request->netconn, FALSE, request->receive_timeout ); - if (request->content_length) ret = refill_buffer( request, FALSE );
if (async) {
From: Paul Gofman pgofman@codeweavers.com
--- dlls/winhttp/request.c | 8 +++++++- dlls/winhttp/winhttp_private.h | 1 + 2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c index 37508f1c81c..2e68decb761 100644 --- a/dlls/winhttp/request.c +++ b/dlls/winhttp/request.c @@ -1772,6 +1772,7 @@ static DWORD read_more_data( struct request *request, int maxlen, BOOL notify ) maxlen - request->read_size, 0, &len );
if (notify) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, &len, sizeof(len) ); + request->read_reply_len += len;
request->read_size += len; return ret; @@ -2212,6 +2213,8 @@ static DWORD send_request( struct request *request, const WCHAR *headers, DWORD int bytes_sent; DWORD ret, len;
+ request->read_reply_len = 0; + if (request->flags & REQUEST_FLAG_WEBSOCKET_UPGRADE && request->websocket_set_send_buffer_size < MIN_WEBSOCKET_SEND_BUFFER_SIZE) { @@ -2530,7 +2533,7 @@ static DWORD read_line( struct request *request, char *buffer, DWORD *len ) remove_data( request, bytes_read ); if (eol) break;
- if ((ret = read_more_data( request, -1, TRUE ))) return ret; + if ((ret = read_more_data( request, -1, FALSE ))) return ret; if (!request->read_size) { *len = 0; @@ -2841,6 +2844,9 @@ static DWORD receive_response( struct request *request, BOOL async ) netconn_set_timeout( request->netconn, FALSE, request->receive_response_timeout ); for (;;) { + send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NULL, 0 ); + send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, + &request->read_reply_len, sizeof(request->read_reply_len) ); if ((ret = read_reply( request ))) break;
size = sizeof(DWORD); diff --git a/dlls/winhttp/winhttp_private.h b/dlls/winhttp/winhttp_private.h index 0326a8fc1e3..88b5c890945 100644 --- a/dlls/winhttp/winhttp_private.h +++ b/dlls/winhttp/winhttp_private.h @@ -220,6 +220,7 @@ struct request } creds[TARGET_MAX][SCHEME_MAX]; unsigned int websocket_receive_buffer_size; unsigned int websocket_send_buffer_size, websocket_set_send_buffer_size; + int read_reply_len; };
enum socket_state
From: Paul Gofman pgofman@codeweavers.com
--- dlls/winhttp/request.c | 30 +++++++++++++++++++++++++----- dlls/winhttp/session.c | 1 + dlls/winhttp/tests/winhttp.c | 8 ++++---- dlls/winhttp/winhttp_private.h | 8 ++++++++ 4 files changed, 38 insertions(+), 9 deletions(-)
diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c index 2e68decb761..265a92c0d79 100644 --- a/dlls/winhttp/request.c +++ b/dlls/winhttp/request.c @@ -800,6 +800,13 @@ BOOL WINAPI WinHttpQueryHeaders( HINTERNET hrequest, DWORD level, const WCHAR *n SetLastError( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE ); return FALSE; } + if (request->state < REQUEST_RESPONSE_STATE_RESPONSE_RECEIVED && !(level & WINHTTP_QUERY_FLAG_REQUEST_HEADERS) + && ((level & ~QUERY_MODIFIER_MASK) != WINHTTP_QUERY_REQUEST_METHOD)) + { + release_object( &request->hdr ); + SetLastError( ERROR_WINHTTP_INCORRECT_HANDLE_STATE ); + return FALSE; + }
ret = query_headers( request, level, name, buffer, buflen, index );
@@ -2213,7 +2220,9 @@ static DWORD send_request( struct request *request, const WCHAR *headers, DWORD int bytes_sent; DWORD ret, len;
+ request->read_reply_status = ERROR_WINHTTP_INCORRECT_HANDLE_STATE; request->read_reply_len = 0; + request->state = REQUEST_RESPONSE_STATE_NONE;
if (request->flags & REQUEST_FLAG_WEBSOCKET_UPGRADE && request->websocket_set_send_buffer_size < MIN_WEBSOCKET_SEND_BUFFER_SIZE) @@ -2293,6 +2302,8 @@ static DWORD send_request( struct request *request, const WCHAR *headers, DWORD request->optional_len = optional_len; len += optional_len; } + netconn_set_timeout( request->netconn, FALSE, request->receive_response_timeout ); + request->read_reply_status = read_reply( request ); send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_SENT, &len, sizeof(len) );
end: @@ -2839,15 +2850,20 @@ static DWORD receive_response( struct request *request, BOOL async ) { DWORD ret, size, query, status;
- if (!request->netconn) return ERROR_WINHTTP_INCORRECT_HANDLE_STATE; + TRACE( "request state %d.\n", request->state ); + + if (request->state >= REQUEST_RESPONSE_STATE_RESPONSE_RECEIVED) + { + ret = ERROR_WINHTTP_INCORRECT_HANDLE_STATE; + goto done; + }
- netconn_set_timeout( request->netconn, FALSE, request->receive_response_timeout ); for (;;) { send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NULL, 0 ); send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, &request->read_reply_len, sizeof(request->read_reply_len) ); - if ((ret = read_reply( request ))) break; + if ((ret = request->read_reply_status)) break;
size = sizeof(DWORD); query = WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER; @@ -2885,8 +2901,12 @@ static DWORD receive_response( struct request *request, BOOL async ) break; }
- if (request->netconn) netconn_set_timeout( request->netconn, FALSE, request->receive_timeout ); - +done: + if (!ret) + { + request->state = REQUEST_RESPONSE_STATE_RESPONSE_RECEIVED; + if (request->netconn) netconn_set_timeout( request->netconn, FALSE, request->receive_timeout ); + } if (async) { if (!ret) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NULL, 0 ); diff --git a/dlls/winhttp/session.c b/dlls/winhttp/session.c index 8aa99f0ece7..65e471f7ee5 100644 --- a/dlls/winhttp/session.c +++ b/dlls/winhttp/session.c @@ -1271,6 +1271,7 @@ HINTERNET WINAPI WinHttpOpenRequest( HINTERNET hconnect, const WCHAR *verb, cons request->websocket_receive_buffer_size = connect->session->websocket_receive_buffer_size; request->websocket_send_buffer_size = connect->session->websocket_send_buffer_size; request->websocket_set_send_buffer_size = request->websocket_send_buffer_size; + request->read_reply_status = ERROR_WINHTTP_INCORRECT_HANDLE_STATE;
if (!verb || !verb[0]) verb = L"GET"; if (!(request->verb = wcsdup( verb ))) goto end; diff --git a/dlls/winhttp/tests/winhttp.c b/dlls/winhttp/tests/winhttp.c index b7deaea324a..76f12837e86 100644 --- a/dlls/winhttp/tests/winhttp.c +++ b/dlls/winhttp/tests/winhttp.c @@ -3277,14 +3277,14 @@ static void test_websocket(int port) ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_UPGRADE, NULL, &header, &size, NULL); error = GetLastError(); ok(!ret, "success\n"); - todo_wine ok(error == ERROR_WINHTTP_INCORRECT_HANDLE_STATE, "got %lu\n", error); + ok(error == ERROR_WINHTTP_INCORRECT_HANDLE_STATE, "got %lu\n", error);
size = sizeof(header); SetLastError(0xdeadbeef); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CONNECTION, NULL, &header, &size, NULL); error = GetLastError(); ok(!ret, "success\n"); - todo_wine ok(error == ERROR_WINHTTP_INCORRECT_HANDLE_STATE, "got %lu\n", error); + ok(error == ERROR_WINHTTP_INCORRECT_HANDLE_STATE, "got %lu\n", error);
index = 0; size = sizeof(buf); @@ -3312,14 +3312,14 @@ static void test_websocket(int port) ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_UPGRADE, NULL, &header, &size, NULL); error = GetLastError(); ok(!ret, "success\n"); - todo_wine ok(error == ERROR_WINHTTP_INCORRECT_HANDLE_STATE, "got %lu\n", error); + ok(error == ERROR_WINHTTP_INCORRECT_HANDLE_STATE, "got %lu\n", error);
size = sizeof(header); SetLastError(0xdeadbeef); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CONNECTION, NULL, &header, &size, NULL); error = GetLastError(); ok(!ret, "success\n"); - todo_wine ok(error == ERROR_WINHTTP_INCORRECT_HANDLE_STATE, "got %lu\n", error); + ok(error == ERROR_WINHTTP_INCORRECT_HANDLE_STATE, "got %lu\n", error);
index = 0; buf[0] = 0; diff --git a/dlls/winhttp/winhttp_private.h b/dlls/winhttp/winhttp_private.h index 88b5c890945..9c6d30eca77 100644 --- a/dlls/winhttp/winhttp_private.h +++ b/dlls/winhttp/winhttp_private.h @@ -174,6 +174,12 @@ enum request_flags REQUEST_FLAG_WEBSOCKET_UPGRADE = 0x01, };
+enum request_response_state +{ + REQUEST_RESPONSE_STATE_NONE, + REQUEST_RESPONSE_STATE_RESPONSE_RECEIVED, +}; + struct request { struct object_header hdr; @@ -221,6 +227,8 @@ struct request unsigned int websocket_receive_buffer_size; unsigned int websocket_send_buffer_size, websocket_set_send_buffer_size; int read_reply_len; + DWORD read_reply_status; + enum request_response_state state; };
enum socket_state
From: Paul Gofman pgofman@codeweavers.com
--- dlls/winhttp/request.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-)
diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c index 265a92c0d79..c8e19b6f0a8 100644 --- a/dlls/winhttp/request.c +++ b/dlls/winhttp/request.c @@ -2846,6 +2846,19 @@ static DWORD handle_passport_redirect( struct request *request ) return ERROR_SUCCESS; }
+static void task_receive_response( void *ctx, BOOL abort ); + +static DWORD queue_receive_response( struct request *request ) +{ + struct receive_response *r; + DWORD ret; + + if (!(r = malloc( sizeof(*r) ))) return ERROR_OUTOFMEMORY; + if ((ret = queue_task( &request->queue, task_receive_response, &r->task_hdr, &request->hdr ))) + free( r ); + return ret; +} + static DWORD receive_response( struct request *request, BOOL async ) { DWORD ret, size, query, status; @@ -2954,20 +2967,8 @@ BOOL WINAPI WinHttpReceiveResponse( HINTERNET hrequest, LPVOID reserved ) return FALSE; }
- if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC) - { - struct receive_response *r; - - if (!(r = malloc( sizeof(*r) ))) - { - release_object( &request->hdr ); - SetLastError( ERROR_OUTOFMEMORY ); - return FALSE; - } - if ((ret = queue_task( &request->queue, task_receive_response, &r->task_hdr, &request->hdr ))) - free( r ); - } - else ret = receive_response( request, FALSE ); + if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC) ret = queue_receive_response( request ); + else ret = receive_response( request, FALSE );
release_object( &request->hdr ); SetLastError( ret );
From: Paul Gofman pgofman@codeweavers.com
--- dlls/winhttp/request.c | 76 ++++++++++++++++++---------------- dlls/winhttp/winhttp_private.h | 1 + 2 files changed, 42 insertions(+), 35 deletions(-)
diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c index c8e19b6f0a8..130adeee8a2 100644 --- a/dlls/winhttp/request.c +++ b/dlls/winhttp/request.c @@ -2859,8 +2859,9 @@ static DWORD queue_receive_response( struct request *request ) return ret; }
-static DWORD receive_response( struct request *request, BOOL async ) +static DWORD receive_response( struct request *request ) { + BOOL async_mode = request->connect->hdr.flags & WINHTTP_FLAG_ASYNC; DWORD ret, size, query, status;
TRACE( "request state %d.\n", request->state ); @@ -2871,48 +2872,53 @@ static DWORD receive_response( struct request *request, BOOL async ) goto done; }
- for (;;) + if (request->state == REQUEST_RESPONSE_RECURSIVE_REQUEST) { - send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NULL, 0 ); - send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, - &request->read_reply_len, sizeof(request->read_reply_len) ); - if ((ret = request->read_reply_status)) break; - - size = sizeof(DWORD); - query = WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER; - if ((ret = query_headers( request, query, NULL, &status, &size, NULL ))) break; + TRACE( "Sending request.\n" ); + if ((ret = send_request( request, NULL, 0, request->optional, request->optional_len, 0, 0, FALSE ))) goto done; + }
- set_content_length( request, status ); + send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NULL, 0 ); + send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, + &request->read_reply_len, sizeof(request->read_reply_len) ); + if ((ret = request->read_reply_status)) goto done;
- if (!(request->hdr.disable_flags & WINHTTP_DISABLE_COOKIES)) record_cookies( request ); + size = sizeof(DWORD); + query = WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER; + if ((ret = query_headers( request, query, NULL, &status, &size, NULL ))) goto done;
- if (status == HTTP_STATUS_REDIRECT && is_passport_request( request )) - { - ret = handle_passport_redirect( request ); - } - else if (status == HTTP_STATUS_MOVED || status == HTTP_STATUS_REDIRECT || status == HTTP_STATUS_REDIRECT_KEEP_VERB) - { - if (request->hdr.disable_flags & WINHTTP_DISABLE_REDIRECTS || - request->hdr.redirect_policy == WINHTTP_OPTION_REDIRECT_POLICY_NEVER) break; + set_content_length( request, status );
- if (++request->redirect_count > request->max_redirects) return ERROR_WINHTTP_REDIRECT_FAILED; + if (!(request->hdr.disable_flags & WINHTTP_DISABLE_COOKIES)) record_cookies( request );
- if ((ret = handle_redirect( request, status ))) break; + if (status == HTTP_STATUS_REDIRECT && is_passport_request( request )) + { + ret = handle_passport_redirect( request ); + goto done; + } + if (status == HTTP_STATUS_MOVED || status == HTTP_STATUS_REDIRECT || status == HTTP_STATUS_REDIRECT_KEEP_VERB) + { + if (request->hdr.disable_flags & WINHTTP_DISABLE_REDIRECTS || + request->hdr.redirect_policy == WINHTTP_OPTION_REDIRECT_POLICY_NEVER) goto done;
- /* recurse synchronously */ - if (!(ret = send_request( request, NULL, 0, request->optional, request->optional_len, 0, 0, FALSE ))) continue; - } - else if (status == HTTP_STATUS_DENIED || status == HTTP_STATUS_PROXY_AUTH_REQ) + if (++request->redirect_count > request->max_redirects) { - if (request->hdr.disable_flags & WINHTTP_DISABLE_AUTHENTICATION) break; + ret = ERROR_WINHTTP_REDIRECT_FAILED; + goto done; + }
- if (handle_authorization( request, status )) break; + if ((ret = handle_redirect( request, status ))) goto done; + } + else if (status == HTTP_STATUS_DENIED || status == HTTP_STATUS_PROXY_AUTH_REQ) + { + if (request->hdr.disable_flags & WINHTTP_DISABLE_AUTHENTICATION) goto done;
- /* recurse synchronously */ - if (!(ret = send_request( request, NULL, 0, request->optional, request->optional_len, 0, 0, FALSE ))) continue; - } - break; + if (handle_authorization( request, status )) goto done; } + else goto done; + + request->state = REQUEST_RESPONSE_RECURSIVE_REQUEST; + return receive_response( request );
done: if (!ret) @@ -2920,7 +2926,7 @@ done: request->state = REQUEST_RESPONSE_STATE_RESPONSE_RECEIVED; if (request->netconn) netconn_set_timeout( request->netconn, FALSE, request->receive_timeout ); } - if (async) + if (async_mode) { if (!ret) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NULL, 0 ); else @@ -2942,7 +2948,7 @@ static void task_receive_response( void *ctx, BOOL abort ) if (abort) return;
TRACE("running %p\n", ctx); - receive_response( request, TRUE ); + receive_response( request ); }
/*********************************************************************** @@ -2968,7 +2974,7 @@ BOOL WINAPI WinHttpReceiveResponse( HINTERNET hrequest, LPVOID reserved ) }
if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC) ret = queue_receive_response( request ); - else ret = receive_response( request, FALSE ); + else ret = receive_response( request );
release_object( &request->hdr ); SetLastError( ret ); diff --git a/dlls/winhttp/winhttp_private.h b/dlls/winhttp/winhttp_private.h index 9c6d30eca77..cc2187d4200 100644 --- a/dlls/winhttp/winhttp_private.h +++ b/dlls/winhttp/winhttp_private.h @@ -177,6 +177,7 @@ enum request_flags enum request_response_state { REQUEST_RESPONSE_STATE_NONE, + REQUEST_RESPONSE_RECURSIVE_REQUEST, REQUEST_RESPONSE_STATE_RESPONSE_RECEIVED, };
From: Paul Gofman pgofman@codeweavers.com
--- dlls/winhttp/request.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c index 130adeee8a2..d5eb1bfce3a 100644 --- a/dlls/winhttp/request.c +++ b/dlls/winhttp/request.c @@ -5259,7 +5259,7 @@ static HRESULT request_send( struct winhttp_request *request ) size++; } } - wait_set_status_callback( request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT ); + wait_set_status_callback( request, WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE ); if (!WinHttpSendRequest( request->hrequest, NULL, 0, ptr, size, size, 0 )) { err = GetLastError();
From: Paul Gofman pgofman@codeweavers.com
--- dlls/winhttp/request.c | 34 ++++++++++++++++++++++++++++++---- dlls/winhttp/winhttp_private.h | 4 ++++ 2 files changed, 34 insertions(+), 4 deletions(-)
diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c index d5eb1bfce3a..c99cb7ee195 100644 --- a/dlls/winhttp/request.c +++ b/dlls/winhttp/request.c @@ -2220,6 +2220,8 @@ static DWORD send_request( struct request *request, const WCHAR *headers, DWORD int bytes_sent; DWORD ret, len;
+ TRACE( "request state %d.\n", request->state ); + request->read_reply_status = ERROR_WINHTTP_INCORRECT_HANDLE_STATE; request->read_reply_len = 0; request->state = REQUEST_RESPONSE_STATE_NONE; @@ -2289,6 +2291,7 @@ static DWORD send_request( struct request *request, const WCHAR *headers, DWORD } TRACE("full request: %s\n", debugstr_a(wire_req));
+ request->state = REQUEST_RESPONSE_STATE_SENDING_REQUEST; send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST, NULL, 0 );
ret = netconn_send( request->netconn, wire_req, len, &bytes_sent, NULL ); @@ -2306,6 +2309,11 @@ static DWORD send_request( struct request *request, const WCHAR *headers, DWORD request->read_reply_status = read_reply( request ); send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_SENT, &len, sizeof(len) );
+ if (request->state == REQUEST_RESPONSE_STATE_READ_RESPONSE_QUEUED) + request->state = REQUEST_RESPONSE_STATE_READ_RESPONSE_QUEUED_REQUEST_SENT; + else + request->state = REQUEST_RESPONSE_STATE_REQUEST_SENT; + end: if (async) { @@ -2863,6 +2871,7 @@ static DWORD receive_response( struct request *request ) { BOOL async_mode = request->connect->hdr.flags & WINHTTP_FLAG_ASYNC; DWORD ret, size, query, status; + BOOL return_to_send;
TRACE( "request state %d.\n", request->state );
@@ -2878,7 +2887,24 @@ static DWORD receive_response( struct request *request ) if ((ret = send_request( request, NULL, 0, request->optional, request->optional_len, 0, 0, FALSE ))) goto done; }
- send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NULL, 0 ); + return_to_send = async_mode && request->state == REQUEST_RESPONSE_STATE_SENDING_REQUEST; + if (request->state < REQUEST_RESPONSE_STATE_REQUEST_SENT && !return_to_send) + { + ret = ERROR_WINHTTP_INCORRECT_HANDLE_STATE; + goto done; + } + + if (request->state == REQUEST_RESPONSE_STATE_READ_RESPONSE_QUEUED_REQUEST_SENT) + request->state = REQUEST_RESPONSE_STATE_REQUEST_SENT; + else + send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NULL, 0 ); + + if (return_to_send) + { + request->state = REQUEST_RESPONSE_STATE_READ_RESPONSE_QUEUED; + return queue_receive_response( request ); + } + send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, &request->read_reply_len, sizeof(request->read_reply_len) ); if ((ret = request->read_reply_status)) goto done; @@ -2918,7 +2944,7 @@ static DWORD receive_response( struct request *request ) else goto done;
request->state = REQUEST_RESPONSE_RECURSIVE_REQUEST; - return receive_response( request ); + return async_mode ? queue_receive_response( request ) : receive_response( request );
done: if (!ret) @@ -2936,6 +2962,7 @@ done: result.dwError = ret; send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &result, sizeof(result) ); } + return ERROR_SUCCESS; } return ret; } @@ -2973,8 +3000,7 @@ BOOL WINAPI WinHttpReceiveResponse( HINTERNET hrequest, LPVOID reserved ) return FALSE; }
- if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC) ret = queue_receive_response( request ); - else ret = receive_response( request ); + ret = receive_response( request );
release_object( &request->hdr ); SetLastError( ret ); diff --git a/dlls/winhttp/winhttp_private.h b/dlls/winhttp/winhttp_private.h index cc2187d4200..8e4789356ec 100644 --- a/dlls/winhttp/winhttp_private.h +++ b/dlls/winhttp/winhttp_private.h @@ -177,6 +177,10 @@ enum request_flags enum request_response_state { REQUEST_RESPONSE_STATE_NONE, + REQUEST_RESPONSE_STATE_SENDING_REQUEST, + REQUEST_RESPONSE_STATE_READ_RESPONSE_QUEUED, + REQUEST_RESPONSE_STATE_REQUEST_SENT, + REQUEST_RESPONSE_STATE_READ_RESPONSE_QUEUED_REQUEST_SENT, REQUEST_RESPONSE_RECURSIVE_REQUEST, REQUEST_RESPONSE_STATE_RESPONSE_RECEIVED, };
From: Paul Gofman pgofman@codeweavers.com
--- dlls/winhttp/tests/notification.c | 198 +++++++++++++++++++++++------- 1 file changed, 152 insertions(+), 46 deletions(-)
diff --git a/dlls/winhttp/tests/notification.c b/dlls/winhttp/tests/notification.c index a9f782f5e3d..d029a0a9054 100644 --- a/dlls/winhttp/tests/notification.c +++ b/dlls/winhttp/tests/notification.c @@ -64,6 +64,7 @@ struct notification #define NF_SIGNAL 0x0004 /* signal wait handle when notified */ #define NF_MAIN_THREAD 0x0008 /* the operation completes synchronously and callback is called from the main thread */ #define NF_SAVE_BUFFER 0x0010 /* save buffer data when notified */ +#define NF_OTHER_THREAD 0x0020 /* the operation completes asynchronously and callback is called from the other thread */
struct info { @@ -119,8 +120,13 @@ static void CALLBACK check_notification( HINTERNET handle, DWORD_PTR context, DW
if (info->test[info->index].flags & NF_MAIN_THREAD) { - ok(GetCurrentThreadId() == info->main_thread_id, "%u: expected callback to be called from the same thread\n", - info->line); + ok(GetCurrentThreadId() == info->main_thread_id, "%u: expected callback %#lx to be called from the same thread\n", + info->line, status); + } + else if (info->test[info->index].flags & NF_OTHER_THREAD) + { + ok(GetCurrentThreadId() != info->main_thread_id, "%u: expected callback %#lx to be called from the other thread\n", + info->line, status); } if (info->test[info->index].flags & NF_SAVE_BUFFER) { @@ -134,6 +140,56 @@ static void CALLBACK check_notification( HINTERNET handle, DWORD_PTR context, DW } }
+static const struct notification cache_test_async[] = +{ + { winhttp_connect, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, + { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME, NF_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED, NF_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, NF_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, NF_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE, NF_SIGNAL }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NF_MAIN_THREAD | NF_SIGNAL }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }, + { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, NF_WINE_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, NF_WINE_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE, NF_SIGNAL }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NF_MAIN_THREAD | NF_SIGNAL }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }, + { winhttp_connect, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, + { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME, NF_WINE_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED, NF_WINE_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, NF_WINE_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, NF_WINE_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_MAIN_THREAD }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }, + { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, NF_WINE_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, NF_WINE_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_MAIN_THREAD }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL } +}; + static const struct notification cache_test[] = { { winhttp_connect, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, @@ -143,17 +199,17 @@ static const struct notification cache_test[] = { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, - { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT, NF_SIGNAL }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_MAIN_THREAD | NF_SIGNAL }, { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }, { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, NF_WINE_ALLOW }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, NF_WINE_ALLOW }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, - { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT, NF_SIGNAL }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_MAIN_THREAD | NF_SIGNAL }, { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING }, { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }, { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }, @@ -165,16 +221,16 @@ static const struct notification cache_test[] = { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, NF_WINE_ALLOW }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_MAIN_THREAD }, { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }, { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, NF_WINE_ALLOW }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, NF_WINE_ALLOW }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_MAIN_THREAD }, { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING }, { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }, { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL } @@ -202,19 +258,19 @@ static void end_test( struct info *info, unsigned int line ) info->test[info->index].status); }
-static void test_connection_cache( void ) +static void test_connection_cache( BOOL async ) { HANDLE ses, con, req, event; DWORD size, status, err; BOOL ret, unload = TRUE; struct info info, *context = &info;
- info.test = cache_test; - info.count = ARRAY_SIZE( cache_test ); + info.test = async ? cache_test_async : cache_test; + info.count = async ? ARRAY_SIZE( cache_test_async ) : ARRAY_SIZE ( cache_test ); info.index = 0; info.wait = CreateEventW( NULL, FALSE, FALSE, NULL );
- ses = WinHttpOpen( L"winetest", 0, NULL, NULL, 0 ); + ses = WinHttpOpen( L"winetest", 0, NULL, NULL, async ? WINHTTP_FLAG_ASYNC : 0 ); ok( ses != NULL, "failed to open session %lu\n", GetLastError() );
event = CreateEventW( NULL, FALSE, FALSE, NULL ); @@ -247,11 +303,14 @@ static void test_connection_cache( void ) goto done; } ok( ret, "failed to send request %lu\n", GetLastError() ); + WaitForSingleObject( info.wait, INFINITE );
setup_test( &info, winhttp_receive_response, __LINE__ ); ret = WinHttpReceiveResponse( req, NULL ); ok( ret, "failed to receive response %lu\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 %lu\n", GetLastError() ); @@ -260,6 +319,7 @@ static void test_connection_cache( void ) ResetEvent( info.wait ); setup_test( &info, winhttp_close_handle, __LINE__ ); WinHttpCloseHandle( req ); + WaitForSingleObject( info.wait, INFINITE );
setup_test( &info, winhttp_open_request, __LINE__ ); @@ -279,10 +339,14 @@ static void test_connection_cache( void ) } ok( ret, "failed to send request %lu\n", GetLastError() );
+ WaitForSingleObject( info.wait, INFINITE ); + setup_test( &info, winhttp_receive_response, __LINE__ ); ret = WinHttpReceiveResponse( req, NULL ); ok( ret, "failed to receive response %lu\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 %lu\n", GetLastError() ); @@ -414,6 +478,32 @@ done: }
static const struct notification redirect_test[] = +{ + { winhttp_connect, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, + { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME, NF_WINE_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED, NF_WINE_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, NF_WINE_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, NF_WINE_ALLOW }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST, NF_MAIN_THREAD }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT, NF_MAIN_THREAD | NF_SIGNAL }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_REDIRECT, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME, NF_ALLOW | NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED, NF_ALLOW | NF_MAIN_THREAD}, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, NF_ALLOW | NF_MAIN_THREAD}, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, NF_ALLOW | NF_MAIN_THREAD}, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST, NF_MAIN_THREAD}, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_REQUEST_SENT, NF_MAIN_THREAD}, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_MAIN_THREAD}, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_MAIN_THREAD | NF_SIGNAL}, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL } +}; + +static const struct notification redirect_test_async[] = { { winhttp_connect, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, @@ -423,35 +513,37 @@ static const struct notification redirect_test[] = { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, NF_WINE_ALLOW }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_REDIRECT }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE, NF_SIGNAL | NF_OTHER_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_REDIRECT, NF_MAIN_THREAD }, { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME, NF_ALLOW }, { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED, NF_ALLOW }, { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, NF_ALLOW }, { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, NF_ALLOW }, { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_REQUEST_SENT }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_OTHER_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_OTHER_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NF_OTHER_THREAD | NF_SIGNAL }, { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING }, { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING }, { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL } };
-static void test_redirect( void ) +static void test_redirect( BOOL async ) { HANDLE ses, con, req; DWORD size, status, err; BOOL ret; struct info info, *context = &info;
- info.test = redirect_test; - info.count = ARRAY_SIZE( redirect_test ); + info.test = async ? redirect_test_async : redirect_test; + info.count = async ? ARRAY_SIZE( redirect_test_async ) : ARRAY_SIZE( redirect_test ); info.index = 0; info.wait = CreateEventW( NULL, FALSE, FALSE, NULL );
- ses = WinHttpOpen( L"winetest", 0, NULL, NULL, 0 ); + ses = WinHttpOpen( L"winetest", 0, NULL, NULL, async ? WINHTTP_FLAG_ASYNC : 0 ); ok( ses != NULL, "failed to open session %lu\n", GetLastError() );
WinHttpSetStatusCallback( ses, check_notification, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0 ); @@ -476,12 +568,15 @@ static void test_redirect( void ) goto done; } ok( ret, "failed to send request %lu\n", GetLastError() ); + WaitForSingleObject( info.wait, INFINITE );
setup_test( &info, winhttp_receive_response, __LINE__ ); ret = WinHttpReceiveResponse( req, NULL ); ok( ret, "failed to receive response %lu\n", GetLastError() ); + WaitForSingleObject( info.wait, INFINITE );
size = sizeof(status); + status = 0xdeadbeef; ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL ); ok( ret, "failed unexpectedly %lu\n", GetLastError() ); ok( status == 200, "request failed unexpectedly %lu\n", status ); @@ -507,9 +602,10 @@ static const struct notification async_test[] = { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE, NF_SIGNAL }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NF_SIGNAL }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, NF_SIGNAL | NF_MAIN_THREAD }, { winhttp_query_data, WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE, NF_SIGNAL }, { winhttp_read_data, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_ALLOW }, { winhttp_read_data, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_ALLOW }, @@ -599,6 +695,12 @@ static void test_async( void ) ok( ret, "failed to receive response %lu\n", err ); ok( err == ERROR_SUCCESS, "got %lu\n", err );
+ SetLastError( 0xdeadbeef ); + ret = WinHttpReceiveResponse( req, NULL ); + err = GetLastError(); + ok( ret, "failed to receive response %lu\n", err ); + ok( err == ERROR_SUCCESS, "got %lu\n", err ); + WaitForSingleObject( info.wait, INFINITE );
size = sizeof(status); @@ -668,9 +770,9 @@ static const struct notification websocket_test[] = { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE, NF_SIGNAL }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NF_SIGNAL }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NF_MAIN_THREAD | NF_SIGNAL }, { winhttp_websocket_complete_upgrade, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, { winhttp_websocket_complete_upgrade, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }, { winhttp_websocket_send, WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE, NF_MAIN_THREAD | NF_SIGNAL }, @@ -694,9 +796,9 @@ static const struct notification websocket_test2[] = { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE, NF_SIGNAL }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NF_SIGNAL }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NF_SIGNAL | NF_MAIN_THREAD}, { winhttp_websocket_complete_upgrade, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, NF_SIGNAL }, { winhttp_websocket_receive, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, NF_SIGNAL }, { winhttp_websocket_close, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, NF_MAIN_THREAD | NF_SAVE_BUFFER}, @@ -715,9 +817,9 @@ static const struct notification websocket_test3[] = { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE, NF_SIGNAL }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NF_SIGNAL }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NF_SIGNAL | NF_MAIN_THREAD }, { winhttp_websocket_complete_upgrade, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, NF_SIGNAL }, { winhttp_websocket_receive, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, NF_SIGNAL },
@@ -738,9 +840,9 @@ static struct notification websocket_test4[] = { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE, NF_SIGNAL }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NF_SIGNAL }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NF_SIGNAL | NF_MAIN_THREAD }, { winhttp_websocket_complete_upgrade, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, NF_SIGNAL }, { winhttp_websocket_receive, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, NF_SIGNAL },
@@ -760,10 +862,10 @@ static const struct notification websocket_test5[] = { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT }, { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE, NF_SIGNAL }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED }, - { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NF_SIGNAL }, - { winhttp_websocket_complete_upgrade, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, NF_SIGNAL }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_MAIN_THREAD }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NF_SIGNAL | NF_MAIN_THREAD }, + { winhttp_websocket_complete_upgrade, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, NF_SIGNAL | NF_MAIN_THREAD }, { winhttp_websocket_receive, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, NF_SIGNAL },
{ winhttp_websocket_shutdown, WINHTTP_CALLBACK_STATUS_SHUTDOWN_COMPLETE, NF_MAIN_THREAD }, @@ -1901,8 +2003,12 @@ START_TEST (notification) pWinHttpWebSocketSend = (void *)GetProcAddress( mod, "WinHttpWebSocketSend" ); pWinHttpWebSocketShutdown = (void *)GetProcAddress( mod, "WinHttpWebSocketShutdown" );
- test_connection_cache(); - test_redirect(); + test_connection_cache( FALSE ); + test_redirect( FALSE ); + winetest_push_context( "async" ); + test_connection_cache( TRUE ); + test_redirect( TRUE ); + winetest_pop_context(); test_async(); test_websocket( FALSE ); winetest_push_context( "secure" );
From: Paul Gofman pgofman@codeweavers.com
--- dlls/winhttp/tests/notification.c | 88 ++++++++++++++++++++++++++++--- 1 file changed, 81 insertions(+), 7 deletions(-)
diff --git a/dlls/winhttp/tests/notification.c b/dlls/winhttp/tests/notification.c index d029a0a9054..d5a576ce4e1 100644 --- a/dlls/winhttp/tests/notification.c +++ b/dlls/winhttp/tests/notification.c @@ -1848,6 +1848,10 @@ struct test_recursion_context LONG recursion_count, max_recursion_query, max_recursion_read; BOOL read_from_callback; BOOL have_sync_callback; + DWORD call_receive_response_status; + DWORD main_thread_id; + DWORD receive_response_thread_id; + BOOL headers_available; };
/* The limit is 128 before Win7 and 3 on newer Windows. */ @@ -1863,8 +1867,25 @@ static void CALLBACK test_recursion_callback( HINTERNET handle, DWORD_PTR contex
switch (status) { + case WINHTTP_CALLBACK_STATUS_SENDING_REQUEST: + case WINHTTP_CALLBACK_STATUS_REQUEST_SENT: case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE: + if (status == context->call_receive_response_status) + { + context->receive_response_thread_id = GetCurrentThreadId(); + ret = WinHttpReceiveResponse( context->request, NULL ); + ok( ret, "failed to receive response, GetLastError() %lu\n", GetLastError() ); + } + break; + case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE: + if (context->call_receive_response_status == WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE) + ok( GetCurrentThreadId() == context->receive_response_thread_id, + "expected callback to be called from the same thread, got %lx.\n", GetCurrentThreadId() ); + else + ok( GetCurrentThreadId() != context->main_thread_id, + "expected callback to be called from the other thread, got main.\n" ); + context->headers_available = TRUE; SetEvent( context->wait ); break;
@@ -1911,20 +1932,37 @@ static void CALLBACK test_recursion_callback( HINTERNET handle, DWORD_PTR contex if (err == ERROR_SUCCESS) context->have_sync_callback = TRUE; InterlockedDecrement( &context->recursion_count ); break; + case WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE: + case WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED: + if (context->headers_available) + ok( GetCurrentThreadId() == context->main_thread_id, + "expected callback to be called from the same thread, got %lx.\n", GetCurrentThreadId() ); + else if (context->call_receive_response_status == WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE) + ok( GetCurrentThreadId() == context->receive_response_thread_id, + "expected callback to be called from the same thread, got %lx.\n", GetCurrentThreadId() ); + break; } }
static void test_recursion(void) { + static DWORD request_callback_status_tests[] = + { + WINHTTP_CALLBACK_STATUS_SENDING_REQUEST, + WINHTTP_CALLBACK_STATUS_REQUEST_SENT, + }; struct test_recursion_context context; HANDLE session, connection, request; DWORD size, status, err; + char buffer[1024]; + unsigned int i; BOOL ret; BYTE b;
memset( &context, 0, sizeof(context) );
context.wait = CreateEventW( NULL, FALSE, FALSE, NULL ); + context.main_thread_id = GetCurrentThreadId();
session = WinHttpOpen( L"winetest", 0, NULL, NULL, WINHTTP_FLAG_ASYNC ); ok( !!session, "failed to open session, GetLastError() %lu\n", GetLastError() ); @@ -1938,6 +1976,11 @@ static void test_recursion(void) ok( !!request, "failed to open a request, GetLastError() %lu\n", GetLastError() );
context.request = request; + + ret = WinHttpReceiveResponse( request, NULL ); + ok( ret, "failed to receive response, GetLastError() %lu\n", GetLastError() ); + + context.call_receive_response_status = WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE; ret = WinHttpSendRequest( request, NULL, 0, NULL, 0, 0, (DWORD_PTR)&context ); err = GetLastError(); if (!ret && (err == ERROR_WINHTTP_CANNOT_CONNECT || err == ERROR_WINHTTP_TIMEOUT)) @@ -1954,11 +1997,6 @@ static void test_recursion(void)
WaitForSingleObject( context.wait, INFINITE );
- ret = WinHttpReceiveResponse( request, NULL ); - ok( ret, "failed to receive response, GetLastError() %lu\n", GetLastError() ); - - WaitForSingleObject( context.wait, INFINITE ); - size = sizeof(status); ret = WinHttpQueryHeaders( request, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL ); @@ -1981,9 +2019,45 @@ static void test_recursion(void) } else skip( "no sync callbacks\n");
- WinHttpSetStatusCallback( session, NULL, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0 ); - WinHttpCloseHandle( request ); + + for (i = 0; i < ARRAY_SIZE(request_callback_status_tests); ++i) + { + winetest_push_context( "i %u", i ); + + request = WinHttpOpenRequest( connection, NULL, L"/tests/hello.html", NULL, NULL, NULL, 0 ); + ok( !!request, "failed to open a request, GetLastError() %lu\n", GetLastError() ); + + context.request = request; + context.call_receive_response_status = request_callback_status_tests[i]; + context.headers_available = FALSE; + + ret = WinHttpSendRequest( request, NULL, 0, NULL, 0, 0, (DWORD_PTR)&context ); + err = GetLastError(); + if (!ret && (err == ERROR_WINHTTP_CANNOT_CONNECT || err == ERROR_WINHTTP_TIMEOUT)) + { + skip("Connection failed, skipping\n"); + WinHttpSetStatusCallback( session, NULL, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0 ); + WinHttpCloseHandle( request ); + WinHttpCloseHandle( connection ); + WinHttpCloseHandle( session ); + CloseHandle( context.wait ); + winetest_pop_context(); + return; + } + + WaitForSingleObject( context.wait, INFINITE ); + + ret = WinHttpReadData( request, buffer, sizeof(buffer), NULL ); + ok( ret, "failed to read data, GetLastError() %lu\n", GetLastError() ); + + WaitForSingleObject( context.wait, INFINITE ); + + WinHttpCloseHandle( request ); + winetest_pop_context(); + } + + WinHttpSetStatusCallback( session, NULL, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0 ); WinHttpCloseHandle( connection ); WinHttpCloseHandle( session ); CloseHandle( context.wait );
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=127228
Your paranoid android.
=== w7u_2qxl (32 bit report) ===
winhttp: notification.c:1938: Test failed: expected callback to be called from the same thread, got 680. notification.c:1938: Test failed: expected callback to be called from the same thread, got 680.
=== w7u_adm (32 bit report) ===
winhttp: notification.c:1938: Test failed: expected callback to be called from the same thread, got 86c. notification.c:1938: Test failed: expected callback to be called from the same thread, got 86c.
=== w7u_el (32 bit report) ===
winhttp: notification.c:1938: Test failed: expected callback to be called from the same thread, got a68. notification.c:1938: Test failed: expected callback to be called from the same thread, got a68.
v2: - added patch 2 ("winhttp: Don't refill buffer after receiving server response."); - keep header and redirect processing in receive_response(); - introduce a receive / response state instead of multiple flags and receive_response_queue_state; - added patch 7 ("winhttp: Wait for WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE in request_send()."). Waiting for WINHTTP_CALLBACK_STATUS_REQUEST_SENT is a bit racy with the next patch (it would be fine if WinHttpReceiveResponse was called right from callback but when it signals the event the state update in send_request() races with receive_request() (matter of atomic status update in receive_request / send_request but it is hopefully not needed). WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE looks like a correct callback and using it also avoids asynchronous queuing due to send_request() is not fully complete yet. - remove leftover break from test_recursion_callback() in the last patch.