Hi Floris, thanks for the proposal! Unfortunately this is a bit more complicated than expected.
First of all, the current implementation is not in violation of RFC3986. %20 is a valid escaping of spaces in query strings. As far as I know, RFC3986 does not explicitly mention that + is equivalent to a space. Furthermore, earlier specifications, such as RFC2396 <https://www.ietf.org/rfc/rfc2396.txt>, did not allow + in query strings at all. Only later on W3C specified that + is reserved to mean spaces <https://www.w3.org/Addressing/URL/uri-spec.html> to be compatible with the general usage of URLs - which browsers eventually standardized on. However, at this point, the damage was done. For example, for mailto links, your mail client may not rewrite + to spaces, while it will certainly handle percent encoded spaces. In other words, if you want to guarantee the space will be treated as space, %20 is the best choice. So I would say String.replace/3 is the way to go unless there is a quote in RFC3986 which suggests or advocates for using + as the escaping of spaces in query strings. Finally, it is important to remember that escaping of URI segments for paths and query strings use distinct algorithms <http://stephane.epardaud.fr/articles/2009-02-03-what-every-web-developer-must-know-about-url-encoding.html#Thereservedcharactersarenotwhatyouthinktheyare> (which is why the function is called encode_query). On Fri, Jan 29, 2021 at 10:59 AM Floris Huetink <[email protected]> wrote: > Hi, > > I've been using `URI.encode_query/1` to convert a key/value map to a query > string to be appended to a URL (as GET parameters). > > As it turns out, `URI.encode_query/1` encodes differently than > `URI.encode/2`, particularly in the case of spaces ("+" instead of "%20"). > For more context, please see the comment thread here: > > https://github.com/elixir-lang/elixir/pull/2392 > > For me, it was non-obvious that I better *not* use `encode_query` to > encode a URL-appending query string. I tried using `URI.encode/2` instead, > as this provides RFC3986 encoding, but this simply behaves differently, in > the sense that it takes string input, not an Enumerable. > > Given the above, I'd like to propose the addition of `URI.encode_query/2`, > where the second argument should allow the user to specify which type of > encoding should be used. > Default encoding should be the existing `:www_form` encoding (I'm not sure > if there is an official RFC for www-form-urlencoded? If so, we should use > that) > One should be able to replace this with RFC3986, e.g. like so: > > URI.encode_query(%{foo: "bar"}, :rfc3986) > > This should produce a query string with spaces encoded as "%20" instead of > "+" (and possibly other differences). > > An alternative approach could be to use an `opts` Keyword list: > > URI.encode_query(%{foo: "bar"}, encoding: :rfc3986) > > The latter approach could have the benefit of being able to add other > options later (which I currently cannot think of, but others might). > > The general benefit for Elixir users would be to be able to encode Elixir > data structures (typically maps) into RFC3986 compliant query strings > without having to manually iterate over every item and/or patching the > `URI.encode_query/1` result with quick-and-dirty solutions like > `String.replace(query_string, "+", "%20")`. > > That's it. I'd love to hear feedback! > > – Floris > > -- > You received this message because you are subscribed to the Google Groups > "elixir-lang-core" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected]. > To view this discussion on the web visit > https://groups.google.com/d/msgid/elixir-lang-core/538f2618-dd14-4084-b6cc-dabb7a8f58e7n%40googlegroups.com > <https://groups.google.com/d/msgid/elixir-lang-core/538f2618-dd14-4084-b6cc-dabb7a8f58e7n%40googlegroups.com?utm_medium=email&utm_source=footer> > . > -- You received this message because you are subscribed to the Google Groups "elixir-lang-core" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4Jp6S_KwuQtZyWwKAJZBFJ14Q8CDGdwW0zz445thf7Wqw%40mail.gmail.com.
