Problems with HttpServer Module

Hello!

I hope I’m posting in the right place, I decided to post it here since I will be quoting the engine code itself. I want to share some of the problems I found while trying to use the HTTP Server Module (HttpServer | Unreal Engine Documentation).

[Just in case you are wondering I’m using it for client side google authentication, so I execute the flow in a browser and then redirect to a local http server in my game and get the user’s access token]

First problem: I cannot stop the listeners. The problem is although the StopAllListeners() method stops the listeners, it doesn’t actually remove them from the listeners list, so next time the listener ticks an assertions will fail.

​​



void FHttpServerModule::StopAllListeners()
{
    UE_LOG(LogHttpServerModule, Log,
        TEXT("Stopping all listeners..."));

    for (const auto& Listener : Listeners)
    {
        if (Listener.Value->IsListening())
        {
            Listener.Value->StopListening();
        }
    }

    UE_LOG(LogHttpServerModule, Log,
        TEXT("All listeners stopped"));

}

void FHttpListener::Tick(float DeltaTime)
{
    // Accept new connections
    AcceptConnections(MaxConnectionsToAcceptPerFrame);

    // Tick Connections
    TickConnections(DeltaTime);

    // Remove any destroyed connections
    RemoveDestroyedConnections();
}


void FHttpListener::AcceptConnections(uint32 MaxConnectionsToAccept)
{
 check(ListenSocket);   // <--- this assertion fails
      ....
}



Second problem: the previous problem causes the http server to always keep the port bind until the end of the process, preventing another client to start its own server. I decided to workaround this problem by retrying with another port if the server cannot be bind. The problem is the module is swallowing those errors.

As you can see the http listener will return true if the socket can be bind:

​​



bool FHttpListener::StartListening()
{
    ...

    // Bind to Localhost/Caller-defined port
    TSharedRef<FInternetAddr> LocalhostAddr = SocketSubsystem->CreateInternetAddr();
    LocalhostAddr->SetAnyAddress();
    LocalhostAddr->SetPort(ListenPort);
    if (!ListenSocket->Bind(*LocalhostAddr))
    {
        UE_LOG(LogHttpListener, Error,
            TEXT("HttpListener unable to bind to %s"),
            *LocalhostAddr->ToString(true));
        return false;
    }

      ...
    UE_LOG(LogHttpListener, Log,
        TEXT("Created new HttpListener on port %u"), ListenPort);
    return true;
}


but the module swallows the error:

​​



void FHttpServerModule::StartAllListeners()
{
    bHttpListenersEnabled = true;

    UE_LOG(LogHttpServerModule, Log,
        TEXT("Starting all listeners..."));

    for (const auto& Listener : Listeners)
    {
        if (!Listener.Value->IsListening())
        {
            Listener.Value->StartListening();
        }
    }
    UE_LOG(LogHttpServerModule, Log,
        TEXT("All listeners started"));
}


Not sure if I’m missing something (and pretty new to unreal) or if there are bugs (which is what I suspect), and I’m also not sure if this is the right place to post a bug, but decided to start somewhere!.

Thanks!

I am encountering this issue when I stop playing the game as well, did you ever resolve it?

Although I haven’t managed to find a fix either, it’s at least good to know, that I’m not the only one struggling with this. OP or @OOOllie, did you find a fix by any chance?

你这个问题,我在项目的Saved->Config->WindowEdit->Engine.ini中添加以下内容就会关闭自动检测

[/Script/Engine.GarbageCollectionSettings]
gc.TimeBetweenPurgingPendingKillObjects=0

What @Creator_joey suggests may work; however, it has an impact on the entire engine, and managing memory more aggressively might have performance implications.

For me, I successfully managed to work with the HttpServer Module by not stopping the listeners but unbinding the route and rebinding it:

// First, unbind any already bound route:
if (GameInstance->BoundRoute.IsValid())
{
	httpRouter->UnbindRoute(GameInstance->BoundRoute);
	GameInstance->BoundRoute = nullptr;
}

// Then (re-)bind and store the handle
GameInstance->BoundRoute = httpRouter->BindRoute(FHttpPath(HttpPathGET), EHttpServerRequestVerbs::VERB_GET,
												 [WeakThisPtr](const FHttpServerRequest& Request,
															   const FHttpResultCallback& OnComplete)
												 {
													 TSharedPtr<WSHttpConnector> SharedThis = WeakThisPtr.Pin();
													 if (!SharedThis.IsValid())
													 {
														 return false;
													 }
													 return SharedThis->RequestGETInternal(Request, OnComplete);
												 });

1 Like