Skip to content

Commit a0ecb70

Browse files
authored
fix: manually percent encode query items to allow values with + sign (#402)
* fix: manually percent encode query items to allow values with + sign * ci: fix ci not running when tests changes
1 parent 35ac278 commit a0ecb70

File tree

9 files changed

+54
-14
lines changed

9 files changed

+54
-14
lines changed

.github/workflows/auth.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ on:
44
pull_request:
55
paths:
66
- "Sources/Auth/**"
7-
- "Tests/Auth/**"
7+
- "Tests/AuthTests/**"
88
- ".github/workflows/auth.yml"
99
push:
1010
branches:
1111
- main
1212
paths:
1313
- "Sources/Auth/**"
14-
- "Tests/Auth/**"
14+
- "Tests/AuthTests/**"
1515
- ".github/workflows/auth.yml"
1616

1717
concurrency:

.github/workflows/functions.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ on:
44
pull_request:
55
paths:
66
- "Sources/Functions/**"
7-
- "Tests/Functions/**"
7+
- "Tests/FunctionsTests/**"
88
- ".github/workflows/functions.yml"
99
push:
1010
branches:
1111
- main
1212
paths:
1313
- "Sources/Functions/**"
14-
- "Tests/Functions/**"
14+
- "Tests/FunctionsTests/**"
1515
- ".github/workflows/functions.yml"
1616

1717
concurrency:

.github/workflows/postgrest.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ on:
44
pull_request:
55
paths:
66
- "Sources/PostgREST/**"
7-
- "Tests/PostgREST/**"
7+
- "Tests/PostgRESTTests/**"
88
- ".github/workflows/postgrest.yml"
99
push:
1010
branches:
1111
- main
1212
paths:
1313
- "Sources/PostgREST/**"
14-
- "Tests/PostgREST/**"
14+
- "Tests/PostgRESTTests/**"
1515
- ".github/workflows/postgrest.yml"
1616

1717
concurrency:

.github/workflows/realtime.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ on:
44
pull_request:
55
paths:
66
- "Sources/Realtime/**"
7-
- "Tests/Realtime/**"
7+
- "Tests/RealtimeTests/**"
88
- ".github/workflows/realtime.yml"
99
push:
1010
branches:
1111
- main
1212
paths:
1313
- "Sources/Realtime/**"
14-
- "Tests/Realtime/**"
14+
- "Tests/RealtimeTests/**"
1515
- ".github/workflows/realtime.yml"
1616

1717
concurrency:

.github/workflows/storage.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ on:
44
pull_request:
55
paths:
66
- "Sources/Storage/**"
7-
- "Tests/Storage/**"
7+
- "Tests/StorageTests/**"
88
- ".github/workflows/storage.yml"
99
push:
1010
branches:
1111
- main
1212
paths:
1313
- "Sources/Storage/**"
14-
- "Tests/Storage/**"
14+
- "Tests/StorageTests/**"
1515
- ".github/workflows/storage.yml"
1616

1717
concurrency:

.github/workflows/supabase.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ on:
44
pull_request:
55
paths:
66
- "Sources/Supabase/**"
7-
- "Tests/Supabase/**"
7+
- "Tests/SupabaseTests/**"
88
- ".github/workflows/supabase.yml"
99
push:
1010
branches:
1111
- main
1212
paths:
1313
- "Sources/Supabase/**"
14-
- "Tests/Supabase/**"
14+
- "Tests/SupabaseTests/**"
1515
- ".github/workflows/supabase.yml"
1616

1717
concurrency:

Sources/_Helpers/FoundationExtensions.swift

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,14 @@ extension URL {
4242
return
4343
}
4444

45-
let currentQueryItems = components.queryItems ?? []
46-
components.queryItems = currentQueryItems + queryItems
45+
let currentQueryItems = components.percentEncodedQueryItems ?? []
46+
47+
components.percentEncodedQueryItems = currentQueryItems + queryItems.map {
48+
URLQueryItem(
49+
name: escape($0.name),
50+
value: $0.value.map(escape)
51+
)
52+
}
4753

4854
if let newURL = components.url {
4955
self = newURL
@@ -56,3 +62,27 @@ extension URL {
5662
return url
5763
}
5864
}
65+
66+
func escape(_ string: String) -> String {
67+
string.addingPercentEncoding(withAllowedCharacters: .sbURLQueryAllowed) ?? string
68+
}
69+
70+
extension CharacterSet {
71+
/// Creates a CharacterSet from RFC 3986 allowed characters.
72+
///
73+
/// RFC 3986 states that the following characters are "reserved" characters.
74+
///
75+
/// - General Delimiters: ":", "#", "[", "]", "@", "?", "/"
76+
/// - Sub-Delimiters: "!", "$", "&", "'", "(", ")", "*", "+", ",", ";", "="
77+
///
78+
/// In RFC 3986 - Section 3.4, it states that the "?" and "/" characters should not be escaped to allow
79+
/// query strings to include a URL. Therefore, all "reserved" characters with the exception of "?" and "/"
80+
/// should be percent-escaped in the query string.
81+
static let sbURLQueryAllowed: CharacterSet = {
82+
let generalDelimitersToEncode = ":#[]@" // does not include "?" or "/" due to RFC 3986 - Section 3.4
83+
let subDelimitersToEncode = "!$&'()*+,;="
84+
let encodableDelimiters = CharacterSet(charactersIn: "\(generalDelimitersToEncode)\(subDelimitersToEncode)")
85+
86+
return CharacterSet.urlQueryAllowed.subtracting(encodableDelimiters)
87+
}()
88+
}

Tests/PostgRESTTests/BuildURLRequestTests.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,11 @@ final class BuildURLRequestTests: XCTestCase {
206206
.select()
207207
.containedBy("userMetadata", value: ["age": 18])
208208
},
209+
TestCase(name: "filter starting with non-alphanumeric") { client in
210+
client.from("users")
211+
.select()
212+
.eq("to", value: "+16505555555")
213+
},
209214
]
210215

211216
for testCase in testCases {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
curl \
2+
--header "Accept: application/json" \
3+
--header "Content-Type: application/json" \
4+
--header "X-Client-Info: postgrest-swift/x.y.z" \
5+
"https://example.supabase.co/users?select=*&to=eq.+16505555555"

0 commit comments

Comments
 (0)