Skip to content

Commit

Permalink
Revert fix for URL encoding
Browse files Browse the repository at this point in the history
  • Loading branch information
grdsdev committed Oct 7, 2023
1 parent 8b7348b commit 1f7e0c7
Show file tree
Hide file tree
Showing 18 changed files with 125 additions and 128 deletions.
23 changes: 11 additions & 12 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,17 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/pointfreeco/swift-snapshot-testing",
"state" : {
"revision": "506b6052384d8e97a4bb16fe8680325351c23c64",
"version": "1.14.0"
}
},
{
"package": "swift-syntax",
"repositoryURL": "https://github.com/apple/swift-syntax.git",
"state": {
"branch": null,
"revision": "74203046135342e4a4a627476dd6caf8b28fe11b",
"version": "509.0.0"
}
"revision" : "506b6052384d8e97a4bb16fe8680325351c23c64",
"version" : "1.14.0"
}
},
{
"identity" : "swift-syntax",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-syntax.git",
"state" : {
"revision" : "74203046135342e4a4a627476dd6caf8b28fe11b",
"version" : "509.0.0"
}
}
],
Expand Down
50 changes: 49 additions & 1 deletion Sources/PostgREST/PostgrestBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ public class PostgrestBuilder {
}
}

if headers["Accept"] == nil {
headers["Accept"] = "application/json"
}
headers["Content-Type"] = "application/json"

if let schema = configuration.schema {
Expand Down Expand Up @@ -124,7 +127,9 @@ public class PostgrestBuilder {
}

if !queryParams.isEmpty {
components.queryItems = queryParams.map(URLQueryItem.init)
let percentEncodedQuery =
(components.percentEncodedQuery.map { $0 + "&" } ?? "") + self.query(queryParams)
components.percentEncodedQuery = percentEncodedQuery
}

guard let url = components.url else {
Expand All @@ -145,4 +150,47 @@ public class PostgrestBuilder {

return urlRequest
}

private func escape(_ string: String) -> String {
string.addingPercentEncoding(withAllowedCharacters: .postgrestURLQueryAllowed) ?? string
}

private func query(_ parameters: [(String, String?)]) -> String {
parameters.compactMap { key, value in
if let value {
return (key, value)
}
return nil
}
.map { key, value in
let escapedKey = escape(key)
let escapedValue = escape(value)
return "\(escapedKey)=\(escapedValue)"
}
.joined(separator: "&")
}
}

extension CharacterSet {
/// Creates a CharacterSet from RFC 3986 allowed characters.
///
/// RFC 3986 states that the following characters are "reserved" characters.
///
/// - General Delimiters: ":", "#", "[", "]", "@", "?", "/"
/// - Sub-Delimiters: "!", "$", "&", "'", "(", ")", "*", "+", ",", ";", "="
///
/// In RFC 3986 - Section 3.4, it states that the "?" and "/" characters should not be escaped to
/// allow
/// query strings to include a URL. Therefore, all "reserved" characters with the exception of "?"
/// and "/"
/// should be percent-escaped in the query string.
static let postgrestURLQueryAllowed: CharacterSet = {
let generalDelimitersToEncode =
":#[]@" // does not include "?" or "/" due to RFC 3986 - Section 3.4
let subDelimitersToEncode = "!$&'()*+,;="
let encodableDelimiters =
CharacterSet(charactersIn: "\(generalDelimitersToEncode)\(subDelimitersToEncode)")

return CharacterSet.urlQueryAllowed.subtracting(encodableDelimiters)
}()
}
70 changes: 0 additions & 70 deletions Sources/PostgREST/PostgrestClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -141,52 +141,6 @@ public actor PostgrestClient {
) throws -> PostgrestTransformBuilder {
try rpc(fn: fn, params: NoParams(), count: count)
}

func client<T>(_ client: APIClient, makeURLForRequest request: Request<T>) throws -> URL? {
func makeURL() -> URL? {
guard let url = request.url else {
return nil
}

return url.scheme == nil ? client.configuration.baseURL?
.appendingPathComponent(url.absoluteString) : url
}

guard let url = makeURL(), var components = URLComponents(
url: url,
resolvingAgainstBaseURL: false
) else {
throw URLError(.badURL)
}
if let query = request.query, !query.isEmpty {
let percentEncodedQuery = (components.percentEncodedQuery.map { $0 + "&" } ?? "") + self
.query(query)
components.percentEncodedQuery = percentEncodedQuery
}
guard let url = components.url else {
throw URLError(.badURL)
}
return url
}

private func escape(_ string: String) -> String {
string.addingPercentEncoding(withAllowedCharacters: .postgrestURLQueryAllowed) ?? string
}

private func query(_ parameters: [(String, String?)]) -> String {
parameters.compactMap { key, value in
if let value {
return (key, value)
}
return nil
}
.map { key, value in
let escapedKey = escape(key)
let escapedValue = escape(value)
return "\(escapedKey)=\(escapedValue)"
}
.joined(separator: "&")
}
}

private let supportedDateFormatters: [ISO8601DateFormatter] = [
Expand Down Expand Up @@ -232,27 +186,3 @@ extension JSONEncoder {
return encoder
}()
}

extension CharacterSet {
/// Creates a CharacterSet from RFC 3986 allowed characters.
///
/// RFC 3986 states that the following characters are "reserved" characters.
///
/// - General Delimiters: ":", "#", "[", "]", "@", "?", "/"
/// - Sub-Delimiters: "!", "$", "&", "'", "(", ")", "*", "+", ",", ";", "="
///
/// In RFC 3986 - Section 3.4, it states that the "?" and "/" characters should not be escaped to
/// allow
/// query strings to include a URL. Therefore, all "reserved" characters with the exception of "?"
/// and "/"
/// should be percent-escaped in the query string.
static let postgrestURLQueryAllowed: CharacterSet = {
let generalDelimitersToEncode =
":#[]@" // does not include "?" or "/" due to RFC 3986 - Section 3.4
let subDelimitersToEncode = "!$&'()*+,;="
let encodableDelimiters =
CharacterSet(charactersIn: "\(generalDelimitersToEncode)\(subDelimitersToEncode)")

return CharacterSet.urlQueryAllowed.subtracting(encodableDelimiters)
}()
}
2 changes: 1 addition & 1 deletion Tests/PostgRESTIntegrationTests/IntegrationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ final class IntegrationTests: XCTestCase {
.ilike(column: "email", value: "johndoe+test%").execute().value
XCTAssertEqual(
fetchedUsers[...],
users[1 ... 2]
users[1...2]
)
}
}
37 changes: 3 additions & 34 deletions Tests/PostgRESTTests/BuildURLRequestTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -89,16 +89,16 @@
.upsert(values: ["email": "johndoe@supabase.io"], ignoreDuplicates: true)
},
TestCase(name: "query with + character") { client in
client.from("users")
await client.from("users")
.select()
.eq(column: "id", value: "Cigányka-ér (0+400 cskm) vízrajzi állomás")
},
TestCase(name: "query with timestampz") { client in
client.from("tasks")
await client.from("tasks")
.select()
.gt(column: "received_at", value: "2023-03-23T15:50:30.511743+00:00")
.order(column: "received_at")
}
},
]

for testCase in testCases {
Expand All @@ -115,35 +115,4 @@
}
}

final class LockIsolated<Value>: @unchecked Sendable {
private let lock = NSRecursiveLock()
private var _value: Value

init(_ value: Value) {
self._value = value
}

@discardableResult
func withValue<T>(_ block: (inout Value) throws -> T) rethrows -> T {
try lock.sync {
var value = self._value
defer { self._value = value }
return try block(&value)
}
}

var value: Value {
lock.sync { self._value }
}
}

extension NSRecursiveLock {
@discardableResult
func sync<R>(work: () throws -> R) rethrows -> R {
lock()
defer { unlock() }
return try work()
}
}

#endif
39 changes: 39 additions & 0 deletions Tests/PostgRESTTests/Helpers/LockIsolated.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//
// File.swift
//
//
// Created by Guilherme Souza on 07/10/23.
//

import Foundation

final class LockIsolated<Value>: @unchecked Sendable {
private let lock = NSRecursiveLock()
private var _value: Value

init(_ value: Value) {
self._value = value
}

@discardableResult
func withValue<T>(_ block: (inout Value) throws -> T) rethrows -> T {
try lock.sync {
var value = self._value
defer { self._value = value }
return try block(&value)
}
}

var value: Value {
lock.sync { self._value }
}
}

extension NSRecursiveLock {
@discardableResult
func sync<R>(work: () throws -> R) rethrows -> R {
lock()
defer { unlock() }
return try work()
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
curl \
--request POST \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--header "X-Client-Info: postgrest-swift/1.0.1" \
--header "X-Client-Info: postgrest-swift/1.0.2" \
"https://example.supabase.co/rpc/test_fcn"
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
curl \
--request POST \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--header "X-Client-Info: postgrest-swift/1.0.1" \
--header "X-Client-Info: postgrest-swift/1.0.2" \
--data "{\"KEY\":\"VALUE\"}" \
"https://example.supabase.co/rpc/test_fcn"
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
curl \
--request POST \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--header "X-Client-Info: postgrest-swift/1.0.1" \
--header "X-Client-Info: postgrest-swift/1.0.2" \
--data "{\"email\":\"johndoe@supabase.io\"}" \
"https://example.supabase.co/users"
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
curl \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--header "X-Client-Info: postgrest-swift/1.0.2" \
"https://example.supabase.co/users?id=eq.Cig%C3%A1nyka-%C3%A9r%20(0+400%20cskm)%20v%C3%ADzrajzi%20%C3%A1llom%C3%A1s&select=*"
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
curl \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--header "X-Client-Info: postgrest-swift/1.0.2" \
"https://example.supabase.co/tasks?order=received_at.asc.nullslast&received_at=gt.2023-03-23T15:50:30.511743+00:00&select=*"
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
curl \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--header "X-Client-Info: postgrest-swift/1.0.1" \
--header "X-Client-Info: postgrest-swift/1.0.2" \
"https://example.supabase.co/users?email=like.%25@supabase.co&select=*"
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
curl \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--header "X-Client-Info: postgrest-swift/1.0.1" \
--header "X-Client-Info: postgrest-swift/1.0.2" \
"https://example.supabase.co/todos?column=eq.Some%20value&column=neq.Some%20value&column=gt.Some%20value&column=gte.Some%20value&column=lt.Some%20value&column=lte.Some%20value&column=like.Some%20value&column=ilike.Some%20value&column=is.Some%20value&column=in.Some%20value&column=cs.Some%20value&column=cd.Some%20value&column=sl.Some%20value&column=sr.Some%20value&column=nxl.Some%20value&column=nxr.Some%20value&column=adj.Some%20value&column=ov.Some%20value&column=fts.Some%20value&column=plfts.Some%20value&column=phfts.Some%20value&column=wfts.Some%20value&select=*"
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
curl \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--header "X-Client-Info: postgrest-swift/1.0.1" \
--header "X-Client-Info: postgrest-swift/1.0.2" \
"https://example.supabase.co/users?name=cs.%7Bis:online,faction:red%7D&select=*"
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
curl \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--header "X-Client-Info: postgrest-swift/1.0.1" \
--header "X-Client-Info: postgrest-swift/1.0.2" \
"https://example.supabase.co/users?address=cs.%7B%22postcode%22:90210%7D&select=name"
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
curl \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--header "X-Client-Info: postgrest-swift/1.0.1" \
--header "X-Client-Info: postgrest-swift/1.0.2" \
"https://example.supabase.co/todos?id=in.(1,2,3)&select=*"
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
curl \
--request POST \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--header "Prefer: resolution=ignore-duplicates,return=representation" \
--header "X-Client-Info: postgrest-swift/1.0.1" \
--header "X-Client-Info: postgrest-swift/1.0.2" \
--data "{\"email\":\"johndoe@supabase.io\"}" \
"https://example.supabase.co/users"
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
curl \
--request POST \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--header "Prefer: resolution=merge-duplicates,return=representation" \
--header "X-Client-Info: postgrest-swift/1.0.1" \
--header "X-Client-Info: postgrest-swift/1.0.2" \
--data "{\"email\":\"johndoe@supabase.io\"}" \
"https://example.supabase.co/users"

0 comments on commit 1f7e0c7

Please sign in to comment.