This commit is contained in:
Phantasm 2025-10-10 22:37:16 +02:00
commit cfd2c08ef6
No known key found for this signature in database
GPG key ID: 2669E588BCC634C8
3 changed files with 50 additions and 28 deletions

View file

@ -146,8 +146,10 @@ defmodule Pleroma.HTTP do
true -> true ->
URI.parse(url) URI.parse(url)
|> then(fn parsed -> |> then(fn parsed ->
path = encode_path(parsed.path, bypass_decode) path =
|> maybe_apply_path_encoding_quirks() encode_path(parsed.path, bypass_decode)
|> maybe_apply_path_encoding_quirks()
query = encode_query(parsed.query) query = encode_query(parsed.query)
%{parsed | path: path, query: query} %{parsed | path: path, query: query}
@ -197,7 +199,7 @@ defmodule Pleroma.HTTP do
|> Enum.to_list() |> Enum.to_list()
|> do_encode_query() |> do_encode_query()
end end
defp maybe_apply_path_encoding_quirks(path), do: path defp maybe_apply_path_encoding_quirks(path), do: path
# Always uses www_form encoding # Always uses www_form encoding
@ -221,19 +223,22 @@ defmodule Pleroma.HTTP do
# URI.encode_query/2 does not appear to follow spec and encodes all parts of our URI path Constant. # URI.encode_query/2 does not appear to follow spec and encodes all parts of our URI path Constant.
# This appears to work outside of edge-cases like The Guardian Rich Media Cards, # This appears to work outside of edge-cases like The Guardian Rich Media Cards,
# keeping behavior same as with URI.encode_query/2 unless otherwise specified via rules. # keeping behavior same as with URI.encode_query/2 unless otherwise specified via rules.
URI.encode_www_form(Kernel.to_string(key)) <> "=" <> (URI.encode_www_form(Kernel.to_string(key)) <>
URI.encode(value, fn byte -> "=" <>
URI.char_unreserved?(byte) || URI.encode(value, fn byte ->
Enum.any?( URI.char_unreserved?(byte) ||
rules, Enum.any?(
fn char -> rules,
char == byte fn char ->
end) char == byte
end) end
|> String.replace("%20", "+") )
end))
|> String.replace("%20", "+")
true -> true ->
URI.encode_www_form(Kernel.to_string(key)) <> "=" <> URI.encode_www_form(Kernel.to_string(value)) URI.encode_www_form(Kernel.to_string(key)) <>
"=" <> URI.encode_www_form(Kernel.to_string(value))
end end
end end
end end

View file

@ -38,13 +38,25 @@ defmodule Pleroma.HTTPTest do
%{method: :get, url: "https://example.com/media/unicode%20%F0%9F%99%82%20.gif"} -> %{method: :get, url: "https://example.com/media/unicode%20%F0%9F%99%82%20.gif"} ->
%Tesla.Env{status: 200, body: "unicode data"} %Tesla.Env{status: 200, body: "unicode data"}
%{method: :get, url: "https://i.guim.co.uk/img/media/1069ef13c447908272c4de94174cec2b6352cb2f/0_91_2000_1201/master/2000.jpg?width=1200&height=630&quality=85&auto=format&fit=crop&precrop=40:21,offset-x50,offset-y0&overlay-align=bottom%2Cleft&overlay-width=100p&overlay-base64=L2ltZy9zdGF0aWMvb3ZlcmxheXMvdGctb3BpbmlvbnMtYWdlLTIwMTkucG5n&enable=upscale&s=cba21427a73512fdc9863c486c03fdd8"} -> %{
method: :get,
url:
"https://i.guim.co.uk/img/media/1069ef13c447908272c4de94174cec2b6352cb2f/0_91_2000_1201/master/2000.jpg?width=1200&height=630&quality=85&auto=format&fit=crop&precrop=40:21,offset-x50,offset-y0&overlay-align=bottom%2Cleft&overlay-width=100p&overlay-base64=L2ltZy9zdGF0aWMvb3ZlcmxheXMvdGctb3BpbmlvbnMtYWdlLTIwMTkucG5n&enable=upscale&s=cba21427a73512fdc9863c486c03fdd8"
} ->
%Tesla.Env{status: 200, body: "Guardian image quirk"} %Tesla.Env{status: 200, body: "Guardian image quirk"}
%{method: :get, url: "https://example.com/emoji/Pack%201/koronebless.png?precrop=40:21,overlay-x0,overlay-y0&foo=bar+baz"} -> %{
method: :get,
url:
"https://example.com/emoji/Pack%201/koronebless.png?precrop=40:21,overlay-x0,overlay-y0&foo=bar+baz"
} ->
%Tesla.Env{status: 200, body: "Space in query with Guardian quirk"} %Tesla.Env{status: 200, body: "Space in query with Guardian quirk"}
%{method: :get, url: "https://examplebucket.s3.amazonaws.com/test.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=accessKEY%2F20130721%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20130721T201207Z&X-Amz-Expires=86400&X-Amz-Signature=SIGNATURE&X-Amz-SignedHeaders=host"} -> %{
method: :get,
url:
"https://examplebucket.s3.amazonaws.com/test.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=accessKEY%2F20130721%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20130721T201207Z&X-Amz-Expires=86400&X-Amz-Signature=SIGNATURE&X-Amz-SignedHeaders=host"
} ->
%Tesla.Env{status: 200, body: "AWS S3 data"} %Tesla.Env{status: 200, body: "AWS S3 data"}
end) end)
@ -140,7 +152,8 @@ defmodule Pleroma.HTTPTest do
test "properly applies Guardian image query quirk" do test "properly applies Guardian image query quirk" do
clear_config(:test_url_encoding, true) clear_config(:test_url_encoding, true)
url = "https://i.guim.co.uk/img/media/1069ef13c447908272c4de94174cec2b6352cb2f/0_91_2000_1201/master/2000.jpg?width=1200&height=630&quality=85&auto=format&fit=crop&precrop=40:21,offset-x50,offset-y0&overlay-align=bottom%2Cleft&overlay-width=100p&overlay-base64=L2ltZy9zdGF0aWMvb3ZlcmxheXMvdGctb3BpbmlvbnMtYWdlLTIwMTkucG5n&enable=upscale&s=cba21427a73512fdc9863c486c03fdd8" url =
"https://i.guim.co.uk/img/media/1069ef13c447908272c4de94174cec2b6352cb2f/0_91_2000_1201/master/2000.jpg?width=1200&height=630&quality=85&auto=format&fit=crop&precrop=40:21,offset-x50,offset-y0&overlay-align=bottom%2Cleft&overlay-width=100p&overlay-base64=L2ltZy9zdGF0aWMvb3ZlcmxheXMvdGctb3BpbmlvbnMtYWdlLTIwMTkucG5n&enable=upscale&s=cba21427a73512fdc9863c486c03fdd8"
result = HTTP.encode_url(url) result = HTTP.encode_url(url)
@ -154,9 +167,11 @@ defmodule Pleroma.HTTPTest do
test "properly encodes spaces as \"pluses\" in query when using quirks" do test "properly encodes spaces as \"pluses\" in query when using quirks" do
clear_config(:test_url_encoding, true) clear_config(:test_url_encoding, true)
url = "https://example.com/emoji/Pack 1/koronebless.png?precrop=40:21,overlay-x0,overlay-y0&foo=bar baz" url =
"https://example.com/emoji/Pack 1/koronebless.png?precrop=40:21,overlay-x0,overlay-y0&foo=bar baz"
properly_encoded_url = "https://example.com/emoji/Pack%201/koronebless.png?precrop=40:21,overlay-x0,overlay-y0&foo=bar+baz" properly_encoded_url =
"https://example.com/emoji/Pack%201/koronebless.png?precrop=40:21,overlay-x0,overlay-y0&foo=bar+baz"
result = HTTP.encode_url(url) result = HTTP.encode_url(url)
@ -170,8 +185,11 @@ defmodule Pleroma.HTTPTest do
test "properly encode AWS S3 queries" do test "properly encode AWS S3 queries" do
clear_config(:test_url_encoding, true) clear_config(:test_url_encoding, true)
url = "https://examplebucket.s3.amazonaws.com/test.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=accessKEY%2F20130721%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20130721T201207Z&X-Amz-Expires=86400&X-Amz-Signature=SIGNATURE&X-Amz-SignedHeaders=host" url =
unencoded_url = "https://examplebucket.s3.amazonaws.com/test.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=accessKEY/20130721/us-east-1/s3/aws4_request&X-Amz-Date=20130721T201207Z&X-Amz-Expires=86400&X-Amz-Signature=SIGNATURE&X-Amz-SignedHeaders=host" "https://examplebucket.s3.amazonaws.com/test.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=accessKEY%2F20130721%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20130721T201207Z&X-Amz-Expires=86400&X-Amz-Signature=SIGNATURE&X-Amz-SignedHeaders=host"
unencoded_url =
"https://examplebucket.s3.amazonaws.com/test.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=accessKEY/20130721/us-east-1/s3/aws4_request&X-Amz-Date=20130721T201207Z&X-Amz-Expires=86400&X-Amz-Signature=SIGNATURE&X-Amz-SignedHeaders=host"
result = HTTP.encode_url(url) result = HTTP.encode_url(url)
result_unencoded = HTTP.encode_url(unencoded_url) result_unencoded = HTTP.encode_url(unencoded_url)
@ -182,7 +200,6 @@ defmodule Pleroma.HTTPTest do
{:ok, result_get} = HTTP.get(result) {:ok, result_get} = HTTP.get(result)
assert result_get.status == 200 assert result_get.status == 200
end end
test "preserves query key order" do test "preserves query key order" do

View file

@ -62,9 +62,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicyTest do
get: fn _, _, _ -> {:ok, []} end, get: fn _, _, _ -> {:ok, []} end,
encode_url: fn url -> :meck.passthrough([url]) end, encode_url: fn url -> :meck.passthrough([url]) end,
encode_url: fn url, opts -> :meck.passthrough([url, opts]) end do encode_url: fn url, opts -> :meck.passthrough([url, opts]) end do
MediaProxyWarmingPolicy.filter(@message) MediaProxyWarmingPolicy.filter(@message)
assert called(HTTP.get(:_, :_, :_)) assert called(HTTP.get(:_, :_, :_))
end end
end end
@ -92,9 +92,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicyTest do
get: fn _, _, _ -> {:ok, []} end, get: fn _, _, _ -> {:ok, []} end,
encode_url: fn url -> :meck.passthrough([url]) end, encode_url: fn url -> :meck.passthrough([url]) end,
encode_url: fn url, opts -> :meck.passthrough([url, opts]) end do encode_url: fn url, opts -> :meck.passthrough([url, opts]) end do
MRF.filter_one(MediaProxyWarmingPolicy, @message_with_history) MRF.filter_one(MediaProxyWarmingPolicy, @message_with_history)
assert called(HTTP.get(:_, :_, :_)) assert called(HTTP.get(:_, :_, :_))
end end
end end
@ -107,7 +107,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicyTest do
get: fn _, _, _ -> {:ok, []} end, get: fn _, _, _ -> {:ok, []} end,
encode_url: fn url -> :meck.passthrough([url]) end, encode_url: fn url -> :meck.passthrough([url]) end,
encode_url: fn url, opts -> :meck.passthrough([url, opts]) end do encode_url: fn url, opts -> :meck.passthrough([url, opts]) end do
MRF.filter_one(MediaProxyWarmingPolicy, @message_with_history |> Map.put("type", "Update")) MRF.filter_one(MediaProxyWarmingPolicy, @message_with_history |> Map.put("type", "Update"))
assert called(HTTP.get(:_, :_, :_)) assert called(HTTP.get(:_, :_, :_))
end end