Skip to content

Commit

Permalink
Relative urls for static content (#164)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
jdhollander authored Jul 19, 2024
1 parent 586cd3f commit 8006c05
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 31 deletions.
55 changes: 29 additions & 26 deletions lib/index-html.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,35 @@
'use strict'

function indexHtml (opts) {
return (url) => `<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>${opts.theme?.title || 'Swagger UI'}</title>
<link rel="stylesheet" type="text/css" href="${url}${opts.staticPrefix}/swagger-ui.css" />
<link rel="stylesheet" type="text/css" href="${url}${opts.staticPrefix}/index.css" />
${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('') : ''}
${opts.theme && opts.theme.favicon
? opts.theme.favicon.map(favicon => `<link rel="${favicon.rel}" type="${favicon.type}" href="${url}${opts.staticPrefix}/theme/${favicon.filename}" sizes="${favicon.sizes}" />\n`).join('')
: `
<link rel="icon" type="image/png" href="${url}${opts.staticPrefix}/favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="${url}${opts.staticPrefix}/favicon-16x16.png" sizes="16x16" />
`}
</head>
<body>
<div id="swagger-ui"></div>
<script src="${url}${opts.staticPrefix}/swagger-ui-bundle.js" charset="UTF-8"> </script>
<script src="${url}${opts.staticPrefix}/swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
<script src="${url}${opts.staticPrefix}/swagger-initializer.js" charset="UTF-8"> </script>
${opts.theme && opts.theme.js ? opts.theme.js.map(js => `<script src="${url}${opts.staticPrefix}/theme/${js.filename}" charset="UTF-8"> </script>\n`).join('') : ''}
</body>
</html>
`
return (hasTrailingSlash) => {
const prefix = hasTrailingSlash ? `.${opts.staticPrefix}` : `.${opts.prefix}${opts.staticPrefix}`
return `<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>${opts.theme?.title || 'Swagger UI'}</title>
<link rel="stylesheet" type="text/css" href="${prefix}/swagger-ui.css" />
<link rel="stylesheet" type="text/css" href="${prefix}/index.css" />
${opts.theme && opts.theme.css ? opts.theme.css.map(css => `<link rel="stylesheet" type="text/css" href="${prefix}/theme/${css.filename}" />\n`).join('') : ''}
${opts.theme && opts.theme.favicon
? opts.theme.favicon.map(favicon => `<link rel="${favicon.rel}" type="${favicon.type}" href="${prefix}/theme/${favicon.filename}" sizes="${favicon.sizes}" />\n`).join('')
: `
<link rel="icon" type="image/png" href="${prefix}/favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href=".${opts.prefix}/favicon-16x16.png" sizes="16x16" />
`}
</head>
<body>
<div id="swagger-ui"></div>
<script src="${prefix}/swagger-ui-bundle.js" charset="UTF-8"> </script>
<script src="${prefix}/swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
<script src="${prefix}/swagger-initializer.js" charset="UTF-8"> </script>
${opts.theme && opts.theme.js ? opts.theme.js.map(js => `<script src="${prefix}/theme/${js.filename}" charset="UTF-8"> </script>\n`).join('') : ''}
</body>
</html>
`
}
}

module.exports = indexHtml
3 changes: 2 additions & 1 deletion lib/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,10 @@ function fastifySwagger (fastify, opts, done) {
schema: { hide: true },
...hooks,
handler: (req, reply) => {
const hasTrailingSlash = /\/$/.test(req.url)
reply
.header('content-type', 'text/html; charset=utf-8')
.send(indexHtmlContent(req.url.replace(/\/$/, ''))) // remove trailing slash, as staticPrefix has a leading slash
.send(indexHtmlContent(hasTrailingSlash)) // trailing slash alters the relative urls generated in the html
}
})

Expand Down
59 changes: 55 additions & 4 deletions test/route.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -548,8 +548,59 @@ test('/documentation should display index html with correct asset urls', async (
url: '/documentation'
})

t.equal(res.payload.includes('href="/documentation/static/index.css"'), true)
t.equal(res.payload.includes('src="/documentation/static/theme/theme-js.js"'), true)
t.equal(res.payload.includes('href="/documentation/index.css"'), false)
t.equal(res.payload.includes('src="/documentation/theme/theme-js.js"'), false)
t.equal(res.payload.includes('href="./documentation/static/index.css"'), true)
t.equal(res.payload.includes('src="./documentation/static/theme/theme-js.js"'), true)
t.equal(res.payload.includes('href="./documentation/index.css"'), false)
t.equal(res.payload.includes('src="./documentation/theme/theme-js.js"'), false)
})

test('/documentation/ should display index html with correct asset urls', async (t) => {
t.plan(4)
const fastify = Fastify()
await fastify.register(fastifySwagger, swaggerOption)
await fastify.register(fastifySwaggerUi, { theme: { js: [{ filename: 'theme-js.js' }] } })

const res = await fastify.inject({
method: 'GET',
url: '/documentation/'
})

t.equal(res.payload.includes('href="./static/index.css"'), true)
t.equal(res.payload.includes('src="./static/theme/theme-js.js"'), true)
t.equal(res.payload.includes('href="./index.css"'), false)
t.equal(res.payload.includes('src="./theme/theme-js.js"'), false)
})

test('/docs should display index html with correct asset urls when documentation prefix is set', async (t) => {
t.plan(4)
const fastify = Fastify()
await fastify.register(fastifySwagger, swaggerOption)
await fastify.register(fastifySwaggerUi, { theme: { js: [{ filename: 'theme-js.js' }] }, routePrefix: '/docs' })

const res = await fastify.inject({
method: 'GET',
url: '/docs'
})

t.equal(res.payload.includes('href="./docs/static/index.css"'), true)
t.equal(res.payload.includes('src="./docs/static/theme/theme-js.js"'), true)
t.equal(res.payload.includes('href="./docs/index.css"'), false)
t.equal(res.payload.includes('src="./docs/theme/theme-js.js"'), false)
})

test('/docs/ should display index html with correct asset urls when documentation prefix is set', async (t) => {
t.plan(4)
const fastify = Fastify()
await fastify.register(fastifySwagger, swaggerOption)
await fastify.register(fastifySwaggerUi, { theme: { js: [{ filename: 'theme-js.js' }] }, routePrefix: '/docs' })

const res = await fastify.inject({
method: 'GET',
url: '/docs/'
})

t.equal(res.payload.includes('href="./static/index.css"'), true)
t.equal(res.payload.includes('src="./static/theme/theme-js.js"'), true)
t.equal(res.payload.includes('href="./index.css"'), false)
t.equal(res.payload.includes('src="./theme/theme-js.js"'), false)
})

0 comments on commit 8006c05

Please sign in to comment.