Upon receiving a suspend event, the WinHttp provider will automatically tear down any active WebSocket connections. Depending on the current state of the connection, the suspend handler will either call WinHttpWebSocketClose followed by WinHttpCloseHandle, or just call WinHttpCloseHandle directly. If we receive a WinHttp disconnect callback at the same time, the disconnect handler will call WinHttpCloseHandle. This leads to race condition between the two handlers:
If the suspend handler runs first and determines that it needs to call WinHttpWebSocketClose (because at that point we believe the WebSocket is still connected) and then the disconnect handler runs and calls WinHttpCloseHandle BEFORE the suspend handler actually calls WinHttpWebSocketClose, the WinHttp handle may be in an invalid state when WebSocketClose finally gets called, leading to a crash.
The fix here involves a couple things. First, I updated the suspend handler to forego the call to WinHttpWebSocketClose altogether. This means that during suspend the WebSocket won't be torn down gracefully, but it greatly simplifies the LHC teardown process. Second, there is some additional logic needed to make sure that LHC still raises a disconnected event to clients during suspend, as the flow will change slightly with the removal of the WinHttpWebSocketClose call.
This change also contains a fix for a debug assert due to buffer size in FormatTrace
* Adding Zlib from Source to Apple LHC
* Adding Compression API to exp files
* Adding ifdef to pch_common.h
* Subtle bug in new build guards
* Replacing iOS and MAC build guards for HC_PLATFORM_IS_APPLE
* Isolating Zlib warnings to specific files
* Fixing Targets with corresponding compiler flags
* Excluding one least warning treated as error
---------
Co-authored-by: raulalbertog <raulalbertog@microsoft.com>
* Initial changes
* Fix unknown override specifier errors
* GZIP Integration with Win32 and GDK
* Adding support for 2019
* Restoring Win32 Sample app
* Removing unnecessary include
* Excluding ZLib on props files
* Managing ZLib source compilation in props files
* Fixing variable redeclaration
* Addressing PR Feedback Pt1
* Pointing to v1.3 commit
* Addressing PR Feedback pt2
* Enabling compression through read body callback
* Addressing PR Feedback
* Minor changes
* Addressing PR Feedback
* Removing extra buffer in compress function
* Minor mistake in compression header
* Removing unnecessary buffer when reading body
* Moving compression from Common to HTTP
* Removing loop and reading whole body at once
---------
Co-authored-by: Raul Gomez Rodriguez <raulalbertog@microsoft.com>
* Import GDK bwoi props file prior to using VCTargetsPath as that gets changed when 'GDKUseBWOI' is set
* Define _DEBUG macro for debug builds to avoid linker errors when building XSAPI
At a high level, the goal of these changes is to restructure the code and project files to better allow for extending libHttpClient to new platforms, including platforms that require an NDA and need to be maintained outside of the public github repository. Specific changes in this pull request include:
* Added IHttpProvider and IWebSocketProvider interfaces which platform specific implementations of HTTP and WebSockets must implement.
* Added PlatformComponents struct and PlatformInitialize method which each platform must implement. Those implementations can easily exist outside the primary github repository without modification to existing source.
* Removal of the HC_PERFORM_ENV class which acted as a context object for all of the in-box HTTP and WebSocket providers. It had gotten extremely messy and required updating for new platforms. This was replaced by the NetworkState class, which does a lot of the same things, but it contains no platform specific code. Rather than having hard-coded HTTP and WebSocket hooks for each platform, it is initialized with an IHttpProvider and IWebSocketProvider during HCInitialize.
* Refactoring of props files in the /Build directory. A libHttpClient.[platform].props file was added for each supported platform. These props files define the platform specific default build configuration and will be imported by each project targeting that platform.
* Refactoring visual studio project files and removal of the CMake + ProjectFileProcessor utility that was used to generate the project files. That system has been replaced by a much more modular build system which breaks source files required for multiple projects into .vcxitems projects. The .vcxproj files end up being very minimal, referencing the appropriate .props files and .vcxitems projects based on the platform they target.
* Some minor cleanup and code refactoring including addition of internal types.h header and dependency on std::optional in Result<T> class
* Dropped support for the XDK platform as well as visual studio 2015. Additionally the visual studio 2017 .sln was removed, but the projects building with platform toolset 141 were maintained and can still be used if needed.
CurlMulti creates a composite work queue and schedules work to that queue as long as there are outstanding HTTP requests. During cleanup, CurlMulti will terminate its queue, effectively cancelling all ongoing requests. However, if there are no ongoing requests at the time of cleanup, there is no guarantee that the client will still be dispatching the queue, which is required to fully terminate a queue. To fix this I've done two things:
1. Only terminate the queue if there are ongoing requests. If there are no ongoing requests, we're guaranteed to have no remaining callbacks pending on the queue, so termination is unnecessary.
2. When terminating the queue, don't await a queue terminated callback. This avoids a potential race condition where the client stops dispatching the queue after they've gotten a completion callback for the final HTTP request but before they've dispatched the queue terminated callback.
I also added some additional verbose logging to help diagnose future cleanup issues.
* Add Linux build files and configure files to support LibHttpClient Linux
* resolving comments
Removed extern structs in .h file and moved them up where they were in pch_common to ensure they are defined properly
* added templates
* Update x509_cert_utilities.hpp
* Update x509_cert_utilities.hpp
change check to something defined by us
* Update x509_cert_utilities.hpp
fix error in pipeline where there are errors of an unused function.
* Update x509_cert_utilities.hpp
use elif and corrected to use else
* Update CurlEasyRequest.cpp
Fix to handle behavioral differences with cURL and XcURL
* Update CurlEasyRequest.cpp
have this be a fix/workaround for xCurl
---------
Co-authored-by: SebastianPD-XB <sebastianp@microsoft.com>
* Add Linux build files and configure files to support LibHttpClient Linux
* resolving comments
Removed extern structs in .h file and moved them up where they were in pch_common to ensure they are defined properly
* added templates
* Update x509_cert_utilities.hpp
* Update x509_cert_utilities.hpp
change check to something defined by us
* Update x509_cert_utilities.hpp
fix error in pipeline where there are errors of an unused function.
* Update x509_cert_utilities.hpp
use elif and corrected to use else
---------
Co-authored-by: SebastianPD-XB <sebastianp@microsoft.com>
When creating a std::shared_ptr<> from a raw pointer, we need to pass in both a custom deleter and allocator. Though the object itself is already allocated, std::shared_ptr<> allocates some internal data on top of that.
More details here: https://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr.
This PR fixes a few different bugs in the WinHttp WebSocket stack:
1) The most severe bug is related to situations where WinHttpSendRequest fails synchronously. This can happen for a variety of reasons, though it does not seem to be consistent. According to msdn docs, (https://learn.microsoft.com/en-us/windows/win32/api/winhttp/nf-winhttp-winhttpsendrequest) "even when WinHTTP is used in asynchronous mode, that is, when WINHTTP_FLAG_ASYNC has been set in [WinHttpOpen](https://learn.microsoft.com/en-us/windows/desktop/api/winhttp/nf-winhttp-winhttpopen), this function can operate either synchronously or asynchronously." In our code, if the WinHttpSendRequest call failed synchronously, we'd clean up the WinHttp callback context which we still expected to exist to handle other WinHttp events (i.e. WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING) resulting in us accessing an invalid pointer. The fix is to release ownership of the callback context after WinHttpSetStatusCallback (rather than after WinHttpSendRequest).
2) The second bug that was in some error paths of HCWebSocketConnectAsync, the WinHttpCloseHandle never happens, nor is our WinHttp callback context ever cleaned up. The fix is to call StartWinHttpClose from WinHttpConnection::complete_task if the WebSocket Connect has fails. In cases where it succeeds, cleanup works correctly but doesn't take place until the WebSocket is later disconnected. This bug doesn't result in any crash, but does leak WinHttp handles and associated LHC context in some cases.
3) The final bug is that in some cases the client's WebSocket disconnect handler may be invoked multiple times. In some cases WinHttp can raise multiple error events (WINHTTP_CALLBACK_STATUS_REQUEST_ERROR), but we should only notify the client of a disconnect once. The fix is to add a flag to track whether we've already called the disconnect handler, and ignore subsequent WinHttp errors. This also doesn't cause any crashes, but could cause issues depending on how clients handle the disconnect event being fired multiple times.
* Use okhttp for websockets on android
* empty commit to re-trigger build pipelines
Co-authored-by: Jason Sandlin <jasonsa@microsoft.com>
Co-authored-by: Sahil <saashar@microsoft.com>
* Re-classifying NO_NETWORK to be only UnknownHostException
At some point recently various socket exceptions started getting classified as "isNoNetworkFailure". While this was intended to be helpful classification, the resulting behavior is that on a socket exception, retry logic will not get engaged. This is because retry logic does not attempt to retry if there is no network in order to save from repeatedly waiting when there isn't a reason to wait. This behavior change was not good or intended so I am reverting it.