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

261 lines
7.1 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "HttpConnectionTypes.h"
#include "HttpConnectionRequestReadContext.h"
#include "HttpConnectionResponseWriteContext.h"
#include "HttpResultCallback.h"
#include "HttpServerConfig.h"
#include "HttpServerConstants.h"
#include "HttpServerHttpVersion.h"
#include "Misc/Timespan.h"
class FSocket;
class ISocketSubsystem;
class FHttpRouter;
struct FHttpServerRequest;
struct FHttpServerResponse;
DECLARE_LOG_CATEGORY_EXTERN(LogHttpConnection, Log, All);
struct FHttpConnection final : public TSharedFromThis<FHttpConnection>
{
public:
/**
* Constructor
*
* @param InSocket The underlying file descriptor
*/
FHttpConnection(FSocket* InSocket, TSharedPtr<FHttpRouter> InRouter, uint32 InOriginPort, uint32 InConnectionId);
/**
* Destructor
*/
~FHttpConnection();
/**
* Ticks the connection to drive internal state
*
* @param DeltaTime The elapsed time since the last Tick()
*/
void Tick(float DeltaTime);
/**
* Returns the current state of the connection
*/
FORCEINLINE EHttpConnectionState GetState() const
{
return State;
}
/**
* Signals the connection to destroy itself
*
* @param bGraceful Whether to gracefully destroy pending current operations
*/
void RequestDestroy(bool bGraceful);
/**
* Determines whether this connection should remain open after writing
*/
FORCEINLINE bool IsHttpKeepAliveEnabled() const
{
return bKeepAlive;
}
FORCEINLINE bool operator==(const FHttpConnection& Other) const
{
return this->Socket == Other.Socket;
}
friend uint32 GetTypeHash(const FHttpConnection& Conn)
{
return GetTypeHash(Conn.Socket);
}
private:
/**
* The reason why the connection was destroyed.
*/
enum class EConnectionDestroyReason : uint8
{
WriteError,
AwaitReadTimeout,
BeginReadTimeout,
ReadTimeout,
WriteTimeout,
WriteComplete,
DestroyRequest
};
private:
/**
* Changes the internal state of the connection to NewState
*
* @param NewState The state to transition to
*/
void ChangeState(EHttpConnectionState NewState);
/**
* Changes the internal state from the caller-supplied current state to the next state
*
* @param CurrentState The expected current state
* @param NextState The next state
*/
void TransferState(EHttpConnectionState CurrentState, EHttpConnectionState NextState);
/**
* Begins a read operation
*
* @param DeltaTime The elapsed time since the last invocation
*/
void BeginRead(float DeltaTime);
/**
* Continues an in-progress read operation
*
* @param DeltaTime The elapsed time since the last invocation
*/
void ContinueRead(float DeltaTime);
/**
* Completes a previously begun read operation
*
* @param Request The instantiated request object
*/
void CompleteRead(const TSharedPtr<FHttpServerRequest>& Request);
/**
* Proxies the respective request to a bound handler
* @param Request The request to process
* @param OnProcessingComplete The callback to be invoked upon completion
* @return true if the request was accepted by a handler, false otherwise
*/
void ProcessRequest(const TSharedPtr<FHttpServerRequest>& Request, const FHttpResultCallback& OnProcessingComplete);
/**
* Begins a write operation
*
* @param Response The response to write
* @param RequestNumber The expected and unique request number
*/
void BeginWrite(TUniquePtr<FHttpServerResponse>&& Response, uint32 RequestNumber);
/**
* Continues an in-progress write operation
*
* @param DeltaTime The elapsed time since the last invocation
*/
void ContinueWrite(float DeltaTime);
/**
* Completes a previously begun write operation
*/
void CompleteWrite();
/**
* Closes and nullifies the underlying connection
* @param DestroyReason The reason why the connection should be destroyed.
*/
void Destroy(EConnectionDestroyReason DestroyReason);
/**
* Logs and responds with the caller-supplied error code
*
* @param ErrorCode The HTTP error code
* @param ErrorCodeStr The machine-readable error description
*/
void HandleReadError(EHttpServerResponseCodes ErrorCode, const TCHAR* ErrorCodeStr);
/**
* Logs the caller-supplied error code and closes the connection
*
* @param ErrorCodeStr The machine-readable error description
*/
void HandleWriteError(const TCHAR* ErrorCodeStr);
/**
* Determines whether KeepAlive is set based on the caller-supplied http version and connection headers
*
* @param HttpVersion The http version of the request
* @param ConnectionHeaders The request "Connection:" headers
* @return true if KeepAlive should be set, false otherwise
*/
static bool ResolveKeepAlive(HttpVersion::EHttpServerHttpVersion HttpVersion, const TArray<FString>& ConnectionHeaders);
/**
* Convert a connection destroy reason to a string.
* @param DestroyReason The reason why the connection was destroyed.
* @return The output string.
*/
static const TCHAR* LexToString(EConnectionDestroyReason DestroyReason)
{
switch (DestroyReason)
{
case EConnectionDestroyReason::WriteError:
return TEXT("Write error");
case EConnectionDestroyReason::AwaitReadTimeout:
return TEXT("Await read timeout");
case EConnectionDestroyReason::BeginReadTimeout:
return TEXT("Begin read timeout");
case EConnectionDestroyReason::ReadTimeout:
return TEXT("Read timeout");
case EConnectionDestroyReason::WriteTimeout:
return TEXT("Write timeout");
case EConnectionDestroyReason::WriteComplete:
return TEXT("Write complete");
case EConnectionDestroyReason::DestroyRequest:
return TEXT("Destroy connection request");
default:
{
checkNoEntry();
return TEXT("Unknown");
}
}
}
private:
/** Accepted external socket */
FSocket* Socket;
/** State of the connection */
EHttpConnectionState State = EHttpConnectionState::AwaitingRead;
/** Routing mechanism */
const TSharedPtr<FHttpRouter> Router;
/** The origin port on which this connection was accepted */
uint32 OriginPort;
/** The connection identifier (used for logging purposes) */
uint32 ConnectionId;
/** Helper reader context to track the state of streaming request reads */
FHttpConnectionRequestReadContext ReadContext;
/** Helper writer context to track the state of streaming response writes */
FHttpConnectionResponseWriteContext WriteContext;
/** Whether to keep this connection alive after writing */
bool bKeepAlive = true;
/** Whether to gracefully close pending current operations */
bool bGracefulDestroyRequested = false;
/** Internal state tracker (incremented per-request-read) used to validate request/response throughput */
uint32 LastRequestNumber = 0;
/** The duration (seconds) at which connections are forcefully timed out */
static constexpr float ConnectionTimeout = 5.0f;
/** The duration (seconds) at which idle keep-alive connections are forcefully timed out */
static constexpr float ConnectionKeepAliveTimeout = 15.0f;
/** Connection configuration data */
FHttpServerConnectionConfig Config;
};