fix: encoding issues with payload paths (#8738)

- fix(generator): decode full static filesystem paths
- fix(vue-app): check decoded path against manifest
- fix(vue-app): prevent double encoding for urls

Co-authored-by: Pooya Parsa <pyapar@gmail.com>
This commit is contained in:
Daniel Roe 2021-02-02 12:38:54 +00:00 committed by GitHub
parent f917297a70
commit 6a8339e4c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 30 additions and 7 deletions

View File

@ -343,7 +343,7 @@ export default class Generator {
// Save Static Assets // Save Static Assets
if (this.staticAssetsDir && renderContext.staticAssets) { if (this.staticAssetsDir && renderContext.staticAssets) {
for (const asset of renderContext.staticAssets) { for (const asset of renderContext.staticAssets) {
const assetPath = path.join(this.staticAssetsDir, asset.path) const assetPath = path.join(this.staticAssetsDir, decodeURI(asset.path))
await fsExtra.ensureDir(path.dirname(assetPath)) await fsExtra.ensureDir(path.dirname(assetPath))
await fsExtra.writeFile(assetPath, asset.src, 'utf-8') await fsExtra.writeFile(assetPath, asset.src, 'utf-8')
} }

View File

@ -1,5 +1,5 @@
import Vue from 'vue' import Vue from 'vue'
import { parsePath, withoutTrailingSlash } from 'ufo' import { parsePath, withoutTrailingSlash, normalizeURL } from 'ufo'
<% utilsImports = [ <% utilsImports = [
...(features.asyncData || features.fetch) ? [ ...(features.asyncData || features.fetch) ? [
'getMatchedComponentsInstances', 'getMatchedComponentsInstances',
@ -317,7 +317,7 @@ export default {
}, },
<% if (nuxtOptions.generate.manifest) { %> <% if (nuxtOptions.generate.manifest) { %>
async fetchStaticManifest() { async fetchStaticManifest() {
return window.__NUXT_IMPORT__('manifest.js', encodeURI(urlJoin(this.getStaticAssetsPath(), 'manifest.js'))) return window.__NUXT_IMPORT__('manifest.js', normalizeURL(urlJoin(this.getStaticAssetsPath(), 'manifest.js')))
}, },
<% } %> <% } %>
setPagePayload(payload) { setPagePayload(payload) {
@ -328,14 +328,14 @@ export default {
<% if (nuxtOptions.generate.manifest) { %> <% if (nuxtOptions.generate.manifest) { %>
const manifest = await this.fetchStaticManifest() const manifest = await this.fetchStaticManifest()
const path = this.getRoutePath(route) const path = this.getRoutePath(route)
if (!manifest.routes.includes(path)) { if (!manifest.routes.includes(decodeURI(path))) {
if (!prefetch) { this.setPagePayload(false) } if (!prefetch) { this.setPagePayload(false) }
throw new Error(`Route ${path} is not pre-rendered`) throw new Error(`Route ${path} is not pre-rendered`)
} }
<% } %> <% } %>
const src = urlJoin(this.getStaticAssetsPath(route), 'payload.js') const src = urlJoin(this.getStaticAssetsPath(route), 'payload.js')
try { try {
const payload = await window.__NUXT_IMPORT__(decodeURI(route), encodeURI(src)) const payload = await window.__NUXT_IMPORT__(decodeURI(route), normalizeURL(src))
if (!prefetch) { this.setPagePayload(payload) } if (!prefetch) { this.setPagePayload(payload) }
return payload return payload
} catch (err) { } catch (err) {

View File

@ -1,7 +1,8 @@
import http from 'http' import http from 'http'
import { resolve } from 'path' import { join, resolve } from 'path'
import serveStatic from 'serve-static' import serveStatic from 'serve-static'
import finalhandler from 'finalhandler' import finalhandler from 'finalhandler'
import glob from 'glob'
import { Builder, Generator, getPort, loadFixture, Nuxt, rp } from '../utils' import { Builder, Generator, getPort, loadFixture, Nuxt, rp } from '../utils'
let port let port
@ -43,7 +44,21 @@ describe('full-static', () => {
const { body: html } = await rp(url('/payload')) const { body: html } = await rp(url('/payload'))
expect(html).toContain('<script src="https://cdn.nuxtjs.org/test/') expect(html).toContain('<script src="https://cdn.nuxtjs.org/test/')
expect(html).toContain('<link rel="preload" href="https://cdn.nuxtjs.org/test/_nuxt/static/') expect(html).toContain(
'<link rel="preload" href="https://cdn.nuxtjs.org/test/_nuxt/static/'
)
})
test('/encoding/中文', async () => {
const { body: html } = await rp(url('/encoding/中文'))
const paths = ['encoding/中文/state.js', 'encoding/中文/payload.js']
paths.forEach((path) => {
const files = glob.sync(join(distDir, '**', path))
expect(html).toContain(encodeURI(path))
expect(files).toContainEqual(expect.stringContaining(path))
})
}) })
// Close server and ask nuxt to stop listening to file changes // Close server and ask nuxt to stop listening to file changes

View File

@ -7,6 +7,9 @@
<NLink to="/store"> <NLink to="/store">
Store Store
</NLink> </NLink>
<NLink to="/encoding/中文">
Encoding
</NLink>
<NLink to="/pagination/1"> <NLink to="/pagination/1">
Pagination Pagination
</NLink> </NLink>

View File

@ -0,0 +1,5 @@
<template>
<div>
<h1>Encoded path</h1>
</div>
</template>