On windows and systems where wxUSE_EVENTLOOP_SOURCE is 1, it is
possible to monitor socket descriptors for activity from the main
thread. The SocketPoller class used with wxWebSessionCURL is modified
to use an implementation class that does so.
On windows, the implementation uses the winsock1 function
WSAAsyncSelect to send events to wxWebSessionCURL when activity is
detected. When wxUSE_EVENTLOOP_SOURCE is 1, a wxEventLoopSource is used
to monitor for socket activity. The event loop source is given a custom
wxEventLoopSourceHandler object to send the necessary event.
Previously wxWebRequestCURL objects were canceled by removing their
CURL easy handle from the CURLM multihandle. Unfortunately the really
only pauses the connection and does not truly cancel it. This commit
tries to stop the transfer by retrieving the active socket from the CURL
handle for the transfer and closing it.
There are some complications in doing this because the option curl uses
to get the socket have changed over the years. A combination of compile
time and run time checks are used to use the appropriate options to get
the socket. However in the case of 64bit windows using a curl version
older than 7.45.0 simply won’t have an usable option. In this case,
it seems nothing can be done.
At various points in a transfer being managed by the wxWebSessionCURL
class we need to perform operations on a wxWebRequestCURL object.
However it’s possible for the request object to be deleted while the
transfer is in progress.
To ensure that the request objects are valid, keep track of the request
objects with a hash map. Objects are added to the map when a transfer is
started and removed when the transfer is complete or in the request’s
destructor.
Currently for wxWebRequestCURL objects using memory storage, a download
is processed by appending to a wxMemoryBuffer each time the write
callback is called. For a large transfer, this can result in many, many
reallocation calls and can block the main application.
This commit uses the progress callback for wxWebRequestCURL objects
added in a previous commit to set a minimum size for the buffer as soon
as it is known.
This commit adds a progress callback for use with wxWebRequestCURL
objects. This has some complications because over the years curl has
changed the signature of the callback.
A combination of compile-time and run-time checks is used to make sure
the appropriate callback and preferred return value are used.
Instead of having wxWebSessionCURL run a worker thread that uses curl
to monitor and process network activity, set up a separate socket
poller class to monitor socket activity. The socket poller class will
throw an event back to wxWebSessionCURL when it detects activity on the
sockets so that it can tell curl to process the activity in the main
thread.
Under MSW, don't set the state to State_Cancelled as soon as Cancel()
was called, as the request was still used from the other threads
afterwards, resulting in race conditions and crashes.
Fix this by just removing the SetState(State_Cancelled) call from the
main thread, as it was redundant anyhow. This also makes the behaviour
correspond to the documentation, which indicates that Cancel() works
asynchronously.
Also ensure, for all backends, that we actually cancel the request only
once, even if public Cancel() is called multiple times. This required
renaming the existing wxWebRequestImpl::Cancel() to DoCancel().
It's better not to have this method in the public class, even if it
means that we need to pass a wxWebSessionImpl object to wxWebRequestImpl
ctor explicitly now.
No real changes.
It's up to the application code to decide how it handles the HTTP status
codes it gets back from server, there is no need to have a special
method for handling them in wxWebRequest itself.
We also shouldn't skip downloading the response body just because it was
unsuccessful, we may still need it (e.g. it's very common to return the
detailed error description in a JSON object in the message body when
returning some 4xx error), so don't do it in wxMSW implementation and
add a test verifying that we still get the expected body even for an
error status.
Also improve wxWebRequest::State values documentation.
At least in one place the code is still wrong when sending data as HTTP
headers can contain only ASCII characters, but at least do our best to
interpret the data we receive correctly.
Don't just silently ignore invalid user data value, this is not supposed
to happen.
Also use "userdata" name for the same parameter of all callbacks
consistently.
As this flag is tested in the worker thread only when it owns the mutex,
set it only after acquiring the mutex too to avoid any possibility of a
data race.
Call SetState(State_Active) before signalling the worker thread, as
otherwise it would be possible for it to wake up and set its state to
something else before it was reset to "active" from the main thread.
This fixed another TSAN error.
Mutexes must not be destroyed while locked and thread sanitizer
correctly complains about this, so ensure that we do unlock the mutex
before the worked thread terminates and the object is destroyed.
Also use critical section instead of a mutex, as this is more efficient
under MSW.
Main purpose of this commit is to make it clear that this mutex/critical
section is only used together with the data from the same struct.
No real changes.
Check that current state is State_Idle in wxWebRequest itself only once
instead of doing it in 2 (out of 3) wxWebRequestImpl implementations.
Also assert if this is not the case instead of silently doing nothing
which would surely be more difficult to debug.
Don't force the application code to deal with wxObjectDataPtr<> or,
worse, calling {Inc,Dec}Ref() manually by hiding it inside the wx
objects themselves and giving the value-like semantics to them.
There should be no real changes in the behaviour, but the API does
change significantly. Notably, wxWebRequest is not a wxEvtHandler itself
any longer, as this would be incompatible with the value semantics, and
an event handler needs to be specified when creating it, so that it
could be notified about the request state changes.
Using anything else is not recommended by libcurl documentation and it's
not clear why would we need it, so just follow the official advice and
pass CURL_GLOBAL_ALL.
This is unnecessary, it can be protected and we can initialize
wxWebRequest::m_headers directly in its ctor instead of using this
function (which also simplifies code and makes it impossible to forget
to do this).
Use BeforeFirst() when we only need to find the first colon instead of
wxSplit().
No real changes (except for pathological case when there is no colon at
all, which wasn't handled correctly by the original code and still
isn't, but in a slightly different way).
The former can be called from the derived class ctors while the latter
only needs to be called from wxWebRequest itself, so just make it a
friend: this is not ideal, but still better than leaving this public and
simpler than any alternatives.
Support older versions might be useful for older
linux distributions and could be used as a
possible fallback to macOS URLSession implementation
on macOS 10.7 and 10.8.