Skip to content

Commit 2f9996a

Browse files
committed
Only allow index.html as index file.
Fixes #1131
1 parent 70ddc02 commit 2f9996a

File tree

2 files changed

+45
-26
lines changed

2 files changed

+45
-26
lines changed

lib/resource-mapper.js

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class ResourceMapper {
1414
rootPath,
1515
includeHost = false,
1616
defaultContentType = 'application/octet-stream',
17-
indexFilename = 'index',
17+
indexFilename = 'index.html',
1818
overrideTypes = { acl: 'text/turtle', meta: 'text/turtle' },
1919
fileSuffixes = ['.acl', '.meta']
2020
}) {
@@ -23,8 +23,9 @@ class ResourceMapper {
2323
this._includeHost = includeHost
2424
this._readdir = readdir
2525
this._defaultContentType = defaultContentType
26-
this._indexFilename = indexFilename
2726
this._types = { ...types, ...overrideTypes }
27+
this._indexFilename = indexFilename
28+
this._indexContentType = this._getContentTypeByExtension(indexFilename)
2829
this._isControlFile = new RegExp(`(?:${fileSuffixes.map(fs => fs.replace('.', '\\.')).join('|')})$`)
2930

3031
// If the host needs to be replaced on every call, pre-split the root URL
@@ -41,15 +42,17 @@ class ResourceMapper {
4142
}
4243

4344
// Maps the request for a given resource and representation format to a server file
44-
// When the URL ends with a '/', then files with the prefix 'index.' will be matched,
45-
// such as 'index.html' and 'index.ttl', unless searchIndex is false.
45+
// When searchIndex is true and the URL ends with a '/', indexFilename will be matched.
4646
async mapUrlToFile ({ url, contentType, createIfNotExists, searchIndex = true }) {
4747
let fullPath = this.getFullPath(url)
4848
let isIndex = searchIndex && fullPath.endsWith('/')
4949
let path
5050

5151
// Append index filename if the URL ends with a '/'
5252
if (isIndex) {
53+
if (createIfNotExists && contentType !== this._indexContentType) {
54+
throw new Error(`Index file needs to have ${this._indexContentType} as content type`)
55+
}
5356
fullPath += this._indexFilename
5457
}
5558

@@ -58,12 +61,7 @@ class ResourceMapper {
5861
path = fullPath
5962
// If the extension is not correct for the content type, append the correct extension
6063
if (searchIndex && this._getContentTypeByExtension(path) !== contentType) {
61-
// Append a '$', unless we map for the index
62-
// Because the index must _always_ have a proper extension when it is being created
63-
if (!isIndex) {
64-
path += '$'
65-
}
66-
path += contentType in extensions ? `.${extensions[contentType][0]}` : '.unknown'
64+
path += `$${contentType in extensions ? `.${extensions[contentType][0]}` : '.unknown'}`
6765
}
6866
// Determine the path of an existing file
6967
} else {
@@ -92,13 +90,13 @@ class ResourceMapper {
9290

9391
async _getMatchingFile (folder, filename, isIndex) {
9492
const files = await this._readdir(folder)
95-
const hasSameName = (f) => {
96-
return this._removeDollarExtension(f) === filename
97-
}
98-
const isIndexFile = (f) => {
99-
return isIndex && f.startsWith(this._indexFilename + '.') && !this._isControlFile.test(f)
93+
// Search for files with the same name (disregarding a dollar extension)
94+
if (!isIndex) {
95+
return files.find(f => this._removeDollarExtension(f) === filename)
96+
// Check if the index file exists
97+
} else if (files.includes(this._indexFilename)) {
98+
return this._indexFilename
10099
}
101-
return files.find(f => hasSameName(f) || isIndexFile(f))
102100
}
103101

104102
async getRepresentationUrlForResource (resourceUrl) {

test/unit/resource-mapper-test.js

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ describe('ResourceMapper', () => {
237237
contentType: 'text/n3'
238238
})
239239

240-
itMapsUrl(mapper, 'a URL ending with a slash to an index file when index.html is available',
240+
itMapsUrl(mapper, 'a URL ending with a slash when index.html is available',
241241
{
242242
url: 'http://localhost/space/'
243243
},
@@ -250,7 +250,19 @@ describe('ResourceMapper', () => {
250250
contentType: 'text/html'
251251
})
252252

253-
itMapsUrl(mapper, 'a URL ending with a slash to an index file when index$.html is available',
253+
itMapsUrl(mapper, 'a URL ending with a slash when index.ttl is available',
254+
{
255+
url: 'http://localhost/space/'
256+
},
257+
[
258+
`${rootPath}space/index.ttl`
259+
],
260+
{
261+
path: `${rootPath}space/`,
262+
contentType: 'application/octet-stream'
263+
})
264+
265+
itMapsUrl(mapper, 'a URL ending with a slash when index$.html is available',
254266
{
255267
url: 'http://localhost/space/'
256268
},
@@ -259,8 +271,20 @@ describe('ResourceMapper', () => {
259271
`${rootPath}space/index$.ttl`
260272
],
261273
{
262-
path: `${rootPath}space/index$.html`,
263-
contentType: 'text/html'
274+
path: `${rootPath}space/`,
275+
contentType: 'application/octet-stream'
276+
})
277+
278+
itMapsUrl(mapper, 'a URL ending with a slash when index$.ttl is available',
279+
{
280+
url: 'http://localhost/space/'
281+
},
282+
[
283+
`${rootPath}space/index$.ttl`
284+
],
285+
{
286+
path: `${rootPath}space/`,
287+
contentType: 'application/octet-stream'
264288
})
265289

266290
itMapsUrl(mapper, 'a URL ending with a slash to a folder when index.html is available but index is skipped',
@@ -298,7 +322,7 @@ describe('ResourceMapper', () => {
298322
contentType: 'application/octet-stream'
299323
})
300324

301-
itMapsUrl(mapper, 'a URL ending with a slash to an index file for text/html when index.html not is available',
325+
itMapsUrl(mapper, 'a URL ending with a slash for text/html when index.html is not available',
302326
{
303327
url: 'http://localhost/space/',
304328
contentType: 'text/html',
@@ -335,16 +359,13 @@ describe('ResourceMapper', () => {
335359
contentType: 'application/octet-stream'
336360
})
337361

338-
itMapsUrl(mapper, 'a URL ending with a slash to an index file for text/turtle when index.ttl not is available',
362+
itMapsUrl(mapper, 'a URL ending with a slash for text/turtle',
339363
{
340364
url: 'http://localhost/space/',
341365
contentType: 'text/turtle',
342366
createIfNotExists: true
343367
},
344-
{
345-
path: `${rootPath}space/index.ttl`,
346-
contentType: 'text/turtle'
347-
})
368+
new Error('Index file needs to have text/html as content type'))
348369

349370
// Security cases
350371

0 commit comments

Comments
 (0)