Skip to content

Commit

Permalink
BREAKING(http): deprecate enum Status in favour of STATUS_CODES o…
Browse files Browse the repository at this point in the history
…bject (denoland#3781)
  • Loading branch information
iuioiua committed Nov 17, 2023
1 parent f49fc15 commit 2f324fb
Show file tree
Hide file tree
Showing 6 changed files with 366 additions and 202 deletions.
81 changes: 48 additions & 33 deletions http/file_server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,15 @@ import { resolve } from "../path/resolve.ts";
import { SEP_PATTERN } from "../path/separator.ts";
import { contentType } from "../media_types/content_type.ts";
import { calculate, ifNoneMatch } from "./etag.ts";
import { isRedirectStatus, Status, STATUS_TEXT } from "./status.ts";
import {
isRedirectStatus,
STATUS_CODE,
STATUS_TEXT,
type StatusCode,
} from "./status.ts";
import { ByteSliceStream } from "../streams/byte_slice_stream.ts";
import { parseArgs } from "../cli/parse_args.ts";
import { red } from "../fmt/colors.ts";
import { deepMerge } from "../collections/deep_merge.ts";
import { VERSION } from "../version.ts";
import { format as formatBytes } from "../fmt/bytes.ts";

Expand Down Expand Up @@ -87,22 +91,9 @@ function modeToString(isDir: boolean, maybeMode: number | null): string {
return output;
}

/**
* Internal utility for returning a standardized response, automatically defining the body, status code and status text, according to the response type.
*/
function createCommonResponse(
status: Status,
body?: BodyInit | null,
init?: ResponseInit,
): Response {
if (body === undefined) {
body = STATUS_TEXT[status];
}
init = deepMerge({
status,
statusText: STATUS_TEXT[status],
}, init ?? {});
return new Response(body, init);
function createStandardResponse(status: StatusCode, init?: ResponseInit) {
const statusText = STATUS_TEXT[status];
return new Response(statusText, { status, statusText, ...init });
}

/**
Expand Down Expand Up @@ -170,15 +161,15 @@ export async function serveFile(
} catch (error) {
if (error instanceof Deno.errors.NotFound) {
await req.body?.cancel();
return createCommonResponse(Status.NotFound);
return createStandardResponse(STATUS_CODE.NotFound);
} else {
throw error;
}
}

if (fileInfo.isDirectory) {
await req.body?.cancel();
return createCommonResponse(Status.NotFound);
return createStandardResponse(STATUS_CODE.NotFound);
}

const headers = createBaseHeaders();
Expand Down Expand Up @@ -214,7 +205,12 @@ export async function serveFile(
fileInfo.mtime.getTime() <
new Date(ifModifiedSinceValue).getTime() + 1000)
) {
return createCommonResponse(Status.NotModified, null, { headers });
const status = STATUS_CODE.NotModified;
return new Response(null, {
status,
statusText: STATUS_TEXT[status],
headers,
});
}
}

Expand All @@ -241,7 +237,12 @@ export async function serveFile(
headers.set("content-length", `${fileSize}`);

const file = await Deno.open(filePath);
return createCommonResponse(Status.OK, file.readable, { headers });
const status = STATUS_CODE.OK;
return new Response(file.readable, {
status,
statusText: STATUS_TEXT[status],
headers,
});
}

// Return 416 Range Not Satisfiable if invalid range header value
Expand All @@ -253,9 +254,8 @@ export async function serveFile(
// Set the "Content-range" header
headers.set("content-range", `bytes */${fileSize}`);

return createCommonResponse(
Status.RequestedRangeNotSatisfiable,
undefined,
return createStandardResponse(
STATUS_CODE.RangeNotSatisfiable,
{ headers },
);
}
Expand All @@ -276,14 +276,24 @@ export async function serveFile(
await file.seek(start, Deno.SeekMode.Start);
const sliced = file.readable
.pipeThrough(new ByteSliceStream(0, contentLength - 1));
return createCommonResponse(Status.PartialContent, sliced, { headers });
const status = STATUS_CODE.PartialContent;
return new Response(sliced, {
status,
statusText: STATUS_TEXT[status],
headers,
});
}

// Set content length
headers.set("content-length", `${fileSize}`);

const file = await Deno.open(filePath);
return createCommonResponse(Status.OK, file.readable, { headers });
const status = STATUS_CODE.OK;
return new Response(file.readable, {
status,
statusText: STATUS_TEXT[status],
headers,
});
}

async function serveDirIndex(
Expand Down Expand Up @@ -358,19 +368,24 @@ async function serveDirIndex(
const headers = createBaseHeaders();
headers.set("content-type", "text/html; charset=UTF-8");

return createCommonResponse(Status.OK, page, { headers });
const status = STATUS_CODE.OK;
return new Response(page, {
status,
statusText: STATUS_TEXT[status],
headers,
});
}

function serveFallback(maybeError: unknown): Response {
if (maybeError instanceof URIError) {
return createCommonResponse(Status.BadRequest);
return createStandardResponse(STATUS_CODE.BadRequest);
}

if (maybeError instanceof Deno.errors.NotFound) {
return createCommonResponse(Status.NotFound);
return createStandardResponse(STATUS_CODE.NotFound);
}

return createCommonResponse(Status.InternalServerError);
return createStandardResponse(STATUS_CODE.InternalServerError);
}

function serverLog(req: Request, status: number) {
Expand Down Expand Up @@ -642,7 +657,7 @@ async function createServeDirResponse(
let normalizedPath = posixNormalize(decodedUrl);

if (urlRoot && !normalizedPath.startsWith("/" + urlRoot)) {
return createCommonResponse(Status.NotFound);
return createStandardResponse(STATUS_CODE.NotFound);
}

// Redirect paths like `/foo////bar` and `/foo/bar/////` to normalized paths.
Expand Down Expand Up @@ -714,7 +729,7 @@ async function createServeDirResponse(
return serveDirIndex(fsPath, { urlRoot, showDotfiles, target, quiet });
}

return createCommonResponse(Status.NotFound);
return createStandardResponse(STATUS_CODE.NotFound);
}

function logError(error: unknown) {
Expand Down
6 changes: 3 additions & 3 deletions http/file_server_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,7 @@ Deno.test("serveDir() handles bad range request (bytes=500-200)", async () => {

assertEquals(res.headers.get("content-range"), `bytes */${TEST_FILE_SIZE}`);
assertEquals(res.status, 416);
assertEquals(res.statusText, "Requested Range Not Satisfiable");
assertEquals(res.statusText, "Range Not Satisfiable");
});

Deno.test("serveDir() handles bad range request (bytes=99999-999999)", async () => {
Expand All @@ -504,7 +504,7 @@ Deno.test("serveDir() handles bad range request (bytes=99999-999999)", async ()

assertEquals(res.headers.get("content-range"), `bytes */${TEST_FILE_SIZE}`);
assertEquals(res.status, 416);
assertEquals(res.statusText, "Requested Range Not Satisfiable");
assertEquals(res.statusText, "Range Not Satisfiable");
});

Deno.test("serveDir() handles bad range request (bytes=99999)", async () => {
Expand All @@ -516,7 +516,7 @@ Deno.test("serveDir() handles bad range request (bytes=99999)", async () => {

assertEquals(res.headers.get("content-range"), `bytes */${TEST_FILE_SIZE}`);
assertEquals(res.status, 416);
assertEquals(res.statusText, "Requested Range Not Satisfiable");
assertEquals(res.statusText, "Range Not Satisfiable");
});

Deno.test("serveDir() ignores bad range request (bytes=100)", async () => {
Expand Down
1 change: 1 addition & 0 deletions http/http_status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
* console.log(STATUS_TEXT[Status.NotFound]); //=> "Not Found"
* ```
*
* @example
* ```ts
* import { isErrorStatus } from "https://deno.land/std@$STD_VERSION/http/http_status.ts";
*
Expand Down
Loading

0 comments on commit 2f324fb

Please sign in to comment.