From 1f393ead12b2a0aa7a99a4ef9a6e47fd30ff85c2 Mon Sep 17 00:00:00 2001 From: Karl Pauls Date: Mon, 12 Feb 2024 18:36:51 +0100 Subject: [PATCH] Implement support for HEAD requests. --- src/handlers/head.js | 46 +++++++++++++++++++++++++++++++++++++++ src/index.js | 4 ++++ src/storage/object/get.js | 8 ++++--- src/utils/daResp.js | 12 ++++++++-- 4 files changed, 65 insertions(+), 5 deletions(-) create mode 100644 src/handlers/head.js diff --git a/src/handlers/head.js b/src/handlers/head.js new file mode 100644 index 0000000..01387f4 --- /dev/null +++ b/src/handlers/head.js @@ -0,0 +1,46 @@ +/* + * Copyright 2024 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +import { getSource } from '../routes/source.js'; +import getList from '../routes/list.js'; +import { getProperties } from '../routes/properties.js'; + +function get404() { + return { status: 404, contentLength: 0 }; +} + +function getRobots() { + const body = 'User-agent: *\nDisallow: /'; + return { contentLength: body.length, status: 200 }; +} + +export default async function headHandler({ env, daCtx, head }) { + const { path } = daCtx; + + if (path.startsWith('/favicon.ico')) return get404(); + if (path.startsWith('/robots.txt')) return getRobots(); + + if (path.startsWith('/source')) return getSource({ env, daCtx, head }); + if (path.startsWith('/list')) { + const { body, contentType, status } = await getList({ env, daCtx }); + return { + contentLength: body.length, + contentType, + status, + }; + } + if (path.startsWith('/properties')) { + const { body, status, contentType } = getProperties(); + return { status, contentType, contentLength: body.length }; + } + + return undefined; +} diff --git a/src/index.js b/src/index.js index 818a8a1..98f0f02 100644 --- a/src/index.js +++ b/src/index.js @@ -12,6 +12,7 @@ import getDaCtx from './utils/daCtx.js'; import daResp from './utils/daResp.js'; +import headHandler from './handlers/head.js'; import getHandler from './handlers/get.js'; import postHandler from './handlers/post.js'; import deleteHandler from './handlers/delete.js'; @@ -26,6 +27,9 @@ export default { let respObj; switch (req.method) { + case 'HEAD': + respObj = await headHandler({ env, daCtx }); + break; case 'GET': respObj = await getHandler({ env, daCtx }); break; diff --git a/src/storage/object/get.js b/src/storage/object/get.js index 6cc8650..8436bd8 100644 --- a/src/storage/object/get.js +++ b/src/storage/object/get.js @@ -12,6 +12,7 @@ import { S3Client, GetObjectCommand, + HeadObjectCommand, } from '@aws-sdk/client-s3'; import getS3Config from '../utils/config.js'; @@ -21,12 +22,12 @@ function buildInput({ org, key }) { return { Bucket, Key: key }; } -export default async function getObject(env, { org, key }) { +export default async function getObject(env, { org, key, head }) { const config = getS3Config(env); const client = new S3Client(config); const input = buildInput({ org, key }); - const command = new GetObjectCommand(input); + const command = head ? new HeadObjectCommand(input) : new GetObjectCommand(input); try { const resp = await client.send(command); @@ -34,8 +35,9 @@ export default async function getObject(env, { org, key }) { body: resp.Body, status: resp.$metadata.httpStatusCode, contentType: resp.ContentType, + contentLength: resp.ContentLength, }; } catch (e) { - return { body: '', status: 404 }; + return { body: '', status: 404, contentLength: 0 }; } } diff --git a/src/utils/daResp.js b/src/utils/daResp.js index 857e0ac..6286b16 100644 --- a/src/utils/daResp.js +++ b/src/utils/daResp.js @@ -9,12 +9,20 @@ * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ -export default function daResp({ status, body = '', contentType = 'application/json' }) { +export default function daResp({ + status, + body = '', + contentType = 'application/json', + contentLength, +}) { const headers = new Headers(); headers.append('Access-Control-Allow-Origin', '*'); - headers.append('Access-Control-Allow-Methods', 'GET, PUT, POST, DELETE'); + headers.append('Access-Control-Allow-Methods', 'HEAD, GET, PUT, POST, DELETE'); headers.append('Access-Control-Allow-Headers', '*'); headers.append('Content-Type', contentType); + if (contentLength) { + headers.append('Content-Length', contentLength); + } return new Response(body, { status, headers }); }