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)
|
||||
text = normalize_markdown_quirks(text)
|
||||
|
||||
text
|
||||
|> MDEx.to_html!(
|
||||
MDEx.new(
|
||||
markdown: text,
|
||||
extension: [autolink: true, strikethrough: true],
|
||||
parse: [smart: false],
|
||||
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)
|
||||
end
|
||||
|
||||
|
|
@ -155,20 +159,33 @@ defmodule Pleroma.Formatter do
|
|||
end
|
||||
|
||||
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")
|
||||
else
|
||||
html
|
||||
end
|
||||
end
|
||||
|
||||
defp raw_html_only?(markdown) do
|
||||
defp inline_raw_html_only?(markdown) do
|
||||
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, ">")
|
||||
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
|
||||
{html_escape(text, type), mentions, hashtags}
|
||||
end
|
||||
|
|
|
|||
|
|
@ -35,10 +35,11 @@ defmodule Pleroma.ReverseProxy.Client.Hackney do
|
|||
if opts[:follow_redirect] != false do
|
||||
{_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}
|
||||
res = :hackney.request(method, url, headers, body, req_opts)
|
||||
res = do_request(method, url, headers, body, req_opts)
|
||||
|
||||
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)
|
||||
|
||||
{:ok, code, resp_headers} when code in @redirect_statuses ->
|
||||
|
|
@ -48,11 +49,22 @@ defmodule Pleroma.ReverseProxy.Client.Hackney do
|
|||
res
|
||||
end
|
||||
else
|
||||
:hackney.request(method, url, headers, body, opts)
|
||||
do_request(method, url, headers, body, opts)
|
||||
end
|
||||
end
|
||||
|
||||
@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
|
||||
case :hackney.stream_body(ref) do
|
||||
:done -> :done
|
||||
|
|
@ -62,8 +74,33 @@ defmodule Pleroma.ReverseProxy.Client.Hackney do
|
|||
end
|
||||
|
||||
@impl true
|
||||
def close(%{ref: 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
|
||||
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"
|
||||
)
|
||||
|
||||
: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
|
||||
|
||||
defp redirect(url, resp_headers, env, limit) do
|
||||
new_url = absolute_redirect_url(url, resp_headers)
|
||||
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
|
||||
{: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)
|
||||
|
||||
{: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}
|
||||
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,
|
||||
proxy: proxy
|
||||
} do
|
||||
|
|
@ -28,19 +28,15 @@ defmodule Pleroma.HTTP.HackneyFollowRedirectRegressionTest do
|
|||
opts = [
|
||||
pool: :media,
|
||||
proxy: proxy.proxy_url,
|
||||
insecure: true,
|
||||
ssl_options: tls_client_options(tls_server),
|
||||
connect_timeout: 1_000,
|
||||
recv_timeout: 1_000,
|
||||
follow_redirect: true,
|
||||
force_redirect: true
|
||||
force_redirect: true,
|
||||
with_body: true
|
||||
]
|
||||
|
||||
{pid, ref} = spawn_monitor(fn -> :hackney.request(:get, url, [], <<>>, opts) end)
|
||||
|
||||
assert_receive {:DOWN, ^ref, :process, ^pid, reason}, 5_000
|
||||
|
||||
assert match?({%FunctionClauseError{}, _}, reason) or match?(%FunctionClauseError{}, reason) or
|
||||
match?({:function_clause, _}, reason)
|
||||
assert {:ok, 200, _headers, "ok"} = :hackney.request(:get, url, [], <<>>, opts)
|
||||
end
|
||||
|
||||
test "redirects work via proxy when hackney follow_redirect is disabled", %{
|
||||
|
|
@ -52,7 +48,7 @@ defmodule Pleroma.HTTP.HackneyFollowRedirectRegressionTest do
|
|||
adapter_opts = [
|
||||
pool: :media,
|
||||
proxy: proxy.proxy_url,
|
||||
insecure: true,
|
||||
ssl_options: tls_client_options(tls_server),
|
||||
connect_timeout: 1_000,
|
||||
recv_timeout: 1_000,
|
||||
follow_redirect: false,
|
||||
|
|
@ -75,7 +71,7 @@ defmodule Pleroma.HTTP.HackneyFollowRedirectRegressionTest do
|
|||
opts = [
|
||||
pool: :media,
|
||||
proxy: proxy.proxy_url,
|
||||
insecure: true,
|
||||
ssl_options: tls_client_options(tls_server),
|
||||
connect_timeout: 1_000,
|
||||
recv_timeout: 1_000,
|
||||
follow_redirect: true
|
||||
|
|
@ -97,7 +93,7 @@ defmodule Pleroma.HTTP.HackneyFollowRedirectRegressionTest do
|
|||
opts = [
|
||||
pool: :media,
|
||||
proxy: proxy.proxy_url,
|
||||
insecure: true,
|
||||
ssl_options: tls_client_options(tls_server),
|
||||
connect_timeout: 1_000,
|
||||
recv_timeout: 1_000,
|
||||
follow_redirect: true
|
||||
|
|
@ -119,7 +115,7 @@ defmodule Pleroma.HTTP.HackneyFollowRedirectRegressionTest do
|
|||
opts = [
|
||||
pool: :media,
|
||||
proxy: proxy.proxy_url,
|
||||
insecure: true,
|
||||
ssl_options: tls_client_options(tls_server),
|
||||
connect_timeout: 1_000,
|
||||
recv_timeout: 1_000,
|
||||
follow_redirect: true
|
||||
|
|
@ -161,7 +157,13 @@ defmodule Pleroma.HTTP.HackneyFollowRedirectRegressionTest do
|
|||
accept_tls_loop(listener)
|
||||
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
|
||||
|
||||
defp stop_tls_redirect_server(%{listener: listener, acceptor: acceptor}) do
|
||||
|
|
@ -210,11 +212,17 @@ defmodule Pleroma.HTTP.HackneyFollowRedirectRegressionTest do
|
|||
:ssl.close(ssl_socket)
|
||||
else
|
||||
_ ->
|
||||
_ = :gen_tcp.close(tcp_socket)
|
||||
_ = :ssl.close(tcp_socket)
|
||||
:ok
|
||||
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
|
||||
case :ssl.recv(socket, 0, 1_000) do
|
||||
{:ok, data} ->
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue