diff --git a/lib/plug/conn/utils.ex b/lib/plug/conn/utils.ex index a98d09d2..bf58e145 100644 --- a/lib/plug/conn/utils.ex +++ b/lib/plug/conn/utils.ex @@ -286,6 +286,10 @@ defmodule Plug.Conn.Utils do do: stripped end + # 56-bit SWAR guard: all 7 bytes are ASCII (< 128) + defguardp ascii_swar?(w) + when Bitwise.band(w, 0x80808080808080) == 0 + @doc """ Validates the given binary is valid UTF-8. """ @@ -293,18 +297,33 @@ defmodule Plug.Conn.Utils do def validate_utf8!(binary, exception, context) def validate_utf8!(<>, exception, context) do - do_validate_utf8!(binary, exception, context) + if byte_size(binary) < 12 do + do_validate_utf8_small!(binary, exception, context) + else + do_validate_utf8_swar!(binary, exception, context) + end + end + + # SWAR loop + defp do_validate_utf8_swar!(<>, exception, context) + when b <= 127 and ascii_swar?(w) do + do_validate_utf8_swar!(rest, exception, context) + end + + defp do_validate_utf8_swar!(rest, exception, context) do + do_validate_utf8_small!(rest, exception, context) end - defp do_validate_utf8!(<<_::utf8, rest::bits>>, exception, context) do - do_validate_utf8!(rest, exception, context) + # Small loop (identical to original character loop) + defp do_validate_utf8_small!(<<_::utf8, rest::bits>>, exception, context) do + do_validate_utf8_small!(rest, exception, context) end - defp do_validate_utf8!(<>, exception, context) do + defp do_validate_utf8_small!(<>, exception, context) do raise exception, "invalid UTF-8 on #{context}, got byte #{byte}" end - defp do_validate_utf8!(<<>>, _exception, _context) do + defp do_validate_utf8_small!(<<>>, _exception, _context) do :ok end