Skip to content

Commit 43f38db

Browse files
committed
Fix inconsistent query_to_string with +
1 parent 126db53 commit 43f38db

File tree

3 files changed

+21
-1
lines changed

3 files changed

+21
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## v0.66.0 - 2025-10-21
44

55
- The `tap` function from the `function` module has been deprecated.
6+
- `uri.query_to_string` now correctly handles `+` in query params.
67

78
## v0.65.0 - 2025-09-29
89

src/gleam/uri.gleam

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -556,7 +556,13 @@ pub fn query_to_string(query: List(#(String, String))) -> String {
556556
}
557557

558558
fn query_pair(pair: #(String, String)) -> StringTree {
559-
string_tree.from_strings([percent_encode(pair.0), "=", percent_encode(pair.1)])
559+
[percent_encode_query(pair.0), "=", percent_encode_query(pair.1)]
560+
|> string_tree.from_strings
561+
}
562+
563+
fn percent_encode_query(part: String) -> String {
564+
percent_encode(part)
565+
|> string.replace(each: "+", with: "%2B")
560566
}
561567

562568
/// Encodes a string into a percent encoded representation.

test/gleam/uri_test.gleam

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,12 @@ pub fn query_to_string_test() {
413413
assert query_string == "weebl%20bob=1&city=%C3%B6rebro"
414414
}
415415

416+
pub fn query_to_string_special_characters_test() {
417+
let query_string =
418+
uri.query_to_string([#("weebl bob", "1+1-1*1.1~1!1'1(1);%")])
419+
assert query_string == "weebl%20bob=1%2B1-1*1.1~1!1'1(1)%3B%25"
420+
}
421+
416422
pub fn empty_query_to_string_test() {
417423
let query_string = uri.query_to_string([])
418424
assert query_string == ""
@@ -557,6 +563,13 @@ pub fn parse_segments_test() {
557563
assert uri.path_segments("/weebl/../bob") == ["bob"]
558564
}
559565

566+
pub fn query_to_string_parse_query_opposite_unreserved_marks_test() {
567+
let queries = [#("weebl bob", "1+1-1*1.1~1!1'1(1);%"), #("city", "örebro")]
568+
let query_string = uri.query_to_string(queries)
569+
let parsed = uri.parse_query(query_string)
570+
assert parsed == Ok(queries)
571+
}
572+
560573
pub fn origin1_test() {
561574
let assert Ok(parsed) = uri.parse("http://example.test/path?weebl#bob")
562575
assert uri.origin(parsed) == Ok("http://example.test")

0 commit comments

Comments
 (0)