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.
--
https://gitlab.winehq.org/wine/wine/-/merge_requests/1582
I'm not sure what's the best way of registering print processor. The alternative is to register winprint in winspool when driver is added.
--
v2: winprint: Register winprint print processor.
https://gitlab.winehq.org/wine/wine/-/merge_requests/1685
Implement a basic GC based on the mark-and-sweep algorithm, without requiring manually specifying "roots", which vastly simplifies the management. For now, it is triggered every 30 seconds since it last finished, on a new object initialization. Better heuristics could be used in the future.
The comments in the code should hopefully understand the high level logic of this approach without boilerplate details. I've tested it on FFXIV launcher (along with other patches from Proton to have it work) and it stops the massive memory leak successfully by itself, so at least it does its job properly. The last patch in the MR is just an optimization for a *very* common case.
For artificial testing, one could use something like:
```javascript
function leak() {
var a = {}, b = {};
a.b = b;
b.a = a;
}
```
which creates a circular ref and will leak when the function returns.
It also introduces and makes use of a "heap_stack", which prevents stack overflows on long chains.
--
v3: jscript: Create the source function's 'prototype' prop object on demand.
jscript: Run the garbage collector every 30 seconds on a new object
jscript: Implement CollectGarbage().
jscript: Implement a Garbage Collector to deal with circular references.
https://gitlab.winehq.org/wine/wine/-/merge_requests/1635