// Copyright Epic Games, Inc. All Rights Reserved. #include "casstore.h" #include #include #include namespace zen { HttpCasService::HttpCasService(CasStore& Store) : m_CasStore(Store) { m_Router.AddPattern("cas", "([0-9A-Fa-f]{40})"); m_Router.RegisterRoute( "{cas}", [this](HttpRouterRequest& Req) { IoHash Hash = IoHash::FromHexString(Req.GetCapture(1)); ZEN_DEBUG("CAS request for {}", Hash); HttpServerRequest& ServerRequest = Req.ServerRequest(); switch (ServerRequest.RequestVerb()) { case HttpVerb::kGet: case HttpVerb::kHead: { if (IoBuffer Value = m_CasStore.FindChunk(Hash)) { return ServerRequest.WriteResponse(HttpResponseCode::OK, HttpContentType::kBinary, Value); } return ServerRequest.WriteResponse(HttpResponseCode::NotFound); } break; case HttpVerb::kPut: { IoBuffer Payload = ServerRequest.ReadPayload(); IoHash PayloadHash = IoHash::HashBuffer(Payload.Data(), Payload.Size()); // URI hash must match content hash if (PayloadHash != Hash) { return ServerRequest.WriteResponse(HttpResponseCode::BadRequest); } m_CasStore.InsertChunk(Payload, PayloadHash); return ServerRequest.WriteResponse(HttpResponseCode::OK); } break; default: break; } }, HttpVerb::kGet | HttpVerb::kPut | HttpVerb::kHead); } const char* HttpCasService::BaseUri() const { return "/cas/"; } void HttpCasService::HandleRequest(zen::HttpServerRequest& Request) { if (Request.RelativeUri().empty()) { // Root URI request switch (Request.RequestVerb()) { case HttpVerb::kPut: case HttpVerb::kPost: { IoBuffer Payload = Request.ReadPayload(); IoHash PayloadHash = IoHash::HashBuffer(Payload.Data(), Payload.Size()); ZEN_DEBUG("CAS POST request for {} ({} bytes)", PayloadHash, Payload.Size()); auto InsertResult = m_CasStore.InsertChunk(Payload, PayloadHash); if (InsertResult.New) { return Request.WriteResponse(HttpResponseCode::Created); } else { return Request.WriteResponse(HttpResponseCode::OK); } } break; case HttpVerb::kGet: case HttpVerb::kHead: break; default: break; } } else { m_Router.HandleRequest(Request); } } } // namespace zen