Skip to content

Commit c8c90e9

Browse files
authored
Merge pull request #1193 from shockey/bug/1184-rfc3986-query-param-value-escaping
OAS3 Query Parameter value escaping
2 parents da237e5 + 7550981 commit c8c90e9

File tree

7 files changed

+2826
-2486
lines changed

7 files changed

+2826
-2486
lines changed

src/execute/oas3/parameter-builders.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ function query({req, value, parameter}) {
4343
key: k,
4444
value: v,
4545
style: 'deepObject',
46-
escape: !parameter.allowReserved,
46+
escape: parameter.allowReserved ? 'unsafe' : 'reserved',
4747
}),
4848
skipEncoding: true
4949
}
@@ -66,8 +66,9 @@ function query({req, value, parameter}) {
6666
key: k,
6767
value: v,
6868
style: parameter.style || 'form',
69-
escape: !parameter.allowReserved,
70-
})
69+
escape: parameter.allowReserved ? 'unsafe' : 'reserved',
70+
}),
71+
skipEncoding: true
7172
}
7273
})
7374
}
@@ -78,7 +79,7 @@ function query({req, value, parameter}) {
7879
value,
7980
style: parameter.style || 'form',
8081
explode: typeof parameter.explode === 'undefined' ? true : parameter.explode,
81-
escape: !parameter.allowReserved,
82+
escape: parameter.allowReserved ? 'unsafe' : 'reserved',
8283
}),
8384
skipEncoding: true
8485
}

src/execute/oas3/style-serializer.js

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,36 @@
11
import encodeToRFC3986 from 'encode-3986'
22

3+
const isRfc3986Reserved = char => ':/?#[]@!$&\'()*+,;='.indexOf(char) > -1
4+
const isRrc3986Unreserved = (char) => {
5+
return (/^[a-z0-9\-._~]+$/i).test(char)
6+
}
7+
8+
function encodeDisallowedCharacters(str, {escape}) {
9+
if (typeof str === 'number') {
10+
str = str.toString()
11+
}
12+
if (typeof str !== 'string' || !str.length) {
13+
return str
14+
}
15+
16+
if (!escape) {
17+
return str
18+
}
19+
20+
return str.split('').map((char) => {
21+
if (isRrc3986Unreserved(char)) {
22+
return char
23+
}
24+
25+
if (isRfc3986Reserved(char) && escape === 'unsafe') {
26+
return char
27+
}
28+
29+
// percent-encode: char -> ASCII code point num -> hex string -> upcase
30+
return `%${char.charCodeAt(0).toString(16).toUpperCase()}`
31+
}).join('')
32+
}
33+
334
export default function (config) {
435
const {value} = config
536

@@ -9,14 +40,13 @@ export default function (config) {
940
else if (typeof value === 'object') {
1041
return encodeObject(config)
1142
}
12-
1343
return encodePrimitive(config)
1444
}
1545

16-
const escapeFn = str => encodeURIComponent(str)
17-
1846
function encodeArray({key, value, style, explode, escape}) {
19-
const valueEncoder = escape ? a => encodeToRFC3986(a) : a => a
47+
const valueEncoder = str => encodeDisallowedCharacters(str, {
48+
escape
49+
})
2050

2151
if (style === 'simple') {
2252
return value.map(val => valueEncoder(val)).join(',')
@@ -36,25 +66,26 @@ function encodeArray({key, value, style, explode, escape}) {
3666
}
3767

3868
if (style === 'form') {
39-
const commaValue = escape ? escapeFn(',') : ','
40-
const after = explode ? `&${key}=` : commaValue
69+
const after = explode ? `&${key}=` : ','
4170
return value.map(val => valueEncoder(val)).join(after)
4271
}
4372

4473
if (style === 'spaceDelimited') {
4574
const after = explode ? `${key}=` : ''
46-
return value.map(val => valueEncoder(val)).join(`${escapeFn(' ')}${after}`)
75+
return value.map(val => valueEncoder(val)).join(` ${after}`)
4776
}
4877

4978
if (style === 'pipeDelimited') {
5079
const after = explode ? `${key}=` : ''
51-
const separator = escape ? escapeFn('|') : '|'
52-
return value.map(val => valueEncoder(val)).join(`${separator}${after}`)
80+
return value.map(val => valueEncoder(val)).join(`|${after}`)
5381
}
5482
}
5583

5684
function encodeObject({key, value, style, explode, escape}) {
57-
const valueEncoder = escape ? a => encodeToRFC3986(a) : a => a
85+
const valueEncoder = str => encodeDisallowedCharacters(str, {
86+
escape
87+
})
88+
5889
const valueKeys = Object.keys(value)
5990

6091
if (style === 'simple') {
@@ -107,8 +138,10 @@ function encodeObject({key, value, style, explode, escape}) {
107138
}
108139
}
109140

110-
function encodePrimitive({key, value, style, explode, escape}) {
111-
const valueEncoder = escape ? a => encodeToRFC3986(a) : a => a
141+
function encodePrimitive({key, value, style, escape}) {
142+
const valueEncoder = str => encodeDisallowedCharacters(str, {
143+
escape
144+
})
112145

113146
if (style === 'simple') {
114147
return valueEncoder(value)

0 commit comments

Comments
 (0)