// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "Interfaces/IHttpBase.h" class IHttpRequest; class IHttpResponse; /** * Enumerates thread policy about which thread to complete the http request */ enum class EHttpRequestDelegateThreadPolicy : uint8 { CompleteOnGameThread = 0, CompleteOnHttpThread, }; class IHttpRequest; class IHttpResponse; typedef TSharedPtr FHttpRequestPtr; typedef TSharedPtr FHttpResponsePtr; typedef TSharedRef FHttpRequestRef; typedef TSharedRef FHttpResponseRef; /** * Delegate called when an Http request completes * * @param Request original Http request that started things * @param Response response received from the server if a successful connection was established. Note that * even if response is not null, it doesn't mean the request was processed successfully. Use * Response->GetStatus(), Response->GetFailureReason() and Response->GetResponseCode() to decide * how to handle it * @param bProcessedSuccessfully this flag indicates whether or not the request was able to be processed successfully. * It could be connect error, timeout error or platform http error. Note that when this flag is true * doesn't mean the http request get 2xx success status code, it just means this request got response * from http server and completed the processing */ using FHttpRequestCompleteDelegate = TTSDelegate; /** * Delegate called when an Http request receives status code * * @param Request original Http request that started things * @param status code */ using FHttpRequestStatusCodeReceivedDelegate = TTSDelegate; /** * Delegate called when an Http request receives a header * * @param Request original Http request that started things * @param HeaderName the name of the header * @param NewHeaderValue the value of the header */ using FHttpRequestHeaderReceivedDelegate = TTSDelegate; /** * Delegate called per tick to update an Http request upload or download size progress * * @param Request original Http request that started things * @param BytesSent the number of bytes sent / uploaded in the request so far. * @param BytesReceived the number of bytes received / downloaded in the response so far. */ using FHttpRequestProgressDelegate = TTSDelegate; /** * Delegate called per tick to update an Http request upload or download size progress * * @param Request original Http request that started things * @param BytesSent the number of bytes sent / uploaded in the request so far. * @param BytesReceived the number of bytes received / downloaded in the response so far. */ using FHttpRequestProgressDelegate64 = TTSDelegate; /** * Delegate called when an Http request will be retried in the future * * @param Request - original Http request that started things * @param Response - response received from the server if a successful connection was established * @param SecondsToRetry - seconds in the future when the response will be retried */ using FHttpRequestWillRetryDelegate = TTSDelegate; /** * Delegate called when an Http request will send/recv data through stream * * @param Ptr - The buffer ptr to read/write * @param Length - The length of buffer to read/write * @return true if succeed, false if failed to read/write data */ using FHttpRequestStreamDelegate = TTSDelegate; /** * Delegate called when an Http request will send/recv data through stream * * @param Ptr - The buffer ptr to read/write * @param InOutLength - The int64 reference length of buffer to read/write, if there is any error when serialize set it to 0 */ using FHttpRequestStreamDelegateV2 = TTSDelegate; /** * Delegate version of FArchive, for streaming interface */ class UE_DEPRECATED(5.5, "FArchiveWithDelegate is deprecated and will be moved to internal") FArchiveWithDelegate final : public FArchive { public: FArchiveWithDelegate(FHttpRequestStreamDelegate InStreamDelegate) : StreamDelegate(InStreamDelegate) { } virtual void Serialize(void* V, int64 Length) override { if (!StreamDelegate.IsBound() || !StreamDelegate.Execute(V, Length)) { SetError(); } } private: FHttpRequestStreamDelegate StreamDelegate; }; /** * Options that can be specified on a Http Request */ namespace HttpRequestOptions { static const FName HttpVersion("HttpVersion"); #if UE_HTTP_SUPPORT_UNIX_SOCKET static const FName UnixSocketPath("UnixSocketPath"); #endif //UE_HTTP_SUPPORT_UNIX_SOCKET } /** * Interface for Http requests (created using FHttpFactory) */ class IHttpRequest : public IHttpBase, public TSharedFromThis { public: /** * Gets the verb (GET, PUT, POST) used by the request. * * @return the verb string */ virtual FString GetVerb() const = 0; /** * Sets the verb used by the request. * Eg. (GET, PUT, POST) * Should be set before calling ProcessRequest. * If not specified then a GET is assumed. * * @param Verb - verb to use. */ virtual void SetVerb(const FString& Verb) = 0; /** * Sets the URL for the request * Eg. (http://my.domain.com/something.ext?key=value&key2=value). * Must be set before calling ProcessRequest. * * @param URL - URL to use. */ virtual void SetURL(const FString& URL) = 0; /** * Get the current value for the given option * * @return the current value set for this option or an empty string if no value has been specified */ virtual FString GetOption(const FName Option) const = 0; /** * Sets the given option for this Request * Must be set before calling ProcessRequest. * * @param Option - The option to set, see 'HttpRequestOptions' for supported options * @param OptionValue - The value of the option to set */ virtual void SetOption(const FName Option, const FString& OptionValue) = 0; /** * Sets the content of the request (optional data). * Usually only set for POST requests. * * @param ContentPayload - payload to set. */ virtual void SetContent(const TArray& ContentPayload) = 0; /** * Sets the content of the request (optional data). * Usually only set for POST requests. * * This version lets the API take ownership of the payload directly, helpful for larger payloads. * * @param ContentPayload - payload to set. */ virtual void SetContent(TArray&& ContentPayload) = 0; /** * Sets the content of the request as a string encoded as UTF8. * * @param ContentString - payload to set. */ virtual void SetContentAsString(const FString& ContentString) = 0; /** * Sets the content of the request to stream from a file. * * @param FileName - filename from which to stream the body. * @return True if the file is valid and will be used to stream the request. False otherwise. */ virtual bool SetContentAsStreamedFile(const FString& Filename) = 0; /** * Sets the content of the request to stream directly from an archive. * NOTE: The Stream->Serialize will be called from another thread other than the game thread * * @param Stream - archive from which the payload should be streamed. * @return True if the archive can be used to stream the request. False otherwise. */ virtual bool SetContentFromStream(TSharedRef Stream) = 0; /** * Sets the content of the request to stream directly from an delegate. * NOTE: * - The delegate will be called from another thread other than the game thread, make sure * it's thread-safe in there * - Make sure the delegate is safe to be called until receiving the process complete callback * or after canceling the request * @param StreamDelegate - delegate from which the payload should be streamed. * @return True if the delegate can be used to stream the request. False otherwise. */ UE_DEPRECATED(5.5, "SetContentFromStreamDelegate has been deprecated and will not be supported because there is no seek support through delegate. Implement your own FArchive instead.") bool SetContentFromStreamDelegate(FHttpRequestStreamDelegate StreamDelegate); /** * Sets the stream to receive the response body. Make sure to handle the cleanup of stream when * Serialize generated error(Stream->GetError returns true after Stream->Serialize call), this * http request will fail and quit. * * NOTE: Once set, the data will no longer be cached in response, IHttpResponse::GetContent() and * IHttpResponse::GetContentAsString() will return empty result. The Stream->Serialize will be called * from another thread other than the game thread * * @param Stream - will be used to receive the response body * @return True if the stream can be used. False otherwise. */ virtual bool SetResponseBodyReceiveStream(TSharedRef Stream) = 0; /** * Sets the delegate to receive the response body. Make sure to handle the cleanup of received data when * failed to process the data(StreamDelegate return false), this http request will fail and quit. * * NOTE: Once set, the data will no longer be cached in response, IHttpResponse::GetContent() and * IHttpResponse::GetContentAsString() will return empty result. The delegate will be called from * another thread other than the game thread * * @param StreamDelegate - will be used to receive the response body * @return True if the delegate can be used. False otherwise. */ UE_DEPRECATED(5.5, "SetResponseBodyReceiveStreamDelegate has been deprecated, use SetResponseBodyReceiveStreamDelegateV2 instead") HTTP_API bool SetResponseBodyReceiveStreamDelegate(FHttpRequestStreamDelegate StreamDelegate); /** * Sets the delegate to receive the response body. Make sure to handle the cleanup of received data when * failed to process the data(StreamDelegate return false), this http request will fail and quit. * * NOTE: Once set, the data will no longer be cached in response, IHttpResponse::GetContent() and * IHttpResponse::GetContentAsString() will return empty result. The delegate will be called from * another thread other than the game thread * * @param StreamDelegate - will be used to receive the response body * @return True if the delegate can be used. False otherwise. */ HTTP_API bool SetResponseBodyReceiveStreamDelegateV2(FHttpRequestStreamDelegateV2 StreamDelegate); /** * Sets optional header info. * SetHeader for a given HeaderName will overwrite any previous values * Use AppendToHeader to append more values for the same header * Content-Length is the only header set for you. * Required headers depends on the request itself. * Eg. "multipart/form-data" needed for a form post * * @param HeaderName - Name of the header (ie, Content-Type) * @param HeaderValue - Value of the header */ virtual void SetHeader(const FString& HeaderName, const FString& HeaderValue) = 0; /** * Appends to the value already set in the header. * If there is already content in that header, a comma delimiter is used. * If the header is as of yet unset, the result is the same as calling SetHeader * Content-Length is the only header set for you. * Also see: SetHeader() * * @param HeaderName - Name of the header (ie, Content-Type) * @param AdditionalHeaderValue - Value to add to the existing contents of the specified header. * comma is inserted between old value and new value, per HTTP specifications */ virtual void AppendToHeader(const FString& HeaderName, const FString& AdditionalHeaderValue) = 0; /** * Sets an optional timeout in seconds for this entire HTTP request to complete. * If set, this value overrides the default HTTP timeout set via FHttpModule::SetTimeout(). * * @param InTimeoutSecs - Timeout for this HTTP request instance, in seconds */ virtual void SetTimeout(float InTimeoutSecs) = 0; /** * Sets an optional activity timeout in seconds for this HTTP request. After connecting to * web server, if there is no activity(send or receive) happen for this time period, it will * trigger activity timeout * If set, this value overrides the default HTTP activity timeout * * @param InTimeoutSecs - Timeout for this HTTP request instance, in seconds */ virtual void SetActivityTimeout(float InTimeoutSecs) = 0; /** * Clears the optional timeout in seconds for this HTTP request, causing the default value * from FHttpModule::GetTimeout() to be used. */ virtual void ClearTimeout() = 0; /** * Reset the elapsed timeout duration and flag, after the request completed and need to be reused */ virtual void ResetTimeoutStatus() = 0; /** * Gets the optional timeout in seconds for this entire HTTP request to complete. * If valid, this value overrides the default HTTP timeout set via FHttpModule::SetTimeout(). * * @return the timeout for this HTTP request instance, in seconds */ virtual TOptional GetTimeout() const = 0; /** * Called to begin processing the request. * OnProcessRequestComplete delegate is always called when the request completes or on error if it is bound. * A request can be re-used but not while still being processed. * * @return if the request was successfully started. */ virtual bool ProcessRequest() = 0; /** * Delegate called when the request is complete. See FHttpRequestCompleteDelegate */ virtual FHttpRequestCompleteDelegate& OnProcessRequestComplete() = 0; /** * Delegate called to update the request/response progress. See FHttpRequestProgressDelegate64 */ virtual FHttpRequestProgressDelegate64& OnRequestProgress64() = 0; /** * Delegate called when the request will be retried */ virtual FHttpRequestWillRetryDelegate& OnRequestWillRetry() = 0; /** * Delegate called to signal the receipt of a header. See FHttpRequestHeaderReceivedDelegate */ virtual FHttpRequestHeaderReceivedDelegate& OnHeaderReceived() = 0; /** * Delegate called to signal the receipt of a header. See FHttpRequestStatusCodeReceivedDelegate */ virtual FHttpRequestStatusCodeReceivedDelegate& OnStatusCodeReceived() = 0; /** * Called to cancel a request that is still being processed */ virtual void CancelRequest() = 0; /** * Get the associated Response * * @return the response */ virtual const FHttpResponsePtr GetResponse() const = 0; /** * Used to tick the request * * @param DeltaSeconds - seconds since last ticked */ virtual void Tick(float DeltaSeconds) = 0; /** * Gets the time that it took for the server to fully respond to the request. * * @return elapsed time in seconds. */ virtual float GetElapsedTime() const = 0; /** * Set thread policy about which thread to trigger the delegates, set by FHttpManager::SetRequestCompletedDelegate, * IHttpRequest::OnStatusCodeReceived, IHttpRequest::OnHeaderReceived, IHttpRequest::OnRequestProgress64 and IHttpRequest::OnProcessRequestComplete. * * Note that when set it as CompleteOnHttpThread, the thread to trigger delegates could be any thread * depends on the implementation. User code should make the delegate thread-safe and shouldn't assume * it's triggered by the thread where this request get created. * * @param InThreadPolicy - The thread policy to indicate which thread to trigger the delegates */ virtual void SetDelegateThreadPolicy(EHttpRequestDelegateThreadPolicy InThreadPolicy) = 0; /** * Get thread policy about which thread to complete this request * * @return The thread policy */ virtual EHttpRequestDelegateThreadPolicy GetDelegateThreadPolicy() const = 0; /** * Blocking call to wait the request until it's completed * * WARNINGS: * * - This is a blocking call, DON'T use this in a time-sensitive context * - Complete delegate will be used in this function so customized complete delegate is not supported * - This will force the usage of EHttpRequestDelegateThreadPolicy::CompleteOnHttpThread to make sure the * request can complete, when this function get called from main thread. So if any other delegate is * bound, make sure the bound delegate can handle the custom logic in a thread-safe way */ virtual void ProcessRequestUntilComplete() = 0; /** * Destructor for overrides */ virtual ~IHttpRequest() = default; };