Signed-off-by: Paul Gofman pgofman@codeweavers.com --- winhttp functions (in particular, WinHttpQueryDataAvailable and WinHttpReadData) can execute synchronously if the data is available. This is the documented behaviour which is also confirmed by the tests.
'eFootball PES 2021 Season Update' depends on this behaviour. It creates asynchronous session but then breaks in various ways if WinHttpReadData() actually queues the async task. The game always calls WinHttpQueryDataAvailable() first and then WinHttpReadData with the read size equal to the available data, so that the read is always synchronous on Windows.
dlls/winhttp/request.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c index a6c16d7b653..b8f5817737e 100644 --- a/dlls/winhttp/request.c +++ b/dlls/winhttp/request.c @@ -2815,19 +2815,26 @@ BOOL WINAPI WinHttpReceiveResponse( HINTERNET hrequest, LPVOID reserved ) return !ret; }
+static DWORD query_data_ready( struct request *request ) +{ + DWORD count; + + count = get_available_data( request ); + if (!request->read_chunked && request->netconn) count += netconn_query_data_available( request->netconn ); + + return count; +} + static DWORD query_data_available( struct request *request, DWORD *available, BOOL async ) { DWORD ret = ERROR_SUCCESS, count = 0;
if (end_of_read_data( request )) goto done;
- count = get_available_data( request ); - if (!request->read_chunked && request->netconn) count += netconn_query_data_available( request->netconn ); - if (!count) + if (!(count = query_data_ready( request ))) { if ((ret = refill_buffer( request, async ))) goto done; - count = get_available_data( request ); - if (!request->read_chunked && request->netconn) count += netconn_query_data_available( request->netconn ); + count = query_data_ready( request ); }
done:
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/winhttp/request.c | 6 ++++-- dlls/winhttp/tests/notification.c | 9 +++++++++ 2 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c index b8f5817737e..b1223d89060 100644 --- a/dlls/winhttp/request.c +++ b/dlls/winhttp/request.c @@ -2873,6 +2873,7 @@ BOOL WINAPI WinHttpQueryDataAvailable( HINTERNET hrequest, LPDWORD available ) { DWORD ret; struct request *request; + BOOL async;
TRACE("%p, %p\n", hrequest, available);
@@ -2888,7 +2889,8 @@ BOOL WINAPI WinHttpQueryDataAvailable( HINTERNET hrequest, LPDWORD available ) return FALSE; }
- if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC) + if ((async = request->connect->hdr.flags & WINHTTP_FLAG_ASYNC) && !end_of_read_data( request ) + && !query_data_ready( request )) { struct query_data *q;
@@ -2903,7 +2905,7 @@ BOOL WINAPI WinHttpQueryDataAvailable( HINTERNET hrequest, LPDWORD available ) free( q ); } } - else ret = query_data_available( request, available, FALSE ); + else ret = query_data_available( request, available, async );
release_object( &request->hdr ); SetLastError( ret ); diff --git a/dlls/winhttp/tests/notification.c b/dlls/winhttp/tests/notification.c index 98e4024867f..e4d3912d2f6 100644 --- a/dlls/winhttp/tests/notification.c +++ b/dlls/winhttp/tests/notification.c @@ -71,6 +71,8 @@ struct info unsigned int index; HANDLE wait; unsigned int line; + DWORD last_thread_id; + DWORD last_status; };
struct test_request @@ -85,6 +87,9 @@ static void CALLBACK check_notification( HINTERNET handle, DWORD_PTR context, DW BOOL status_ok, function_ok; struct info *info = (struct info *)context;
+ info->last_status = status; + info->last_thread_id = GetCurrentThreadId(); + if (status == WINHTTP_CALLBACK_STATUS_HANDLE_CREATED) { DWORD size = sizeof(struct info *); @@ -177,6 +182,8 @@ static void setup_test( struct info *info, enum api function, unsigned int line ok_(__FILE__,line)(info->test[info->index].function == function, "unexpected function %u, expected %u. probably some notifications were missing\n", info->test[info->index].function, function); + info->last_thread_id = 0xdeadbeef; + info->last_status = 0xdeadbeef; }
static void end_test( struct info *info, unsigned int line ) @@ -597,6 +604,8 @@ static void test_async( void ) ok(err == ERROR_SUCCESS || err == ERROR_IO_PENDING || broken(err == 0xdeadbeef) /* < win7 */, "got %u\n", err);
WaitForSingleObject( info.wait, INFINITE ); + ok(info.last_status == WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE, "got status %#x.\n", status); + ok(info.last_thread_id == GetCurrentThreadId(), "expected synchronous callback.\n");
setup_test( &info, winhttp_read_data, __LINE__ ); ret = WinHttpReadData( req, buffer, sizeof(buffer), NULL );
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=96217
Your paranoid android.
=== w7u_2qxl (32 bit report) ===
winhttp: notification.c:608: Test failed: expected synchronous callback.
=== w7u_adm (32 bit report) ===
winhttp: notification.c:608: Test failed: expected synchronous callback.
=== w7u_el (32 bit report) ===
winhttp: notification.c:608: Test failed: expected synchronous callback.
=== w8adm (32 bit report) ===
winhttp: notification.c:239: Test failed: failed to send request 12007 notification.c:241: Test failed: unexpected function 3, expected 4. probably some notifications were missing notification.c:243: Test failed: failed to receive response 12019 notification.c:247: Test failed: failed unexpectedly 12019 notification.c:248: Test failed: request failed unexpectedly 2147344384 notification.c:251: Test failed: unexpected function 3, expected 13. probably some notifications were missing notification.c:111: Test failed: 251: expected status 0x00000002 got 0x00000800 notification.c:112: Test failed: 251: expected function 3 got 13
=== debiant2 (32 bit report) ===
winhttp: notification.c:111: Test failed: 772: expected status 0x00080000 got 0x00200000
=== debiant2 (32 bit Arabic:Morocco report) ===
winhttp: notification.c:111: Test failed: 772: expected status 0x00080000 got 0x00200000
=== debiant2 (32 bit German report) ===
winhttp: notification.c:111: Test failed: 772: expected status 0x00080000 got 0x00200000
=== debiant2 (32 bit French report) ===
winhttp: notification.c:111: Test failed: 772: expected status 0x00080000 got 0x00200000
=== debiant2 (32 bit Hebrew:Israel report) ===
winhttp: notification.c:111: Test failed: 772: expected status 0x00080000 got 0x00200000
=== debiant2 (32 bit Hindi:India report) ===
winhttp: notification.c:111: Test failed: 772: expected status 0x00080000 got 0x00200000
=== debiant2 (32 bit Japanese:Japan report) ===
winhttp: notification.c:111: Test failed: 772: expected status 0x00080000 got 0x00200000
=== debiant2 (32 bit Chinese:China report) ===
winhttp: notification.c:111: Test failed: 772: expected status 0x00080000 got 0x00200000
=== debiant2 (32 bit WoW report) ===
winhttp: notification.c:111: Test failed: 772: expected status 0x00080000 got 0x00200000
=== debiant2 (64 bit WoW report) ===
winhttp: notification.c:111: Test failed: 772: expected status 0x00080000 got 0x00200000
Fixes eFootball PES 2021 in game contents download.
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/winhttp/request.c | 6 ++++-- dlls/winhttp/tests/notification.c | 3 +++ 2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c index b1223d89060..93b39fa0d72 100644 --- a/dlls/winhttp/request.c +++ b/dlls/winhttp/request.c @@ -2930,6 +2930,7 @@ BOOL WINAPI WinHttpReadData( HINTERNET hrequest, LPVOID buffer, DWORD to_read, L { DWORD ret; struct request *request; + BOOL async;
TRACE("%p, %p, %d, %p\n", hrequest, buffer, to_read, read);
@@ -2945,7 +2946,8 @@ BOOL WINAPI WinHttpReadData( HINTERNET hrequest, LPVOID buffer, DWORD to_read, L return FALSE; }
- if (request->connect->hdr.flags & WINHTTP_FLAG_ASYNC) + if ((async = request->connect->hdr.flags & WINHTTP_FLAG_ASYNC) && !end_of_read_data( request ) + && !query_data_ready( request )) { struct read_data *r;
@@ -2962,7 +2964,7 @@ BOOL WINAPI WinHttpReadData( HINTERNET hrequest, LPVOID buffer, DWORD to_read, L free( r ); } } - else ret = read_data( request, buffer, to_read, read, FALSE ); + else ret = read_data( request, buffer, to_read, read, async );
release_object( &request->hdr ); SetLastError( ret ); diff --git a/dlls/winhttp/tests/notification.c b/dlls/winhttp/tests/notification.c index e4d3912d2f6..9b6713e862f 100644 --- a/dlls/winhttp/tests/notification.c +++ b/dlls/winhttp/tests/notification.c @@ -613,6 +613,9 @@ static void test_async( void )
WaitForSingleObject( info.wait, INFINITE );
+ ok(info.last_status == WINHTTP_CALLBACK_STATUS_READ_COMPLETE, "got status %#x.\n", status); + ok(info.last_thread_id == GetCurrentThreadId(), "expected synchronous callback.\n"); + setup_test( &info, winhttp_close_handle, __LINE__ ); WinHttpCloseHandle( req ); WinHttpCloseHandle( con );
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=96218
Your paranoid android.
=== w7u_2qxl (32 bit report) ===
winhttp: notification.c:608: Test failed: expected synchronous callback. notification.c:617: Test failed: expected synchronous callback.
=== w7u_adm (32 bit report) ===
winhttp: notification.c:608: Test failed: expected synchronous callback. notification.c:617: Test failed: expected synchronous callback.
=== w7u_el (32 bit report) ===
winhttp: notification.c:608: Test failed: expected synchronous callback. notification.c:617: Test failed: expected synchronous callback.
=== w8adm (32 bit report) ===
winhttp: notification.c:239: Test failed: failed to send request 12007 notification.c:241: Test failed: unexpected function 3, expected 4. probably some notifications were missing notification.c:243: Test failed: failed to receive response 12019 notification.c:247: Test failed: failed unexpectedly 12019 notification.c:248: Test failed: request failed unexpectedly 2147348480 notification.c:251: Test failed: unexpected function 3, expected 13. probably some notifications were missing notification.c:111: Test failed: 251: expected status 0x00000002 got 0x00000800 notification.c:112: Test failed: 251: expected function 3 got 13
=== debiant2 (32 bit report) ===
winhttp: notification.c:111: Test failed: 775: expected status 0x00080000 got 0x00200000
=== debiant2 (32 bit Arabic:Morocco report) ===
winhttp: notification.c:111: Test failed: 775: expected status 0x00080000 got 0x00200000
=== debiant2 (32 bit German report) ===
winhttp: notification.c:111: Test failed: 775: expected status 0x00080000 got 0x00200000
=== debiant2 (32 bit French report) ===
winhttp: notification.c:111: Test failed: 775: expected status 0x00080000 got 0x00200000
=== debiant2 (32 bit Hebrew:Israel report) ===
winhttp: notification.c:111: Test failed: 775: expected status 0x00080000 got 0x00200000
=== debiant2 (32 bit Hindi:India report) ===
winhttp: notification.c:111: Test failed: 775: expected status 0x00080000 got 0x00200000
=== debiant2 (32 bit Japanese:Japan report) ===
winhttp: notification.c:111: Test failed: 775: expected status 0x00080000 got 0x00200000
=== debiant2 (32 bit Chinese:China report) ===
winhttp: notification.c:111: Test failed: 775: expected status 0x00080000 got 0x00200000
=== debiant2 (32 bit WoW report) ===
winhttp: notification.c:111: Test failed: 775: expected status 0x00080000 got 0x00200000
=== debiant2 (64 bit WoW report) ===
winhttp: notification.c:111: Test failed: 775: expected status 0x00080000 got 0x00200000