// Copyright Epic Games, Inc. All Rights Reserved. #include "CEF/CEFSchemeHandler.h" #include "Misc/FileHelper.h" #include "Misc/Paths.h" #include "IWebBrowserSchemeHandler.h" #if WITH_CEF3 class FHandlerHeaderSetter : public IWebBrowserSchemeHandler::IHeaders { public: FHandlerHeaderSetter(CefRefPtr& InResponse, #if CEF_VERSION_MAJOR < 128 int64& InContentLength, #else int64_t& InContentLength, #endif CefString& InRedirectUrl) : Response(InResponse) , ContentLength(InContentLength) , RedirectUrl(InRedirectUrl) , StatusCode(INDEX_NONE) { } virtual ~FHandlerHeaderSetter() { if (Headers.size() > 0) { Response->SetHeaderMap(Headers); } if (StatusCode != INDEX_NONE) { Response->SetStatus(StatusCode); } if (MimeType.length() > 0) { Response->SetMimeType(MimeType); } } virtual void SetMimeType(const TCHAR* InMimeType) override { MimeType = TCHAR_TO_WCHAR(InMimeType); } virtual void SetStatusCode(int32 InStatusCode) override { StatusCode = InStatusCode; } virtual void SetContentLength(int32 InContentLength) override { ContentLength = InContentLength; } virtual void SetRedirect(const TCHAR* InRedirectUrl) override { RedirectUrl = TCHAR_TO_WCHAR(InRedirectUrl); } virtual void SetHeader(const TCHAR* Key, const TCHAR* Value) override { Headers.insert(std::make_pair(CefString(TCHAR_TO_WCHAR(Key)), CefString(TCHAR_TO_WCHAR(Value)))); } private: CefRefPtr& Response; #if CEF_VERSION_MAJOR < 128 int64& ContentLength; #else int64_t& ContentLength; #endif CefString& RedirectUrl; CefResponse::HeaderMap Headers; CefString MimeType; int32 StatusCode; }; class FCefSchemeHandler : public CefResourceHandler { public: FCefSchemeHandler(TUniquePtr&& InHandlerImplementation) : HandlerImplementation(MoveTemp(InHandlerImplementation)) { } virtual ~FCefSchemeHandler() { } // Begin CefResourceHandler interface. virtual bool ProcessRequest(CefRefPtr Request, CefRefPtr Callback) override { if (HandlerImplementation.IsValid()) { return HandlerImplementation->ProcessRequest( WCHAR_TO_TCHAR(Request->GetMethod().ToWString().c_str()), WCHAR_TO_TCHAR(Request->GetURL().ToWString().c_str()), FSimpleDelegate::CreateLambda([Callback](){ Callback->Continue(); }) ); } return false; } virtual void GetResponseHeaders(CefRefPtr Response, #if CEF_VERSION_MAJOR < 128 int64& ResponseLength, #else int64_t& ResponseLength, #endif CefString& RedirectUrl) override { if (ensure(HandlerImplementation.IsValid())) { FHandlerHeaderSetter Headers(Response, ResponseLength, RedirectUrl); HandlerImplementation->GetResponseHeaders(Headers); } } virtual bool ReadResponse(void* DataOut, int BytesToRead, int& BytesRead, CefRefPtr Callback) override { if (ensure(HandlerImplementation.IsValid())) { return HandlerImplementation->ReadResponse( (uint8*)DataOut, BytesToRead, BytesRead, FSimpleDelegate::CreateLambda([Callback](){ Callback->Continue(); }) ); } BytesRead = 0; return false; } virtual void Cancel() override { if (HandlerImplementation.IsValid()) { HandlerImplementation->Cancel(); } } // End CefResourceHandler interface. private: TUniquePtr HandlerImplementation; // Include CEF ref counting. IMPLEMENT_REFCOUNTING(FCefSchemeHandler); }; class FCefSchemeHandlerFactory : public CefSchemeHandlerFactory { public: FCefSchemeHandlerFactory(IWebBrowserSchemeHandlerFactory* InWebBrowserSchemeHandlerFactory) : WebBrowserSchemeHandlerFactory(InWebBrowserSchemeHandlerFactory) { } // Begin CefSchemeHandlerFactory interface. virtual CefRefPtr Create(CefRefPtr Browser, CefRefPtr Frame, const CefString& Scheme, CefRefPtr Request) override { return new FCefSchemeHandler(WebBrowserSchemeHandlerFactory->Create( WCHAR_TO_TCHAR(Request->GetMethod().ToWString().c_str()), WCHAR_TO_TCHAR(Request->GetURL().ToWString().c_str()))); } // End CefSchemeHandlerFactory interface. bool IsUsing(IWebBrowserSchemeHandlerFactory* InWebBrowserSchemeHandlerFactory) { return WebBrowserSchemeHandlerFactory == InWebBrowserSchemeHandlerFactory; } private: IWebBrowserSchemeHandlerFactory* WebBrowserSchemeHandlerFactory; // Include CEF ref counting. IMPLEMENT_REFCOUNTING(FCefSchemeHandlerFactory); }; void FCefSchemeHandlerFactories::AddSchemeHandlerFactory(FString Scheme, FString Domain, IWebBrowserSchemeHandlerFactory* WebBrowserSchemeHandlerFactory) { checkf(WebBrowserSchemeHandlerFactory != nullptr, TEXT("WebBrowserSchemeHandlerFactory must be provided.")); CefRefPtr Factory = new FCefSchemeHandlerFactory(WebBrowserSchemeHandlerFactory); CefRegisterSchemeHandlerFactory(TCHAR_TO_WCHAR(*Scheme), TCHAR_TO_WCHAR(*Domain), Factory); SchemeHandlerFactories.Emplace(MoveTemp(Scheme), MoveTemp(Domain), MoveTemp(Factory)); } void FCefSchemeHandlerFactories::RemoveSchemeHandlerFactory(IWebBrowserSchemeHandlerFactory* WebBrowserSchemeHandlerFactory) { checkf(WebBrowserSchemeHandlerFactory != nullptr, TEXT("WebBrowserSchemeHandlerFactory must be provided.")); SchemeHandlerFactories.RemoveAll([WebBrowserSchemeHandlerFactory](const FFactory& Element) { return ((FCefSchemeHandlerFactory*)Element.Factory.get())->IsUsing(WebBrowserSchemeHandlerFactory); }); } void FCefSchemeHandlerFactories::RegisterFactoriesWith(CefRefPtr& Context) { if (Context) { for (const FFactory& SchemeHandlerFactory : SchemeHandlerFactories) { Context->RegisterSchemeHandlerFactory(TCHAR_TO_WCHAR(*SchemeHandlerFactory.Scheme), TCHAR_TO_WCHAR(*SchemeHandlerFactory.Domain), SchemeHandlerFactory.Factory); } } } FCefSchemeHandlerFactories::FFactory::FFactory(FString InScheme, FString InDomain, CefRefPtr InFactory) : Scheme(MoveTemp(InScheme)) , Domain(MoveTemp(InDomain)) , Factory(MoveTemp(InFactory)) { } #endif