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 --- v2: - fix test for Win7; - set last error to reflect actual async status.
dlls/winhttp/request.c | 9 ++++++--- dlls/winhttp/tests/notification.c | 11 +++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c index b8f5817737e..03f895a7fdb 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;
@@ -2902,12 +2904,13 @@ BOOL WINAPI WinHttpQueryDataAvailable( HINTERNET hrequest, LPDWORD available ) release_object( &request->hdr ); free( q ); } + else ret = ERROR_IO_PENDING; } - else ret = query_data_available( request, available, FALSE ); + else ret = query_data_available( request, available, async );
release_object( &request->hdr ); SetLastError( ret ); - return !ret; + return !ret || ret == ERROR_IO_PENDING; }
static void CALLBACK task_read_data( TP_CALLBACK_INSTANCE *instance, void *ctx, TP_WORK *work ) diff --git a/dlls/winhttp/tests/notification.c b/dlls/winhttp/tests/notification.c index 98e4024867f..7d1bfa78a49 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,10 @@ 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((err == ERROR_SUCCESS && info.last_thread_id == GetCurrentThreadId()) + || (err == ERROR_IO_PENDING && info.last_thread_id != GetCurrentThreadId()), + "Got unexpected thread %#x, err %#x.\n", info.last_thread_id, err);
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=96246
Your paranoid android.
=== debiant2 (32 bit report) ===
winhttp: notification.c:111: Test failed: 774: expected status 0x00080000 got 0x00200000
=== debiant2 (32 bit Arabic:Morocco report) ===
winhttp: notification.c:111: Test failed: 774: expected status 0x00080000 got 0x00200000
=== debiant2 (32 bit German report) ===
winhttp: notification.c:111: Test failed: 774: expected status 0x00080000 got 0x00200000
=== debiant2 (32 bit French report) ===
winhttp: notification.c:111: Test failed: 774: expected status 0x00080000 got 0x00200000
=== debiant2 (32 bit Hebrew:Israel report) ===
winhttp: notification.c:111: Test failed: 774: expected status 0x00080000 got 0x00200000
=== debiant2 (32 bit Hindi:India report) ===
winhttp: notification.c:111: Test failed: 774: expected status 0x00080000 got 0x00200000
=== debiant2 (32 bit Japanese:Japan report) ===
winhttp: notification.c:111: Test failed: 774: expected status 0x00080000 got 0x00200000
=== debiant2 (32 bit Chinese:China report) ===
winhttp: notification.c:111: Test failed: 774: expected status 0x00080000 got 0x00200000
=== debiant2 (32 bit WoW report) ===
winhttp: notification.c:111: Test failed: 774: expected status 0x00080000 got 0x00200000
=== debiant2 (64 bit WoW report) ===
winhttp: notification.c:111: Test failed: 774: expected status 0x00080000 got 0x00200000
Signed-off-by: Hans Leidekker hans@codeweavers.com
Fixes eFootball PES 2021 in game contents download.
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- v2: - fix test for Win7; - set last error to reflect actual async status.
dlls/winhttp/request.c | 9 ++++++--- dlls/winhttp/tests/notification.c | 5 +++++ 2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c index 03f895a7fdb..001fff74a87 100644 --- a/dlls/winhttp/request.c +++ b/dlls/winhttp/request.c @@ -2931,6 +2931,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);
@@ -2946,7 +2947,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,12 +2964,13 @@ BOOL WINAPI WinHttpReadData( HINTERNET hrequest, LPVOID buffer, DWORD to_read, L release_object( &request->hdr ); free( r ); } + else ret = ERROR_IO_PENDING; } - 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 ); - return !ret; + return !ret || ret == ERROR_IO_PENDING; }
static DWORD write_data( struct request *request, const void *buffer, DWORD to_write, DWORD *written, BOOL async ) diff --git a/dlls/winhttp/tests/notification.c b/dlls/winhttp/tests/notification.c index 7d1bfa78a49..4cfffe6687e 100644 --- a/dlls/winhttp/tests/notification.c +++ b/dlls/winhttp/tests/notification.c @@ -615,6 +615,11 @@ static void test_async( void )
WaitForSingleObject( info.wait, INFINITE );
+ ok(info.last_status == WINHTTP_CALLBACK_STATUS_READ_COMPLETE, "got status %#x.\n", status); + ok((err == ERROR_SUCCESS && info.last_thread_id == GetCurrentThreadId()) + || (err == ERROR_IO_PENDING && info.last_thread_id != GetCurrentThreadId()), + "Got unexpected thread %#x, err %#x.\n", info.last_thread_id, err); + 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=96247
Your paranoid android.
=== debiant2 (32 bit report) ===
winhttp: notification.c:111: Test failed: 779: expected status 0x00080000 got 0x00200000
=== debiant2 (32 bit Arabic:Morocco report) ===
winhttp: notification.c:111: Test failed: 779: expected status 0x00080000 got 0x00200000
=== debiant2 (32 bit German report) ===
winhttp: notification.c:111: Test failed: 779: expected status 0x00080000 got 0x00200000
=== debiant2 (32 bit French report) ===
winhttp: notification.c:111: Test failed: 779: expected status 0x00080000 got 0x00200000
=== debiant2 (32 bit Hebrew:Israel report) ===
winhttp: notification.c:111: Test failed: 779: expected status 0x00080000 got 0x00200000
=== debiant2 (32 bit Hindi:India report) ===
winhttp: notification.c:111: Test failed: 779: expected status 0x00080000 got 0x00200000
=== debiant2 (32 bit Japanese:Japan report) ===
winhttp: notification.c:111: Test failed: 779: expected status 0x00080000 got 0x00200000
=== debiant2 (32 bit Chinese:China report) ===
winhttp: notification.c:111: Test failed: 779: expected status 0x00080000 got 0x00200000
=== debiant2 (32 bit WoW report) ===
winhttp: notification.c:111: Test failed: 779: expected status 0x00080000 got 0x00200000
=== debiant2 (64 bit WoW report) ===
winhttp: notification.c:111: Test failed: 779: expected status 0x00080000 got 0x00200000
Signed-off-by: Hans Leidekker hans@codeweavers.com