Files
UnrealEngine/Engine/Source/Runtime/Online/HTTP/Private/Apple/AppleHttp.h
2025-05-18 13:04:45 +08:00

215 lines
6.3 KiB
Objective-C

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "GenericPlatform/HttpResponseCommon.h"
#include "GenericPlatform/HttpRequestCommon.h"
#include "PlatformHttp.h"
#include "HttpPackage.h"
#include "Misc/TVariant.h"
/**
* Delegate invoked when in progress Task completes. It is invoked in an out of our control thread
*
*/
DECLARE_DELEGATE(FNewAppleHttpEventDelegate);
/**
* Apple implementation of an Http request
*/
class FAppleHttpRequest : public FHttpRequestCommon
{
public:
// implementation friends
friend class FAppleHttpResponse;
//~ Begin IHttpBase Interface
virtual FString GetHeader(const FString& HeaderName) const override;
virtual TArray<FString> GetAllHeaders() const override;
virtual FString GetContentType() const override;
virtual uint64 GetContentLength() const override;
virtual const TArray<uint8>& GetContent() const override;
//~ End IHttpBase Interface
//~ Begin IHttpRequest Interface
virtual FString GetVerb() const override;
virtual void SetVerb(const FString& Verb) override;
virtual void SetContent(const TArray<uint8>& ContentPayload) override;
virtual void SetContent(TArray<uint8>&& ContentPayload) override;
virtual void SetContentAsString(const FString& ContentString) override;
virtual bool SetContentAsStreamedFile(const FString& Filename) override;
virtual bool SetContentFromStream(TSharedRef<FArchive> Stream) override;
virtual void SetHeader(const FString& HeaderName, const FString& HeaderValue) override;
virtual void AppendToHeader(const FString& HeaderName, const FString& AdditionalHeaderValue) override;
virtual bool ProcessRequest() override;
virtual void Tick(float DeltaSeconds) override;
//~ End IHttpRequest Interface
//~ Begin IHttpRequestThreaded Interface
virtual bool StartThreadedRequest() override;
virtual void FinishRequest() override;
virtual bool IsThreadedRequestComplete() override;
virtual void TickThreadedRequest(float DeltaSeconds) override;
//~ End IHttpRequestThreaded Interface
/**
* Constructor
*
* @param InSession - NSURLSession session used to create NSURLSessionTask to retrieve the response
*/
explicit FAppleHttpRequest(NSURLSession* InSession);
/**
* Destructor. Clean up any connection/request handles
*/
virtual ~FAppleHttpRequest();
PACKAGE_SCOPE:
using FHttpRequestCommon::StartProcessTime;
using FHttpRequestCommon::ConnectTime;
using FHttpRequestCommon::BroadcastResponseHeadersReceived;
using FHttpRequestCommon::StartActivityTimeoutTimer;
using FHttpRequestCommon::ResetActivityTimeoutTimer;
using FHttpRequestCommon::StopActivityTimeoutTimer;
using FHttpRequestCommon::HandleStatusCodeReceived;
using FHttpRequestCommon::SetEffectiveURL;
using FHttpRequestCommon::PassReceivedDataToStream;
bool IsInitializedWithValidStream() const;
private:
/**
* Trigger the request progress delegate if progress has changed
*/
void CheckProgressDelegate();
/**
* Create the session connection and initiate the web request
*
* @return true if the request was started
*/
virtual bool SetupRequest() override;
virtual FHttpResponsePtr CreateResponse() override;
virtual void MockResponseData() override;
virtual void AbortRequest() override;
/**
* Close session/request handles and unregister callbacks
*/
virtual void CleanupRequest() override;
private:
/** This is the NSMutableURLRequest, all our Apple functionality will deal with this. */
NSMutableURLRequest* Request;
/** This is the session our request belongs to */
NSURLSession* Session;
/** This is the Task associated to the sessionin charge of our request */
NSURLSessionTask* Task;
struct FAppleHttpStreamFactory;
struct FNoStreamSource{};
struct FInvalidStreamSource{};
/** Source to create stream from
FNoStreamedSource: No streamed data
FString: Filename set from SetContentAsStreamedFile
TSharedRef<FArchive>: Stream set from SetContentFromStream
*/
TVariant<FNoStreamSource, FInvalidStreamSource, FString, TSharedRef<FArchive>> StreamedContentSource;
/** The request payload length in bytes. This must be tracked separately for a file stream */
uint64 ContentBytesLength;
/** Array used to retrieve back content set on the ObjC request when calling GetContent*/
mutable TArray<uint8> StorageForGetContent;
/** Last reported bytes written */
int32 LastReportedBytesWritten;
/** Last reported bytesread */
int32 LastReportedBytesRead;
// UE-228716: This request should follow same logic as the rest of implementations
const bool bStartTaskInHttpThread;
};
@class FAppleHttpResponseDelegate;
/**
* Apple implementation of an Http response
*/
class FAppleHttpResponse : public FHttpResponseCommon
{
public:
//~ Begin IHttpBase Interface
virtual FString GetHeader(const FString& HeaderName) const override;
virtual TArray<FString> GetAllHeaders() const override;
virtual FString GetContentType() const override;
virtual uint64 GetContentLength() const override;
virtual const TArray<uint8>& GetContent() const override;
//~ End IHttpBase Interface
//~ Begin IHttpResponse Interface
virtual FString GetContentAsString() const override;
//~ End IHttpResponse Interface
/**
* Check whether a response is ready or not.
*/
bool IsReady() const;
/**
* Get the number of bytes received so far
*/
const uint64 GetNumBytesReceived() const;
/**
* Get the number of bytes sent so far
*/
const uint64 GetNumBytesWritten() const;
/**
* Cleans internal shared objects between request and response
*/
void CleanSharedObjects();
/**
* Sets delegate invoked when URLSession:dataTask:didReceiveData or URLSession:task:didCompleteWithError: are triggered
* Should be set right before task is started
*/
void SetNewAppleHttpEventDelegate(FNewAppleHttpEventDelegate&& Delegate);
/**
* Constructor
*
* @param InRequest - original request that created this response
*/
FAppleHttpResponse(FAppleHttpRequest& InRequest);
/**
* Destructor
*/
virtual ~FAppleHttpResponse();
private:
// implementation friends
friend class FAppleHttpRequest;
/**
* Get status from the internal delegate
*/
EHttpRequestStatus::Type GetStatusFromDelegate() const;
/**
* Get reason of failure from the internal delegate
*/
EHttpFailureReason GetFailureReasonFromDelegate() const;
// Delegate implementation. Keeps the response state and data
FAppleHttpResponseDelegate* ResponseDelegate;
};