mirror of
https://github.com/denoland/std.git
synced 2024-11-22 04:59:05 +00:00
feat(http/file_server): add showIndex
option to serveDir (#2738)
This commit is contained in:
parent
3a582ee373
commit
b161285109
@ -282,12 +282,10 @@ export async function serveFile(
|
||||
|
||||
// TODO(bartlomieju): simplify this after deno.stat and deno.readDir are fixed
|
||||
async function serveDirIndex(
|
||||
req: Request,
|
||||
dirPath: string,
|
||||
options: {
|
||||
dotfiles: boolean;
|
||||
target: string;
|
||||
etagAlgorithm?: EtagAlgorithm;
|
||||
},
|
||||
): Promise<Response> {
|
||||
const showDotfiles = options.dotfiles;
|
||||
@ -314,13 +312,6 @@ async function serveDirIndex(
|
||||
const fileUrl = encodeURIComponent(posix.join(dirUrl, entry.name))
|
||||
.replaceAll("%2F", "/");
|
||||
const fileInfo = await Deno.stat(filePath);
|
||||
if (entry.name === "index.html" && entry.isFile) {
|
||||
// in case index.html as dir...
|
||||
return serveFile(req, filePath, {
|
||||
etagAlgorithm: options.etagAlgorithm,
|
||||
fileInfo,
|
||||
});
|
||||
}
|
||||
listEntry.push({
|
||||
mode: modeToString(entry.isDirectory, fileInfo.mode),
|
||||
size: entry.isFile ? fileLenToString(fileInfo.size ?? 0) : "",
|
||||
@ -515,6 +506,8 @@ export interface ServeDirOptions {
|
||||
showDirListing?: boolean;
|
||||
/** Serves dotfiles. Defaults to false. */
|
||||
showDotfiles?: boolean;
|
||||
/** Serves index.html as the index file of the directory. */
|
||||
showIndex?: boolean;
|
||||
/** Enable CORS via the "Access-Control-Allow-Origin" header. Defaults to false. */
|
||||
enableCors?: boolean;
|
||||
/** Do not print request level logs. Defaults to false. Defaults to false. */
|
||||
@ -562,14 +555,16 @@ export interface ServeDirOptions {
|
||||
* @param opts.urlRoot Specified that part is stripped from the beginning of the requested pathname.
|
||||
* @param opts.showDirListing Enable directory listing. Defaults to false.
|
||||
* @param opts.showDotfiles Serves dotfiles. Defaults to false.
|
||||
* @param opts.showIndex Serves index.html as the index file of the directory.
|
||||
* @param opts.enableCors Enable CORS via the "Access-Control-Allow-Origin" header. Defaults to false.
|
||||
* @param opts.quiet Do not print request level logs. Defaults to false.
|
||||
* @param opts.etagAlgorithm Etag The algorithm to use for generating the ETag. Defaults to "fnv1a".
|
||||
*/
|
||||
export async function serveDir(req: Request, opts: ServeDirOptions = {}) {
|
||||
let response: Response;
|
||||
let response: Response | undefined = undefined;
|
||||
const target = opts.fsRoot || ".";
|
||||
const urlRoot = opts.urlRoot;
|
||||
const showIndex = opts.showIndex ?? true;
|
||||
|
||||
try {
|
||||
let normalizedPath = normalizeURL(req.url);
|
||||
@ -585,12 +580,30 @@ export async function serveDir(req: Request, opts: ServeDirOptions = {}) {
|
||||
const fileInfo = await Deno.stat(fsPath);
|
||||
|
||||
if (fileInfo.isDirectory) {
|
||||
if (opts.showDirListing) {
|
||||
response = await serveDirIndex(req, fsPath, {
|
||||
if (showIndex) {
|
||||
try {
|
||||
const path = posix.join(fsPath, "index.html");
|
||||
const indexFileInfo = await Deno.lstat(path);
|
||||
if (indexFileInfo.isFile) {
|
||||
response = await serveFile(req, path, {
|
||||
etagAlgorithm: opts.etagAlgorithm,
|
||||
fileInfo: indexFileInfo,
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
if (!(e instanceof Deno.errors.NotFound)) {
|
||||
throw e;
|
||||
}
|
||||
// pass
|
||||
}
|
||||
}
|
||||
if (!response && opts.showDirListing) {
|
||||
response = await serveDirIndex(fsPath, {
|
||||
dotfiles: opts.showDotfiles || false,
|
||||
target,
|
||||
});
|
||||
} else {
|
||||
}
|
||||
if (!response) {
|
||||
throw new Deno.errors.NotFound();
|
||||
}
|
||||
} else {
|
||||
|
@ -1046,6 +1046,35 @@ Deno.test(
|
||||
},
|
||||
);
|
||||
|
||||
Deno.test(
|
||||
"serveDir serves index.html when showIndex is true",
|
||||
async () => {
|
||||
const url = "http://localhost:4507/http/testdata/subdir-with-index/";
|
||||
const expectedText = "This is subdir-with-index/index.html";
|
||||
{
|
||||
const res = await serveDir(new Request(url), { showIndex: true });
|
||||
assertEquals(res.status, 200);
|
||||
assertStringIncludes(await res.text(), expectedText);
|
||||
}
|
||||
|
||||
{
|
||||
// showIndex is true by default
|
||||
const res = await serveDir(new Request(url));
|
||||
assertEquals(res.status, 200);
|
||||
assertStringIncludes(await res.text(), expectedText);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
Deno.test(
|
||||
"serveDir doesn't serve index.html when showIndex is false",
|
||||
async () => {
|
||||
const url = "http://localhost:4507/http/testdata/subdir-with-index/";
|
||||
const res = await serveDir(new Request(url), { showIndex: false });
|
||||
assertEquals(res.status, 404);
|
||||
},
|
||||
);
|
||||
|
||||
Deno.test(
|
||||
"file_server returns 304 for requests with if-none-match set with the etag but with W/ prefixed etag in request headers.",
|
||||
async () => {
|
||||
|
1
http/testdata/subdir-with-index/index.html
vendored
Normal file
1
http/testdata/subdir-with-index/index.html
vendored
Normal file
@ -0,0 +1 @@
|
||||
This is subdir-with-index/index.html
|
Loading…
Reference in New Issue
Block a user