// Copyright Epic Games, Inc. All Rights Reserved. #include "vfsservice.h" #include #include namespace zen { using namespace std::literals; #if ZEN_WITH_VFS ////////////////////////////////////////////////////////////////////////// bool GetContentAsCbObject(HttpServerRequest& HttpReq, CbObject& Cb) { IoBuffer Payload = HttpReq.ReadPayload(); HttpContentType PayloadContentType = HttpReq.RequestContentType(); switch (PayloadContentType) { case HttpContentType::kJSON: case HttpContentType::kUnknownContentType: case HttpContentType::kText: { std::string JsonText(reinterpret_cast(Payload.GetData()), Payload.GetSize()); Cb = LoadCompactBinaryFromJson(JsonText).AsObject(); if (!Cb) { HttpReq.WriteResponse(HttpResponseCode::BadRequest, HttpContentType::kText, "Content format not supported, expected JSON format"); return false; } } break; case HttpContentType::kCbObject: Cb = LoadCompactBinaryObject(Payload); if (!Cb) { HttpReq.WriteResponse(HttpResponseCode::BadRequest, HttpContentType::kText, "Content format not supported, expected compact binary format"); return false; } break; default: HttpReq.WriteResponse(HttpResponseCode::BadRequest, HttpContentType::kText, "Invalid request content type"); return false; } return true; } ////////////////////////////////////////////////////////////////////////// // // to test: // // echo {"method": "mount", "params": {"path": "d:\\VFS_ROOT"}} | curl.exe http://localhost:8558/vfs --data-binary @- // echo {"method": "unmount"} | curl.exe http://localhost:8558/vfs --data-binary @- VfsService::VfsService(HttpStatusService& StatusService, VfsServiceImpl* ServiceImpl) : m_StatusService(StatusService), m_Impl(ServiceImpl) { m_Router.RegisterRoute( "info", [&](HttpRouterRequest& Request) { CbObjectWriter Cbo; Cbo << "running" << m_Impl->IsVfsRunning(); Cbo << "rootpath" << m_Impl->GetMountpointPath(); Request.ServerRequest().WriteResponse(HttpResponseCode::OK, Cbo.Save()); }, HttpVerb::kGet | HttpVerb::kHead); m_Router.RegisterRoute( "", [&](HttpRouterRequest& Req) { CbObject Payload; if (!GetContentAsCbObject(Req.ServerRequest(), Payload)) return; std::string_view RpcName = Payload["method"sv].AsString(); if (RpcName == "mount"sv) { CbObjectView Params = Payload["params"sv].AsObjectView(); std::string_view Mountpath = Params["path"sv].AsString(); if (Mountpath.empty()) { return Req.ServerRequest().WriteResponse(HttpResponseCode::BadRequest, HttpContentType::kText, "no path specified"); } if (m_Impl->IsVfsRunning()) { return Req.ServerRequest().WriteResponse(HttpResponseCode::BadRequest, HttpContentType::kText, "VFS already mounted"); } try { m_Impl->Mount(Mountpath); } catch (const std::exception& Ex) { return Req.ServerRequest().WriteResponse(HttpResponseCode::BadRequest, HttpContentType::kText, Ex.what()); } Req.ServerRequest().WriteResponse(HttpResponseCode::OK); } else if (RpcName == "unmount"sv) { if (!m_Impl->IsVfsRunning()) { return Req.ServerRequest().WriteResponse(HttpResponseCode::BadRequest, HttpContentType::kText, "VFS not active"); } try { m_Impl->Unmount(); } catch (const std::exception& Ex) { return Req.ServerRequest().WriteResponse(HttpResponseCode::BadRequest, HttpContentType::kText, Ex.what()); } Req.ServerRequest().WriteResponse(HttpResponseCode::OK); } else { Req.ServerRequest().WriteResponse(HttpResponseCode::BadRequest, HttpContentType::kText, "unknown RPC"sv); } }, HttpVerb::kPost); m_StatusService.RegisterHandler("vfs", *this); } VfsService::~VfsService() { m_StatusService.UnregisterHandler("vfs", *this); } #else VfsService::VfsService(HttpStatusService& StatusService, VfsServiceImpl* ServiceImpl) : m_StatusService(StatusService) { ZEN_UNUSED(ServiceImpl); } VfsService::~VfsService() { } #endif const char* VfsService::BaseUri() const { return "/vfs/"; } void VfsService::HandleStatusRequest(HttpServerRequest& Request) { CbObjectWriter Cbo; Cbo << "ok" << true; Request.WriteResponse(HttpResponseCode::OK, Cbo.Save()); } void VfsService::HandleRequest(HttpServerRequest& HttpServiceRequest) { m_Router.HandleRequest(HttpServiceRequest); } } // namespace zen