Skip to content

Commit 8796c4c

Browse files
jdhollandermcollina
authored andcommitted
Relative urls for static content (#164)
Fixes regression where relative urls for the static content became absolute, thus breaking reverse proxy usage. This commit reverts to relative urls for this content, taking into account whether the route that delivers them has a trailing slash or not.
1 parent 1f36cee commit 8796c4c

File tree

3 files changed

+86
-31
lines changed

3 files changed

+86
-31
lines changed

lib/index-html.js

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,35 @@
11
'use strict'
22

33
function indexHtml (opts) {
4-
return (url) => `<!-- HTML for static distribution bundle build -->
5-
<!DOCTYPE html>
6-
<html lang="en">
7-
<head>
8-
<meta charset="UTF-8">
9-
<title>${opts.theme?.title || 'Swagger UI'}</title>
10-
<link rel="stylesheet" type="text/css" href="${url}${opts.staticPrefix}/swagger-ui.css" />
11-
<link rel="stylesheet" type="text/css" href="${url}${opts.staticPrefix}/index.css" />
12-
${opts.theme && opts.theme.css ? opts.theme.css.map(css => `<link rel="stylesheet" type="text/css" href="${url}${opts.staticPrefix}/theme/${css.filename}" />\n`).join('') : ''}
13-
${opts.theme && opts.theme.favicon
14-
? opts.theme.favicon.map(favicon => `<link rel="${favicon.rel}" type="${favicon.type}" href="${url}${opts.staticPrefix}/theme/${favicon.filename}" sizes="${favicon.sizes}" />\n`).join('')
15-
: `
16-
<link rel="icon" type="image/png" href="${url}${opts.staticPrefix}/favicon-32x32.png" sizes="32x32" />
17-
<link rel="icon" type="image/png" href="${url}${opts.staticPrefix}/favicon-16x16.png" sizes="16x16" />
18-
`}
19-
</head>
20-
21-
<body>
22-
<div id="swagger-ui"></div>
23-
<script src="${url}${opts.staticPrefix}/swagger-ui-bundle.js" charset="UTF-8"> </script>
24-
<script src="${url}${opts.staticPrefix}/swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
25-
<script src="${url}${opts.staticPrefix}/swagger-initializer.js" charset="UTF-8"> </script>
26-
${opts.theme && opts.theme.js ? opts.theme.js.map(js => `<script src="${url}${opts.staticPrefix}/theme/${js.filename}" charset="UTF-8"> </script>\n`).join('') : ''}
27-
</body>
28-
</html>
29-
`
4+
return (hasTrailingSlash) => {
5+
const prefix = hasTrailingSlash ? `.${opts.staticPrefix}` : `.${opts.prefix}${opts.staticPrefix}`
6+
return `<!-- HTML for static distribution bundle build -->
7+
<!DOCTYPE html>
8+
<html lang="en">
9+
<head>
10+
<meta charset="UTF-8">
11+
<title>${opts.theme?.title || 'Swagger UI'}</title>
12+
<link rel="stylesheet" type="text/css" href="${prefix}/swagger-ui.css" />
13+
<link rel="stylesheet" type="text/css" href="${prefix}/index.css" />
14+
${opts.theme && opts.theme.css ? opts.theme.css.map(css => `<link rel="stylesheet" type="text/css" href="${prefix}/theme/${css.filename}" />\n`).join('') : ''}
15+
${opts.theme && opts.theme.favicon
16+
? opts.theme.favicon.map(favicon => `<link rel="${favicon.rel}" type="${favicon.type}" href="${prefix}/theme/${favicon.filename}" sizes="${favicon.sizes}" />\n`).join('')
17+
: `
18+
<link rel="icon" type="image/png" href="${prefix}/favicon-32x32.png" sizes="32x32" />
19+
<link rel="icon" type="image/png" href=".${opts.prefix}/favicon-16x16.png" sizes="16x16" />
20+
`}
21+
</head>
22+
23+
<body>
24+
<div id="swagger-ui"></div>
25+
<script src="${prefix}/swagger-ui-bundle.js" charset="UTF-8"> </script>
26+
<script src="${prefix}/swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
27+
<script src="${prefix}/swagger-initializer.js" charset="UTF-8"> </script>
28+
${opts.theme && opts.theme.js ? opts.theme.js.map(js => `<script src="${prefix}/theme/${js.filename}" charset="UTF-8"> </script>\n`).join('') : ''}
29+
</body>
30+
</html>
31+
`
32+
}
3033
}
3134

3235
module.exports = indexHtml

lib/routes.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,10 @@ function fastifySwagger (fastify, opts, done) {
112112
schema: { hide: true },
113113
...hooks,
114114
handler: (req, reply) => {
115+
const hasTrailingSlash = /\/$/.test(req.url)
115116
reply
116117
.header('content-type', 'text/html; charset=utf-8')
117-
.send(indexHtmlContent(req.url.replace(/\/$/, ''))) // remove trailing slash, as staticPrefix has a leading slash
118+
.send(indexHtmlContent(hasTrailingSlash)) // trailing slash alters the relative urls generated in the html
118119
}
119120
})
120121

test/route.test.js

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -548,8 +548,59 @@ test('/documentation should display index html with correct asset urls', async (
548548
url: '/documentation'
549549
})
550550

551-
t.equal(res.payload.includes('href="/documentation/static/index.css"'), true)
552-
t.equal(res.payload.includes('src="/documentation/static/theme/theme-js.js"'), true)
553-
t.equal(res.payload.includes('href="/documentation/index.css"'), false)
554-
t.equal(res.payload.includes('src="/documentation/theme/theme-js.js"'), false)
551+
t.equal(res.payload.includes('href="./documentation/static/index.css"'), true)
552+
t.equal(res.payload.includes('src="./documentation/static/theme/theme-js.js"'), true)
553+
t.equal(res.payload.includes('href="./documentation/index.css"'), false)
554+
t.equal(res.payload.includes('src="./documentation/theme/theme-js.js"'), false)
555+
})
556+
557+
test('/documentation/ should display index html with correct asset urls', async (t) => {
558+
t.plan(4)
559+
const fastify = Fastify()
560+
await fastify.register(fastifySwagger, swaggerOption)
561+
await fastify.register(fastifySwaggerUi, { theme: { js: [{ filename: 'theme-js.js' }] } })
562+
563+
const res = await fastify.inject({
564+
method: 'GET',
565+
url: '/documentation/'
566+
})
567+
568+
t.equal(res.payload.includes('href="./static/index.css"'), true)
569+
t.equal(res.payload.includes('src="./static/theme/theme-js.js"'), true)
570+
t.equal(res.payload.includes('href="./index.css"'), false)
571+
t.equal(res.payload.includes('src="./theme/theme-js.js"'), false)
572+
})
573+
574+
test('/docs should display index html with correct asset urls when documentation prefix is set', async (t) => {
575+
t.plan(4)
576+
const fastify = Fastify()
577+
await fastify.register(fastifySwagger, swaggerOption)
578+
await fastify.register(fastifySwaggerUi, { theme: { js: [{ filename: 'theme-js.js' }] }, routePrefix: '/docs' })
579+
580+
const res = await fastify.inject({
581+
method: 'GET',
582+
url: '/docs'
583+
})
584+
585+
t.equal(res.payload.includes('href="./docs/static/index.css"'), true)
586+
t.equal(res.payload.includes('src="./docs/static/theme/theme-js.js"'), true)
587+
t.equal(res.payload.includes('href="./docs/index.css"'), false)
588+
t.equal(res.payload.includes('src="./docs/theme/theme-js.js"'), false)
589+
})
590+
591+
test('/docs/ should display index html with correct asset urls when documentation prefix is set', async (t) => {
592+
t.plan(4)
593+
const fastify = Fastify()
594+
await fastify.register(fastifySwagger, swaggerOption)
595+
await fastify.register(fastifySwaggerUi, { theme: { js: [{ filename: 'theme-js.js' }] }, routePrefix: '/docs' })
596+
597+
const res = await fastify.inject({
598+
method: 'GET',
599+
url: '/docs/'
600+
})
601+
602+
t.equal(res.payload.includes('href="./static/index.css"'), true)
603+
t.equal(res.payload.includes('src="./static/theme/theme-js.js"'), true)
604+
t.equal(res.payload.includes('href="./index.css"'), false)
605+
t.equal(res.payload.includes('src="./theme/theme-js.js"'), false)
555606
})

0 commit comments

Comments
 (0)