1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include <zencore/fmtutils.h>
#include <zencore/httpserver.h>
#include "cachestore.h"
#include "structuredcache.h"
#include "upstream/jupiter.h"
#include <spdlog/spdlog.h>
#include <filesystem>
namespace zen {
HttpStructuredCacheService::HttpStructuredCacheService(std::filesystem::path RootPath, zen::CasStore& InStore)
: m_CasStore(InStore)
, m_CacheStore(InStore, RootPath)
{
spdlog::info("initializing structured cache at '{}'", RootPath);
}
HttpStructuredCacheService::~HttpStructuredCacheService()
{
spdlog::info("closing structured cache");
}
const char*
HttpStructuredCacheService::BaseUri() const
{
return "/z$/";
}
void
HttpStructuredCacheService::HandleRequest(zen::HttpServerRequest& Request)
{
CacheRef Ref;
if (!ValidateUri(Request, /* out */ Ref))
{
return Request.WriteResponse(zen::HttpResponse::BadRequest); // invalid URL
}
switch (auto Verb = Request.RequestVerb())
{
using enum zen::HttpVerb;
case kHead:
case kGet:
{
CacheValue Value;
bool Success = m_CacheStore.Get(Ref.BucketSegment, Ref.HashKey, /* out */ Value);
if (!Success)
{
Request.WriteResponse(zen::HttpResponse::NotFound);
}
else
{
if (Verb == kHead)
{
Request.SetSuppressResponseBody();
Request.WriteResponse(zen::HttpResponse::OK, zen::HttpContentType::kBinary, Value.Value);
}
else
{
Request.WriteResponse(zen::HttpResponse::OK, zen::HttpContentType::kBinary, Value.Value);
}
}
}
break;
case kPut:
{
if (zen::IoBuffer Body = Request.ReadPayload())
{
CacheValue Value;
Value.Value = Body;
m_CacheStore.Put(Ref.BucketSegment, Ref.HashKey, Value);
Request.WriteResponse(zen::HttpResponse::Created);
}
else
{
return;
}
}
break;
case kPost:
break;
default:
break;
}
}
[[nodiscard]] bool
HttpStructuredCacheService::ValidateUri(zen::HttpServerRequest& Request, CacheRef& OutRef)
{
std::string_view Key = Request.RelativeUri();
std::string_view::size_type BucketSplitOffset = Key.find_last_of('/');
if (BucketSplitOffset == std::string_view::npos)
{
return false;
}
OutRef.BucketSegment = Key.substr(0, BucketSplitOffset);
std::string_view HashSegment = Key.substr(BucketSplitOffset + 1);
if (HashSegment.size() != (2 * sizeof OutRef.HashKey.Hash))
{
return false;
}
bool IsOk = zen::ParseHexBytes(HashSegment.data(), HashSegment.size(), OutRef.HashKey.Hash);
if (!IsOk)
{
return false;
}
return true;
}
} // namespace zen
|