Update local publisher reader to respect case configs on read.

Signed-off-by: Eric Peterson <ericpeterson@spotify.com>
This commit is contained in:
Eric Peterson
2021-08-30 20:00:01 +02:00
parent 3624616e73
commit 31d4a456bf
2 changed files with 87 additions and 9 deletions
@@ -117,6 +117,13 @@ describe('local publisher', () => {
[resolvedDir]: {
'unsafe.html': '<html></html>',
'unsafe.svg': '<svg></svg>',
default: {
testkind: {
testname: {
'index.html': 'found it',
},
},
},
},
});
});
@@ -138,5 +145,37 @@ describe('local publisher', () => {
'content-type': 'text/plain; charset=utf-8',
});
});
it('should redirect case-sensitive triplet path to lower-case', async () => {
await request(app)
.get('/default/TestKind/TestName/index.html')
.expect(301)
.expect('Location', '/default/testkind/testname/index.html');
});
it('should resolve lower-case triplet path content eventually', async () => {
const response = await request(app)
.get('/default/TestKind/TestName/index.html')
.redirects(1);
expect(response.text).toEqual('found it');
});
it('should not redirect when legacy case setting is used', async () => {
const legacyConfig = new ConfigReader({
techdocs: {
legacyUseCaseSensitiveTripletPaths: true,
},
});
const legacyPublisher = new LocalPublish(
legacyConfig,
logger,
testDiscovery,
);
app = express().use(legacyPublisher.docsRouter());
await request(app)
.get('/default/TestKind/TestName/index.html')
.expect(404);
});
});
});
@@ -142,16 +142,55 @@ export class LocalPublish implements PublisherBase {
}
docsRouter(): express.Handler {
return express.static(staticDocsDir, {
// Handle content-type header the same as all other publishers.
setHeaders: (res, filePath) => {
const fileExtension = path.extname(filePath);
const headers = getHeadersForFileExtension(fileExtension);
for (const [header, value] of Object.entries(headers)) {
res.setHeader(header, value);
}
},
const router = express.Router();
// Redirect middleware ensuring that requests to case-sensitive entity
// triplet paths are always sent to lower-case versions.
router.use((req, res, next) => {
// If legacy path casing is on, let the request immediately continue.
if (this.legacyPathCasing) {
return next();
}
// Generate a lower-case entity triplet path.
const [_, namespace, kind, name, ...rest] = req.path.split('/');
// Ignore non-triplet objects.
if (!namespace || !kind || !name) {
return next();
}
const newPath = [
_,
namespace.toLowerCase(),
kind.toLowerCase(),
name.toLowerCase(),
...rest,
].join('/');
// If there was no change, then let express.static() handle the request.
if (newPath === req.path) {
return next();
}
// Otherwise, redirect to the new path.
return res.redirect(req.baseUrl + newPath, 301);
});
router.use(
express.static(staticDocsDir, {
// Handle content-type header the same as all other publishers.
setHeaders: (res, filePath) => {
const fileExtension = path.extname(filePath);
const headers = getHeadersForFileExtension(fileExtension);
for (const [header, value] of Object.entries(headers)) {
res.setHeader(header, value);
}
},
}),
);
return router;
}
async hasDocsBeenGenerated(entity: Entity): Promise<boolean> {