From a6301e40a9e7dd5b9e7d9c6987ff71950c1579e2 Mon Sep 17 00:00:00 2001 From: Daniel Kukula Date: Sun, 27 Sep 2026 08:42:18 +0200 Subject: [PATCH] Avoid intermediate lists in URI query decoding Instead of calling :binary.split/2 twice per key-value pair (once on "&" and once on "="), decode query parameters directly using binary pattern matching and binary_part/3. This eliminates 2 intermediate list allocations per query pair in URI.query_decoder/2 and URI.decode_query/1,2,3. Assisted-by: Antigravity:Gemini 3.8 Flash --- lib/elixir/lib/uri.ex | 52 +++++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/lib/elixir/lib/uri.ex b/lib/elixir/lib/uri.ex index 3a32da98ff..9e9420bba7 100644 --- a/lib/elixir/lib/uri.ex +++ b/lib/elixir/lib/uri.ex @@ -292,27 +292,45 @@ defmodule URI do Stream.unfold(query, &decode_next_query_pair(&1, encoding)) end - defp decode_next_query_pair("", _encoding) do + defp decode_next_query_pair(<<>>, _encoding) do nil end defp decode_next_query_pair(query, encoding) do - {undecoded_next_pair, rest} = - case :binary.split(query, "&") do - [next_pair, rest] -> {next_pair, rest} - [next_pair] -> {next_pair, ""} - end - - next_pair = - case :binary.split(undecoded_next_pair, "=") do - [key, value] -> - {decode_with_encoding(key, encoding), decode_with_encoding(value, encoding)} - - [key] -> - {decode_with_encoding(key, encoding), ""} - end - - {next_pair, rest} + parse_next_key(query, query, 0, encoding) + end + + defp parse_next_key(<>, original, skip, encoding) do + key = binary_part(original, 0, skip) |> decode_with_encoding(encoding) + parse_next_val(rest, rest, 0, key, encoding) + end + + defp parse_next_key(<>, original, skip, encoding) do + key = binary_part(original, 0, skip) |> decode_with_encoding(encoding) + {{key, ""}, rest} + end + + defp parse_next_key(<<_char, rest::binary>>, original, skip, encoding) do + parse_next_key(rest, original, skip + 1, encoding) + end + + defp parse_next_key(<<>>, original, skip, encoding) do + key = binary_part(original, 0, skip) |> decode_with_encoding(encoding) + {{key, ""}, ""} + end + + defp parse_next_val(<>, original, skip, key, encoding) do + val = binary_part(original, 0, skip) |> decode_with_encoding(encoding) + {{key, val}, rest} + end + + defp parse_next_val(<<_char, rest::binary>>, original, skip, key, encoding) do + parse_next_val(rest, original, skip + 1, key, encoding) + end + + defp parse_next_val(<<>>, original, skip, key, encoding) do + val = binary_part(original, 0, skip) |> decode_with_encoding(encoding) + {{key, val}, ""} end defp decode_with_encoding(string, :www_form) do