Skip to content

Conversation

@ghivert
Copy link
Contributor

@ghivert ghivert commented Oct 28, 2025

Hi!

Currently, the documentation indicates in uri.parse_query "The opposite operation is uri.query_to_string."
In uri.query_to_string, we can read "The opposite operation is uri.parse_query.".

Unfortunately, when writing this

pub fn main() {
  let queries = [#("example", "1 + 1")]
  let converted = uri.query_to_string(queries)
  let parsed = uri.parse_query(converted)
  assert parsed == Ok(queries)
}

The code fails. It fails because — from my understanding — while + is an allowed character in query strings in the form %2B, uri.query_to_string does not follows the URI query string convertion and instead replaces %2B with +. Indeed, outside of query strings, + has another meaning, and should not be converted. It makes sense to not convert it in uri.percent_encode, but it should be in uri.query_to_string.

The above code, when changing 1 + 1 to 1 %2B 1 works. I think it's not the desired behaviour here, and it's confusing for developers. From my understanding, when manipulating query strings as keyed lists, the value associated with the key can be any string, including one with +. Using uri.query_to_string without the knowledge that + won't be perserved in percent encoding lead to hard to find bugs.


The proposition here is to properly encode the query strings, and to add a test case with the special characters, where some of them are "unreserved characters", like ~ for example.

I wanted to directly open the PR to talk about that with some code to illustrate, but anything can be changed or the PR can be closed if you estimate it's not desired in the standard library. 🙂
In any case, I think it is important to find a way to communicate how to use URI correctly, as it can be confusing to understand when to use percent_encode, etc. when the framework/libraries you're using is not doing the hard work for you. I wanted to write some documentation but I couldn't find a proper place to do it. Do you have any recommandation on that topic?


For information, that bug surfaced when we had to handle + in query strings in our application, and currently we're just happily using uri.query_to_string before setting the query string in a uri.Uri. We could simply run the string.replace(_, each: "+", with: "%2B"), but I suspect others could end up with the same issue, and struggle to understand why it bugs, as uri.query_to_string is not the exact opposite function of uri.parse_query. 😄

Copy link
Member

@lpil lpil left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! Could you update the changelog please

@ghivert
Copy link
Contributor Author

ghivert commented Oct 28, 2025

Done !

@ghivert ghivert requested a review from lpil October 28, 2025 10:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants