// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "HttpManager.h" #include "HAL/PlatformTime.h" #include "HAL/PlatformProcess.h" #include "Misc/ScopeLock.h" #include "Http.h" #include "HttpThread.h" // FHttpManager FCriticalSection FHttpManager::RequestLock; FHttpManager::FHttpManager() : FTickerObjectBase(0.0f) , DeferredDestroyDelay(10.0f) { } FHttpManager::~FHttpManager() { if (Thread) { Thread->StopThread(); delete Thread; } } void FHttpManager::Initialize() { Thread = CreateHttpThread(); Thread->StartThread(); } FHttpThread* FHttpManager::CreateHttpThread() { return new FHttpThread(); } void FHttpManager::Flush(bool bShutdown) { FScopeLock ScopeLock(&RequestLock); if (bShutdown) { if (Requests.Num()) { UE_LOG(LogHttp, Display, TEXT("Http module shutting down, but needs to wait on %d outstanding Http requests:"), Requests.Num()); } // Clear delegates since they may point to deleted instances for (TArray>::TIterator It(Requests); It; ++It) { TSharedRef Request = *It; Request->OnProcessRequestComplete().Unbind(); Request->OnRequestProgress().Unbind(); UE_LOG(LogHttp, Display, TEXT(" verb=[%s] url=[%s] status=%s"), *Request->GetVerb(), *Request->GetURL(), EHttpRequestStatus::ToString(Request->GetStatus())); } } // block until all active requests have completed double LastTime = FPlatformTime::Seconds(); while (Requests.Num() > 0) { const double AppTime = FPlatformTime::Seconds(); Tick(AppTime - LastTime); LastTime = AppTime; if (Requests.Num() > 0) { UE_LOG(LogHttp, Display, TEXT("Sleeping 0.5s to wait for %d outstanding Http requests."), Requests.Num()); FPlatformProcess::Sleep(0.5f); } } } bool FHttpManager::Tick(float DeltaSeconds) { FScopeLock ScopeLock(&RequestLock); // Tick each active request for (TArray>::TIterator It(Requests); It; ++It) { TSharedRef Request = *It; Request->Tick(DeltaSeconds); } // Tick any pending destroy objects for (int Idx=0; Idx < PendingDestroyRequests.Num(); Idx++) { FRequestPendingDestroy& Request = PendingDestroyRequests[Idx]; Request.TimeLeft -= DeltaSeconds; if (Request.TimeLeft <= 0) { PendingDestroyRequests.RemoveAt(Idx--); } } TArray CompletedThreadedRequests; Thread->GetCompletedRequests(CompletedThreadedRequests); // Finish and remove any completed requests for (IHttpThreadedRequest* CompletedRequest : CompletedThreadedRequests) { // Keep track of requests that have been removed to be destroyed later PendingDestroyRequests.AddUnique(FRequestPendingDestroy(DeferredDestroyDelay,CompletedRequest->AsShared())); CompletedRequest->FinishRequest(); Requests.Remove(CompletedRequest->AsShared()); } // keep ticking return true; } void FHttpManager::AddRequest(const TSharedRef& Request) { FScopeLock ScopeLock(&RequestLock); Requests.Add(Request); } void FHttpManager::RemoveRequest(const TSharedRef& Request) { FScopeLock ScopeLock(&RequestLock); // Keep track of requests that have been removed to be destroyed later PendingDestroyRequests.AddUnique(FRequestPendingDestroy(DeferredDestroyDelay,Request)); Requests.Remove(Request); } void FHttpManager::AddThreadedRequest(const TSharedRef& Request) { { FScopeLock ScopeLock(&RequestLock); Requests.Add(Request); } Thread->AddRequest(&Request.Get()); } void FHttpManager::CancelThreadedRequest(const TSharedRef& Request) { Thread->CancelRequest(&Request.Get()); } bool FHttpManager::IsValidRequest(const IHttpRequest* RequestPtr) const { FScopeLock ScopeLock(&RequestLock); bool bResult = false; for (const TSharedRef& Request : Requests) { if (&Request.Get() == RequestPtr) { bResult = true; break; } } return bResult; } void FHttpManager::DumpRequests(FOutputDevice& Ar) const { FScopeLock ScopeLock(&RequestLock); Ar.Logf(TEXT("------- (%d) Http Requests"), Requests.Num()); for (const TSharedRef& Request : Requests) { Ar.Logf(TEXT(" verb=[%s] url=[%s] status=%s"), *Request->GetVerb(), *Request->GetURL(), EHttpRequestStatus::ToString(Request->GetStatus())); } } static FString GetUrlDomain(const FString& Url) { FString Protocol; FString Domain = Url; // split the http protocol portion from domain Url.Split(TEXT("://"), &Protocol, &Domain); // strip off everything but the domain portion int32 Idx = Domain.Find(TEXT("/")); int32 IdxOpt = Domain.Find(TEXT("?")); Idx = IdxOpt >= 0 && IdxOpt < Idx ? IdxOpt : Idx; if (Idx > 0) { Domain = Domain.Left(Idx); } return Domain; }