// Copyright Epic Games, Inc. All Rights Reserved. #include "cidstore.h" #include #include #include #include #include namespace zen { HttpCidService::HttpCidService(CidStore& Store) : m_CidStore(Store) { m_Router.AddPattern("cid", "([0-9A-Fa-f]{40})"); m_Router.RegisterRoute( "{cid}", [this](HttpRouterRequest& Req) { IoHash Hash = IoHash::FromHexString(Req.GetCapture(1)); ZEN_DEBUG("CID request for {}", Hash); HttpServerRequest& ServerRequest = Req.ServerRequest(); switch (ServerRequest.RequestVerb()) { case HttpVerb::kGet: case HttpVerb::kHead: { if (IoBuffer Value = m_CidStore.FindChunkByCid(Hash)) { return ServerRequest.WriteResponse(HttpResponseCode::OK, HttpContentType::kBinary, Value); } return ServerRequest.WriteResponse(HttpResponseCode::NotFound); } break; case HttpVerb::kPut: { IoBuffer Payload = ServerRequest.ReadPayload(); CompressedBuffer Compressed = CompressedBuffer::FromCompressed(SharedBuffer(Payload)); if (!Compressed) { return ServerRequest.WriteResponse(HttpResponseCode::UnsupportedMediaType); } IoHash PayloadHash = IoHash::FromBLAKE3(Compressed.GetRawHash()); // URI hash must match content hash if (PayloadHash != Hash) { return ServerRequest.WriteResponse(HttpResponseCode::BadRequest); } m_CidStore.AddChunk(Compressed); return ServerRequest.WriteResponse(HttpResponseCode::OK); } break; default: break; } }, HttpVerb::kGet | HttpVerb::kPut | HttpVerb::kHead); } const char* HttpCidService::BaseUri() const { return "/cid/"; } void HttpCidService::HandleRequest(zen::HttpServerRequest& Request) { if (Request.RelativeUri().empty()) { // Root URI request switch (Request.RequestVerb()) { case HttpVerb::kPut: case HttpVerb::kPost: { IoBuffer Payload = Request.ReadPayload(); CompressedBuffer Compressed = CompressedBuffer::FromCompressed(SharedBuffer(Payload)); if (!Compressed) { return Request.WriteResponse(HttpResponseCode::UnsupportedMediaType); } IoHash PayloadHash = IoHash::FromBLAKE3(Compressed.GetRawHash()); ZEN_DEBUG("CID POST request for {} ({} bytes)", PayloadHash, Payload.Size()); auto InsertResult = m_CidStore.AddChunk(Compressed); 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