Skip to content

Commit 63c749c

Browse files
authoredNov 5, 2020
fix(encoding): decode params (#3350)
* fix(encoding): decode params This change forces users to encode their `path` in routes but also fixes existing problems with route location that were provided as string and not encoded. Specially with the slash character, allowing it to be encoded and decoded properly. * feat: warn against unencoded routes
1 parent da34ccd commit 63c749c

File tree

5 files changed

+29
-19
lines changed

5 files changed

+29
-19
lines changed
 

‎examples/basic/app.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ const router = new VueRouter({
4545
{ path: '/', component: Home },
4646
{ path: '/foo', component: Foo },
4747
{ path: '/bar', component: Bar },
48-
{ path: '/é', component: Unicode },
48+
{ path: encodeURI('/é'), component: Unicode },
4949
{ path: '/query/:q', component: Query }
5050
]
5151
})
@@ -76,9 +76,9 @@ const vueInstance = new Vue({
7676
<router-link tag="li" to="/bar" :event="['mousedown', 'touchstart']">
7777
<a>/bar</a>
7878
</router-link>
79-
<li><router-link to="">/é</router-link></li>
80-
<li><router-link to="/é?t=%25ñ">/é?t=%ñ</router-link></li>
81-
<li><router-link to="/é#%25ñ">/é#%25ñ</router-link></li>
79+
<li><router-link :to="encodeURI('/é')">/é</router-link></li>
80+
<li><router-link :to="encodeURI('/é?t=%ñ')">/é?t=%ñ</router-link></li>
81+
<li><router-link :to="encodeURI('/é#%ñ')">/é#%25ñ</router-link></li>
8282
<router-link to="/foo" v-slot="props">
8383
<li :class="[props.isActive && 'active', props.isExactActive && 'exact-active']">
8484
<a :href="props.href" @click="props.navigate">{{ props.route.path }} (with v-slot).</a>

‎examples/hash-mode/app.js

+6-6
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ const router = new VueRouter({
4545
{ path: '/', component: Home }, // all paths are defined without the hash.
4646
{ path: '/foo', component: Foo },
4747
{ path: '/bar', component: Bar },
48-
{ path: '/é', component: Unicode },
49-
{ path: '/é/:unicode', component: Unicode },
48+
{ path: encodeURI('/é'), component: Unicode },
49+
{ path: encodeURI('/é/:unicode'), component: Unicode },
5050
{ path: '/query/:q', component: Query, name: 'param' }
5151
]
5252
})
@@ -64,10 +64,10 @@ const vueInstance = new Vue({
6464
<li><router-link to="/foo">/foo</router-link></li>
6565
<li><router-link to="/bar">/bar</router-link></li>
6666
<router-link tag="li" to="/bar">/bar</router-link>
67-
<li><router-link to="">/é</router-link></li>
68-
<li><router-link to="/é/ñ">/é/ñ</router-link></li>
69-
<li><router-link to="/é/ñ?t=%25ñ">/é/ñ?t=%ñ</router-link></li>
70-
<li><router-link to="/é/ñ#é">/é/ñ#é</router-link></li>
67+
<li><router-link :to="encodeURI('/é')">/é</router-link></li>
68+
<li><router-link :to="encodeURI('/é/ñ')">/é/ñ</router-link></li>
69+
<li><router-link :to="encodeURI('/é/ñ?t=%ñ')">/é/ñ?t=%ñ</router-link></li>
70+
<li><router-link :to="encodeURI('/é/ñ#é')">/é/ñ#é</router-link></li>
7171
<li><router-link to="/query/A%25">/query/A%</router-link></li>
7272
<li><router-link :to="{ name: 'param', params: { q: 'A%' }}">/query/A% (object)</router-link></li>
7373
<li><router-link to="/query/A%2FE">/query/A%2FE</router-link></li>

‎src/create-matcher.js

+2-9
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { createRoute } from './util/route'
77
import { fillParams } from './util/params'
88
import { createRouteMap } from './create-route-map'
99
import { normalizeLocation } from './util/location'
10+
import { decode } from './util/query'
1011

1112
export type Matcher = {
1213
match: (raw: RawLocation, current?: Route, redirectedFrom?: Location) => Route;
@@ -175,14 +176,6 @@ function matchRoute (
175176
path: string,
176177
params: Object
177178
): boolean {
178-
try {
179-
path = decodeURI(path)
180-
} catch (err) {
181-
if (process.env.NODE_ENV !== 'production') {
182-
warn(false, `Error decoding "${path}". Leaving it intact.`)
183-
}
184-
}
185-
186179
const m = path.match(regex)
187180

188181
if (!m) {
@@ -195,7 +188,7 @@ function matchRoute (
195188
const key = regex.keys[i - 1]
196189
if (key) {
197190
// Fix #1994: using * with props: true generates a param named 0
198-
params[key.name || 'pathMatch'] = m[i]
191+
params[key.name || 'pathMatch'] = typeof m[i] === 'string' ? decode(m[i]) : m[i]
199192
}
200193
}
201194

‎src/create-route-map.js

+8
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,14 @@ function addRouteRecord (
7070
path || name
7171
)} cannot be a ` + `string id. Use an actual component instead.`
7272
)
73+
74+
warn(
75+
// eslint-disable-next-line no-control-regex
76+
!/[^\u0000-\u007F]+/.test(path),
77+
`Route with path "${path}" contains unencoded characters, make sure ` +
78+
`your path is correctly encoded before passing it to the router. Use ` +
79+
`encodeURI to encode static segments of your path.`
80+
)
7381
}
7482

7583
const pathToRegexpOptions: PathToRegexpOptions =

‎test/unit/specs/create-map.spec.js

+9
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,15 @@ describe('Creating Route Map', function () {
8181
)
8282
})
8383

84+
it('warns about unencoded entities', function () {
85+
process.env.NODE_ENV = 'development'
86+
maps = createRouteMap([{ path: '/é', component: Home }])
87+
expect(console.warn).toHaveBeenCalledTimes(1)
88+
expect(console.warn.calls.argsFor(0)[0]).toMatch(
89+
'vue-router] Route with path "/é"'
90+
)
91+
})
92+
8493
it('in development, throws if path is missing', function () {
8594
process.env.NODE_ENV = 'development'
8695
expect(() => {

0 commit comments

Comments
 (0)