fix(deps): adapt hackney and mdex behavior
This commit is contained in:
parent
9154f6fe3c
commit
dc348e8be8
3 changed files with 89 additions and 26 deletions
|
|
@ -131,12 +131,16 @@ defmodule Pleroma.Formatter do
|
||||||
breaks = Map.get(opts, :breaks, false)
|
breaks = Map.get(opts, :breaks, false)
|
||||||
text = normalize_markdown_quirks(text)
|
text = normalize_markdown_quirks(text)
|
||||||
|
|
||||||
text
|
MDEx.new(
|
||||||
|> MDEx.to_html!(
|
markdown: text,
|
||||||
extension: [autolink: true, strikethrough: true],
|
extension: [autolink: true, strikethrough: true],
|
||||||
parse: [smart: false],
|
parse: [smart: false],
|
||||||
render: [hardbreaks: breaks, unsafe: true]
|
render: [hardbreaks: breaks, unsafe: true]
|
||||||
)
|
)
|
||||||
|
|> MDEx.Document.run()
|
||||||
|
|> MDEx.Document.update_nodes(MDEx.HtmlBlock, &strip_dangerous_raw_html/1)
|
||||||
|
|> MDEx.Document.update_nodes(MDEx.HtmlInline, &strip_dangerous_raw_html/1)
|
||||||
|
|> MDEx.to_html!()
|
||||||
|> compact_markdown_html(text)
|
|> compact_markdown_html(text)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -155,20 +159,33 @@ defmodule Pleroma.Formatter do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp unwrap_raw_html_paragraph(html, markdown) do
|
defp unwrap_raw_html_paragraph(html, markdown) do
|
||||||
if raw_html_only?(markdown) do
|
if inline_raw_html_only?(markdown) do
|
||||||
String.replace(html, ~r/\A<p>(.*)<\/p>\z/s, "\\1")
|
String.replace(html, ~r/\A<p>(.*)<\/p>\z/s, "\\1")
|
||||||
else
|
else
|
||||||
html
|
html
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp raw_html_only?(markdown) do
|
defp inline_raw_html_only?(markdown) do
|
||||||
markdown = String.trim(markdown)
|
markdown = String.trim(markdown)
|
||||||
|
|
||||||
String.match?(markdown, ~r/\A(?:<!--|<\/?[[:alpha:]][[:alnum:]:-]*(?:\s|>|\/>))/) &&
|
String.match?(
|
||||||
|
markdown,
|
||||||
|
~r/\A(?:<!--|<\/?(?:a|abbr|acronym|b|bdi|bdo|big|br|cite|code|data|del|dfn|em|i|img|ins|kbd|mark|q|rb|rp|rt|rtc|ruby|s|samp|small|span|strong|sub|sup|time|tt|u|var|wbr)(?:\s|>|\/>))/i
|
||||||
|
) &&
|
||||||
String.ends_with?(markdown, ">")
|
String.ends_with?(markdown, ">")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp strip_dangerous_raw_html(%{literal: literal} = node) do
|
||||||
|
literal =
|
||||||
|
literal
|
||||||
|
|> String.replace(~r/<(script|style)\b[^>]*>.*?<\/\1>/is, "")
|
||||||
|
|> String.replace(~r/<(script|style)\b[^>]*>.*\z/is, "")
|
||||||
|
|> String.replace(~r/<\/(script|style)\s*>/i, "")
|
||||||
|
|
||||||
|
%{node | literal: literal}
|
||||||
|
end
|
||||||
|
|
||||||
def html_escape({text, mentions, hashtags}, type) do
|
def html_escape({text, mentions, hashtags}, type) do
|
||||||
{html_escape(text, type), mentions, hashtags}
|
{html_escape(text, type), mentions, hashtags}
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -35,10 +35,11 @@ defmodule Pleroma.ReverseProxy.Client.Hackney do
|
||||||
if opts[:follow_redirect] != false do
|
if opts[:follow_redirect] != false do
|
||||||
{_state, req_opts} = Access.get_and_update(opts, :follow_redirect, fn a -> {a, false} end)
|
{_state, req_opts} = Access.get_and_update(opts, :follow_redirect, fn a -> {a, false} end)
|
||||||
env = %{method: method, headers: headers, body: body, req_opts: req_opts}
|
env = %{method: method, headers: headers, body: body, req_opts: req_opts}
|
||||||
res = :hackney.request(method, url, headers, body, req_opts)
|
res = do_request(method, url, headers, body, req_opts)
|
||||||
|
|
||||||
case res do
|
case res do
|
||||||
{:ok, code, resp_headers, _client} when code in @redirect_statuses ->
|
{:ok, code, resp_headers, client} when code in @redirect_statuses ->
|
||||||
|
close(client)
|
||||||
redirect(url, resp_headers, env, @redirect_limit)
|
redirect(url, resp_headers, env, @redirect_limit)
|
||||||
|
|
||||||
{:ok, code, resp_headers} when code in @redirect_statuses ->
|
{:ok, code, resp_headers} when code in @redirect_statuses ->
|
||||||
|
|
@ -48,11 +49,22 @@ defmodule Pleroma.ReverseProxy.Client.Hackney do
|
||||||
res
|
res
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
:hackney.request(method, url, headers, body, opts)
|
do_request(method, url, headers, body, opts)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
|
def stream_body(%{ref: ref, recv_timeout: recv_timeout} = client) do
|
||||||
|
_ = :hackney.stream_next(ref)
|
||||||
|
|
||||||
|
case receive_response(ref, recv_timeout) do
|
||||||
|
{:ok, data} when is_binary(data) -> {:ok, data, client}
|
||||||
|
{:ok, :done} -> :done
|
||||||
|
{:ok, {:error, error}} -> {:error, error}
|
||||||
|
{:error, error} -> {:error, error}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def stream_body(ref) do
|
def stream_body(ref) do
|
||||||
case :hackney.stream_body(ref) do
|
case :hackney.stream_body(ref) do
|
||||||
:done -> :done
|
:done -> :done
|
||||||
|
|
@ -62,8 +74,33 @@ defmodule Pleroma.ReverseProxy.Client.Hackney do
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
|
def close(%{ref: ref}), do: :hackney.close(ref)
|
||||||
|
|
||||||
def close(ref), do: :hackney.close(ref)
|
def close(ref), do: :hackney.close(ref)
|
||||||
|
|
||||||
|
defp do_request(method, url, headers, body, opts) do
|
||||||
|
recv_timeout = Keyword.get(opts, :recv_timeout, :infinity)
|
||||||
|
|
||||||
|
req_opts =
|
||||||
|
opts
|
||||||
|
|> Keyword.put(:async, :once)
|
||||||
|
|> Keyword.put(:stream_to, self())
|
||||||
|
|
||||||
|
with {:ok, ref} <- :hackney.request(method, url, headers, body, req_opts),
|
||||||
|
{:ok, {:status, code, _reason}} <- receive_response(ref, recv_timeout),
|
||||||
|
{:ok, {:headers, resp_headers}} <- receive_response(ref, recv_timeout) do
|
||||||
|
{:ok, code, resp_headers, %{ref: ref, recv_timeout: recv_timeout}}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp receive_response(ref, recv_timeout) do
|
||||||
|
receive do
|
||||||
|
{:hackney_response, ^ref, response} -> {:ok, response}
|
||||||
|
after
|
||||||
|
recv_timeout -> {:error, :timeout}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
defp redirect(url, resp_headers, env, limit) when limit == 0 do
|
defp redirect(url, resp_headers, env, limit) when limit == 0 do
|
||||||
new_url = absolute_redirect_url(url, resp_headers)
|
new_url = absolute_redirect_url(url, resp_headers)
|
||||||
|
|
||||||
|
|
@ -71,17 +108,18 @@ defmodule Pleroma.ReverseProxy.Client.Hackney do
|
||||||
"#{__MODULE__}: Handling redirect #{url} -> #{new_url}; redirect limit was reached - returning response after final redirect"
|
"#{__MODULE__}: Handling redirect #{url} -> #{new_url}; redirect limit was reached - returning response after final redirect"
|
||||||
)
|
)
|
||||||
|
|
||||||
:hackney.request(env.method, new_url, env.headers, env.body, env.req_opts)
|
do_request(env.method, new_url, env.headers, env.body, env.req_opts)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp redirect(url, resp_headers, env, limit) do
|
defp redirect(url, resp_headers, env, limit) do
|
||||||
new_url = absolute_redirect_url(url, resp_headers)
|
new_url = absolute_redirect_url(url, resp_headers)
|
||||||
Logger.debug("#{__MODULE__}: handling redirect #{url} -> #{new_url}; limit = #{limit}")
|
Logger.debug("#{__MODULE__}: handling redirect #{url} -> #{new_url}; limit = #{limit}")
|
||||||
|
|
||||||
res = :hackney.request(env.method, new_url, env.headers, env.body, env.req_opts)
|
res = do_request(env.method, new_url, env.headers, env.body, env.req_opts)
|
||||||
|
|
||||||
case res do
|
case res do
|
||||||
{:ok, code, new_resp_headers, _client} when code in @redirect_statuses ->
|
{:ok, code, new_resp_headers, client} when code in @redirect_statuses ->
|
||||||
|
close(client)
|
||||||
redirect(new_url, new_resp_headers, env, limit - 1)
|
redirect(new_url, new_resp_headers, env, limit - 1)
|
||||||
|
|
||||||
{:ok, code, new_resp_headers} when code in @redirect_statuses ->
|
{:ok, code, new_resp_headers} when code in @redirect_statuses ->
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ defmodule Pleroma.HTTP.HackneyFollowRedirectRegressionTest do
|
||||||
{:ok, tls_server: tls_server, proxy: proxy}
|
{:ok, tls_server: tls_server, proxy: proxy}
|
||||||
end
|
end
|
||||||
|
|
||||||
test "hackney follow_redirect crashes behind CONNECT proxy on relative redirects", %{
|
test "hackney follow_redirect handles relative redirects behind CONNECT proxy", %{
|
||||||
tls_server: tls_server,
|
tls_server: tls_server,
|
||||||
proxy: proxy
|
proxy: proxy
|
||||||
} do
|
} do
|
||||||
|
|
@ -28,19 +28,15 @@ defmodule Pleroma.HTTP.HackneyFollowRedirectRegressionTest do
|
||||||
opts = [
|
opts = [
|
||||||
pool: :media,
|
pool: :media,
|
||||||
proxy: proxy.proxy_url,
|
proxy: proxy.proxy_url,
|
||||||
insecure: true,
|
ssl_options: tls_client_options(tls_server),
|
||||||
connect_timeout: 1_000,
|
connect_timeout: 1_000,
|
||||||
recv_timeout: 1_000,
|
recv_timeout: 1_000,
|
||||||
follow_redirect: true,
|
follow_redirect: true,
|
||||||
force_redirect: true
|
force_redirect: true,
|
||||||
|
with_body: true
|
||||||
]
|
]
|
||||||
|
|
||||||
{pid, ref} = spawn_monitor(fn -> :hackney.request(:get, url, [], <<>>, opts) end)
|
assert {:ok, 200, _headers, "ok"} = :hackney.request(:get, url, [], <<>>, opts)
|
||||||
|
|
||||||
assert_receive {:DOWN, ^ref, :process, ^pid, reason}, 5_000
|
|
||||||
|
|
||||||
assert match?({%FunctionClauseError{}, _}, reason) or match?(%FunctionClauseError{}, reason) or
|
|
||||||
match?({:function_clause, _}, reason)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "redirects work via proxy when hackney follow_redirect is disabled", %{
|
test "redirects work via proxy when hackney follow_redirect is disabled", %{
|
||||||
|
|
@ -52,7 +48,7 @@ defmodule Pleroma.HTTP.HackneyFollowRedirectRegressionTest do
|
||||||
adapter_opts = [
|
adapter_opts = [
|
||||||
pool: :media,
|
pool: :media,
|
||||||
proxy: proxy.proxy_url,
|
proxy: proxy.proxy_url,
|
||||||
insecure: true,
|
ssl_options: tls_client_options(tls_server),
|
||||||
connect_timeout: 1_000,
|
connect_timeout: 1_000,
|
||||||
recv_timeout: 1_000,
|
recv_timeout: 1_000,
|
||||||
follow_redirect: false,
|
follow_redirect: false,
|
||||||
|
|
@ -75,7 +71,7 @@ defmodule Pleroma.HTTP.HackneyFollowRedirectRegressionTest do
|
||||||
opts = [
|
opts = [
|
||||||
pool: :media,
|
pool: :media,
|
||||||
proxy: proxy.proxy_url,
|
proxy: proxy.proxy_url,
|
||||||
insecure: true,
|
ssl_options: tls_client_options(tls_server),
|
||||||
connect_timeout: 1_000,
|
connect_timeout: 1_000,
|
||||||
recv_timeout: 1_000,
|
recv_timeout: 1_000,
|
||||||
follow_redirect: true
|
follow_redirect: true
|
||||||
|
|
@ -97,7 +93,7 @@ defmodule Pleroma.HTTP.HackneyFollowRedirectRegressionTest do
|
||||||
opts = [
|
opts = [
|
||||||
pool: :media,
|
pool: :media,
|
||||||
proxy: proxy.proxy_url,
|
proxy: proxy.proxy_url,
|
||||||
insecure: true,
|
ssl_options: tls_client_options(tls_server),
|
||||||
connect_timeout: 1_000,
|
connect_timeout: 1_000,
|
||||||
recv_timeout: 1_000,
|
recv_timeout: 1_000,
|
||||||
follow_redirect: true
|
follow_redirect: true
|
||||||
|
|
@ -119,7 +115,7 @@ defmodule Pleroma.HTTP.HackneyFollowRedirectRegressionTest do
|
||||||
opts = [
|
opts = [
|
||||||
pool: :media,
|
pool: :media,
|
||||||
proxy: proxy.proxy_url,
|
proxy: proxy.proxy_url,
|
||||||
insecure: true,
|
ssl_options: tls_client_options(tls_server),
|
||||||
connect_timeout: 1_000,
|
connect_timeout: 1_000,
|
||||||
recv_timeout: 1_000,
|
recv_timeout: 1_000,
|
||||||
follow_redirect: true
|
follow_redirect: true
|
||||||
|
|
@ -161,7 +157,13 @@ defmodule Pleroma.HTTP.HackneyFollowRedirectRegressionTest do
|
||||||
accept_tls_loop(listener)
|
accept_tls_loop(listener)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
{:ok, %{listener: listener, acceptor: acceptor, base_url: "https://127.0.0.1:#{port}"}}
|
{:ok,
|
||||||
|
%{
|
||||||
|
listener: listener,
|
||||||
|
acceptor: acceptor,
|
||||||
|
certfile: certfile,
|
||||||
|
base_url: "https://127.0.0.1:#{port}"
|
||||||
|
}}
|
||||||
end
|
end
|
||||||
|
|
||||||
defp stop_tls_redirect_server(%{listener: listener, acceptor: acceptor}) do
|
defp stop_tls_redirect_server(%{listener: listener, acceptor: acceptor}) do
|
||||||
|
|
@ -210,11 +212,17 @@ defmodule Pleroma.HTTP.HackneyFollowRedirectRegressionTest do
|
||||||
:ssl.close(ssl_socket)
|
:ssl.close(ssl_socket)
|
||||||
else
|
else
|
||||||
_ ->
|
_ ->
|
||||||
_ = :gen_tcp.close(tcp_socket)
|
_ = :ssl.close(tcp_socket)
|
||||||
:ok
|
:ok
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp tls_client_options(_tls_server) do
|
||||||
|
[server_name_indication: ~c"localhost", verify_fun: {&accept_test_certificate/3, []}]
|
||||||
|
end
|
||||||
|
|
||||||
|
defp accept_test_certificate(_cert, _event, state), do: {:valid, state}
|
||||||
|
|
||||||
defp recv_ssl_headers(socket, acc \\ <<>>) do
|
defp recv_ssl_headers(socket, acc \\ <<>>) do
|
||||||
case :ssl.recv(socket, 0, 1_000) do
|
case :ssl.recv(socket, 0, 1_000) do
|
||||||
{:ok, data} ->
|
{:ok, data} ->
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue