Skip to content

Commit

Permalink
[Manifests] Initial Manifests (#2)
Browse files Browse the repository at this point in the history
* Initial Manifests
* Cleaning up and commenting
* Fix logging whitespace
  • Loading branch information
MNThomson committed Nov 3, 2022
1 parent a5cb806 commit be31493
Show file tree
Hide file tree
Showing 5 changed files with 181 additions and 3 deletions.
8 changes: 8 additions & 0 deletions src/blobs.ts
@@ -0,0 +1,8 @@
import { CFRequest } from "./index";

async function blobs(req: CFRequest) {
console.log("Blob", req.path);
return new Response();
}

export default blobs;
35 changes: 32 additions & 3 deletions src/index.ts
@@ -1,11 +1,40 @@
export interface Env {}
import manifests from "./manifests";
import blobs from "./blobs";
import seedDB from "./seed";
import parseRequest, { MoreRequestData } from "./url";

export interface Env {
// R2 Binding: https://developers.cloudflare.com/workers/runtime-apis/r2/
containerFlareR2: R2Bucket;

// KV Binding: https://developers.cloudflare.com/workers/runtime-apis/kv/
containerFlareKV: KVNamespace;
}

export type CFRequest = Request & MoreRequestData;

export default {
async fetch(
req: Request,
request: Request,
env: Env,
ctx: ExecutionContext
): Promise<Response> {
return new Response();
// Seed the dev DB with test data
await seedDB(env);

// Add additional data to the request
const req: CFRequest = Object.assign(request.clone(), {
...parseRequest(request.url),
});

// Request router
if (req.type === "manifests") {
return await manifests(req, env);
} else if (req.type === "blobs") {
return await blobs(req);
} else {
console.log("Uh oh...");
return new Response("Uh oh...", { status: 404 });
}
},
};
49 changes: 49 additions & 0 deletions src/manifests.ts
@@ -0,0 +1,49 @@
import { CFRequest, Env } from "./index";

async function manifests(req: CFRequest, env: Env) {
// DB Query
let dbKey = "";
if (req.tag.includes("sha256")) {
dbKey = req.tag.replace("sha256:", "");
} else {
dbKey = req.image + "/" + req.tag;
}
console.log("DBKey:", dbKey);

let data = await env.containerFlareKV.get(dbKey);
console.log("DATA:", !!data);
if (!data) {
return new Response("{}", { status: 404 });
}

// Set body of response
let body = "";
if (req.method !== "HEAD") {
body = data;
}

let resp = new Response(body);

// Set docker-content-digest header
let shaTag = req.tag;
if (!req.tag.includes("sha256")) {
shaTag = data;
}
console.log("SHATag:", shaTag);
resp.headers.set("docker-content-digest", shaTag);

// Set Content-Type header
let contentType = "";
if (data.startsWith("{")) {
contentType = JSON.parse(data)?.mediaType;
}
if (!contentType) {
contentType = "application/vnd.docker.distribution.manifest.list.v2+json";
}
console.log("ContentType:", contentType);
resp.headers.set("Content-Type", contentType);

return resp;
}

export default manifests;
49 changes: 49 additions & 0 deletions src/seed.ts
@@ -0,0 +1,49 @@
import { Env } from "./index";

async function seedDB(env: Env) {
await env.containerFlareKV.put(
"hello-world/latest",
`sha256:e18f0a777aefabe047a671ab3ec3eed05414477c951ab1a6f352a06974245fe7`
);

await env.containerFlareKV.put(
"e18f0a777aefabe047a671ab3ec3eed05414477c951ab1a6f352a06974245fe7",
`{
"manifests": [
{
"digest": "sha256:f54a58bc1aac5ea1a25d796ae155dc228b3f0e11d046ae276b39c4bf2f13d8c4",
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"platform": {
"architecture": "amd64",
"os": "linux"
},
"size": 525
}
],
"mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
"schemaVersion": 2
}`
);

await env.containerFlareKV.put(
"f54a58bc1aac5ea1a25d796ae155dc228b3f0e11d046ae276b39c4bf2f13d8c4",
`{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"config": {
"mediaType": "application/vnd.docker.container.image.v1+json",
"size": 1469,
"digest": "sha256:feb5d9fea6a5e9606aa995e879d862b825965ba48de054caab5ef356dc6b3412"
},
"layers": [
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 2479,
"digest": "sha256:2db29710123e3e53a794f2694094b9b4338aa9ee5c40b930cb8063a1be392c54"
}
]
}`
);
}

export default seedDB;
43 changes: 43 additions & 0 deletions src/url.ts
@@ -0,0 +1,43 @@
export type MoreRequestData = {
path: string;
image: string;
type: string;
tag: string;
};

const pathPattern = new RegExp(/^http[s]?:\/\/?[^\/\s]+(.*)/);

// Regex from https://github.com/opencontainers/distribution-spec/blob/main/spec.md#pulling-manifests
const imageRegex =
"[a-z0-9]+(?:[._-][a-z0-9]+)*(?:/[a-z0-9]+(?:[._-][a-z0-9]+)*)*";
const typeRegex = "manifests|blobs";
const pathRegex = "(?:sha256:)?(?:[a-zA-Z0-9_][a-zA-Z0-9._-]{0,127})";
const imageTypeTagPattern = new RegExp(
`^\/v2\/+(${imageRegex})\/(${typeRegex})\/?(${pathRegex})`
);

function parseRequest(link: string): MoreRequestData {
const path = pathPattern.exec(link)![1];

try {
const image = imageTypeTagPattern.exec(path)![1];
const type = imageTypeTagPattern.exec(path)![2];
const tag = imageTypeTagPattern.exec(path)![3];

return {
path,
image,
type,
tag,
};
} catch (error) {
return {
path,
image: "",
type: "",
tag: "",
};
}
}

export default parseRequest;

0 comments on commit be31493

Please sign in to comment.