Skip to content

Commit

Permalink
Fix svg+xml content type header
Browse files Browse the repository at this point in the history
  • Loading branch information
simonprev committed Feb 2, 2024
1 parent 08f27cb commit ae1148d
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 30 deletions.
84 changes: 55 additions & 29 deletions lib/plug_image_processing/sources/url.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,19 @@ defmodule PlugImageProcessing.Sources.URL do

alias PlugImageProcessing.Options

@valid_types ~w(jpg jpeg png webp gif svg svg+xml)
@types_extensions_mapping %{
"jpg" => ".jpg",
"jpeg" => ".jpg",
"png" => ".png",
"webp" => ".webp",
"gif" => ".gif",
"svg" => ".svg",
"svg+xml" => ".svg"
}

@valid_types Map.keys(@types_extensions_mapping)
@valid_extensions Map.values(@types_extensions_mapping)
@extensions_types_mapping Map.new(@types_extensions_mapping, fn {k, v} -> {v, k} end)

def fetch_body(source, http_client_timeout, http_client_max_length, http_client, http_client_cache) do
metadata = %{uri: source.uri}
Expand Down Expand Up @@ -58,27 +70,35 @@ defmodule PlugImageProcessing.Sources.URL do
end
end

defp get_file_suffix(source, content_type) do
# Find the type in the source response content-type header
type = String.trim_leading(content_type, "image/")
defp get_file_suffix_from_http_header(content_type) do
content_type = String.trim_leading(content_type, "image/")

type =
if type in @valid_types do
"." <> type
else
nil
end
if content_type in @valid_types do
content_type
end
end

# Find the type in the client provided "type" query param
type =
if source.params["type"] in @valid_types do
"." <> source.params["type"]
else
type
end
defp get_file_suffix_from_query_params(params) do
if params["type"] in @valid_types do
params["type"]
end
end

# Fallback to the extension name of the "url" query param
type = type || (source.uri.path && Path.extname(source.uri.path))
defp get_file_suffix_from_uri(uri) do
case uri.path && Path.extname(uri.path) do
"." <> content_type -> content_type
_ -> nil
end
end

defp get_file_suffix(source, content_type) do
image_type = get_file_suffix_from_query_params(source.params)
# If "type" query param is not found or is invalid, fallback to HTTP header
image_type = image_type || get_file_suffix_from_http_header(content_type)
# If HTTP header "Content-Type" is not found or is invalid, fallback to source uri
image_type = image_type || get_file_suffix_from_uri(source.uri)

type = Map.get(@types_extensions_mapping, image_type)

case type do
".gif" ->
Expand All @@ -98,16 +118,22 @@ defmodule PlugImageProcessing.Sources.URL do

{"image/png", ".png" <> options}

"." <> type_name ->
options =
[
{"Q", Options.cast_integer(source.params["quality"])},
{"strip", Options.cast_boolean(source.params["stripmeta"])}
]
|> Options.build()
|> Options.encode_suffix()

{"image/#{type_name}", type <> options}
extension_name when extension_name in @valid_extensions ->
content_type = Map.get(@extensions_types_mapping, extension_name)

if content_type do
options =
[
{"Q", Options.cast_integer(source.params["quality"])},
{"strip", Options.cast_boolean(source.params["stripmeta"])}
]
|> Options.build()
|> Options.encode_suffix()

{"image/#{content_type}", type <> options}
else
:invalid_file_type
end

_ ->
:invalid_file_type
Expand Down
1 change: 1 addition & 0 deletions lib/plug_image_processing/web.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ defmodule PlugImageProcessing.Web do
plug(:cast_config)
plug(:assign_operation_name)
plug(:run_middlewares)
plug(:fetch_query_params)
plug(:action)

def call(conn, opts) do
Expand Down
11 changes: 10 additions & 1 deletion test/plug_image_processing/web_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ defmodule PlugImageProcessing.WebTest do
@behaviour PlugImageProcessing.Sources.HTTPClient
def get("http://example.org/valid.jpg", _), do: {:ok, @image, [{"Content-type", "image/jpg"}]}
def get("http://example.org/valid.gif", _), do: {:ok, @gif_image, [{"Content-type", "image/gif"}]}
def get("http://example.org/valid.svg", _), do: {:ok, @svg_image, [{"Content-type", "image/svg_xml"}]}
def get("http://example.org/valid.svg", _), do: {:ok, @svg_image, [{"Content-type", "image/svg"}]}
def get("http://example.org/valid-xml.svg", _), do: {:ok, @svg_image, [{"Content-type", "image/svg+xml"}]}
def get("http://example.org/retry.jpg", _), do: {:ok, @image, [{"Content-type", "image/jpg"}]}
def get("http://example.org/404.jpg", _), do: {:error, "404 Not found"}

Expand Down Expand Up @@ -144,6 +145,14 @@ defmodule PlugImageProcessing.WebTest do
assert conn.status === 200
end

test "echo svg+xml", %{config: config} do
plug_opts = Web.init(config)
conn = conn(:get, "/imageproxy", %{url: "http://example.org/valid-xml.svg"})
conn = Web.call(conn, plug_opts)

assert conn.status === 200
end

test "echo redirect gif", %{config: config} do
config = Keyword.merge(config, source_url_redirect_operations: [""])
plug_opts = Web.init(config)
Expand Down

0 comments on commit ae1148d

Please sign in to comment.