diff --git a/src/directory.jst b/src/directory.jst
index 844207b..032d59a 100644
--- a/src/directory.jst
+++ b/src/directory.jst
@@ -150,7 +150,7 @@
diff --git a/src/index.js b/src/index.js
index 34c2501..4a91105 100644
--- a/src/index.js
+++ b/src/index.js
@@ -359,6 +359,10 @@ const renderDirectory = async (current, acceptsJSON, handlers, methods, config,
}
details.relative = path.join(relativePath, details.base);
+ details.href = details.relative
+ .split('/')
+ .map(p => encodeURIComponent(p))
+ .join('/');
if (stats.isDirectory()) {
details.base += slashSuffix;
@@ -393,14 +397,15 @@ const renderDirectory = async (current, acceptsJSON, handlers, methods, config,
const toRoot = path.relative(current, absolutePath);
const directory = path.join(path.basename(current), toRoot, slashSuffix);
- const pathParts = directory.split(path.sep).filter(Boolean);
+ const pathParts = directory.split(path.sep)
+ .map(p => encodeURIComponent(p))
+ .filter(Boolean);
// Sort to list directories first, then sort alphabetically
files = files.sort((a, b) => {
const aIsDir = a.type === 'directory';
const bIsDir = b.type === 'directory';
- /* istanbul ignore next */
if (aIsDir && !bIsDir) {
return -1;
}
@@ -409,12 +414,10 @@ const renderDirectory = async (current, acceptsJSON, handlers, methods, config,
return 1;
}
- /* istanbul ignore next */
if (a.base < b.base) {
return -1;
}
- /* istanbul ignore next */
return 0;
}).filter(Boolean);
@@ -428,6 +431,7 @@ const renderDirectory = async (current, acceptsJSON, handlers, methods, config,
base: '..',
relative,
title: relative,
+ href: relative,
ext: ''
});
}
@@ -448,8 +452,8 @@ const renderDirectory = async (current, acceptsJSON, handlers, methods, config,
parents.shift();
subPaths.push({
- name: pathParts[index] + (isLast ? slashSuffix : '/'),
- url: index === 0 ? '' : parents.join('/') + slashSuffix
+ name: decodeURIComponent(pathParts[index]) + (isLast ? slashSuffix : '/'),
+ url: index === 0 ? '' : parents.map(p => encodeURIComponent(p)).join('/') + slashSuffix
});
}
diff --git a/test/fixtures/special#char/in#my#path.txt b/test/fixtures/special#char/in#my#path.txt
new file mode 100644
index 0000000..53d0671
--- /dev/null
+++ b/test/fixtures/special#char/in#my#path.txt
@@ -0,0 +1 @@
+If you could show the cabbage that I planted with my own hands to your emperor, he definitely wouldn't dare suggest that I replace the peace and happiness of this place with the storms of a never-satisfied greed.
diff --git a/test/integration.test.js b/test/integration.test.js
index d0e5d67..19cf976 100644
--- a/test/integration.test.js
+++ b/test/integration.test.js
@@ -1361,3 +1361,39 @@ test('etag header is set', async () => {
'"ba114dbc69e41e180362234807f093c3c4628f90"'
);
});
+
+test('escape paths with special chars', async () => {
+ const dirName = 'special#char';
+ const fileName = 'in#my#path.txt';
+
+ const sub = path.join(fixturesFull, dirName);
+ // const contents = await getDirectoryContents(sub, true);
+ const url = await getUrl();
+
+ console.log('url', url);
+ await new Promise((res) => setTimeout(res, 20_000));
+
+ {
+ const text = await fetch(`${url}/`).then(resp => resp.text());
+ expect(text).toContain(`${encodeURIComponent(dirName)}`);
+ }
+
+ {
+ const text = await fetch(`${url}/${encodeURIComponent(dirName)}/`).then(resp => resp.text());
+ expect(text).toContain(`${encodeURIComponent(dirName)}`);
+ expect(text).toContain(`${encodeURIComponent(fileName)}`);
+ }
+
+ {
+ const text = await fetch(`${url}/${encodeURIComponent(dirName)}/${encodeURIComponent(fileName)}`).then(resp => resp.text());
+ expect(text).toContain('cabbage');
+ }
+
+ // console.log('text', text);
+
+ // const type = response.headers.get('content-type');
+ // expect(type).toBe('text/html; charset=utf-8');
+
+ // expect(contents.every(item => text.includes(item))).toBe(true);
+ expect(true).toBe(true);
+});