Skip to content

Commit 853f142

Browse files
committed
Unify code paths and reuse exception
1 parent 33644c2 commit 853f142

File tree

4 files changed

+42
-54
lines changed

4 files changed

+42
-54
lines changed

lib/plug/csrf_protection.ex

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,6 @@ defmodule Plug.CSRFProtection do
102102
"""
103103

104104
import Plug.Conn
105-
require Bitwise
106105
require Logger
107106

108107
alias Plug.Crypto.KeyGenerator

lib/plug/request_id.ex

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ defmodule Plug.RequestId do
5656
5757
"""
5858

59-
require Logger
6059
alias Plug.Conn
6160
@behaviour Plug
6261

lib/plug/static.ex

Lines changed: 41 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -153,10 +153,6 @@ defmodule Plug.Static do
153153
defexception message: "invalid path for static asset", plug_status: 400
154154
end
155155

156-
defmodule MissingPathInOnlyFilterError do
157-
defexception message: "static asset found but not specified in :only rule", plug_status: 400
158-
end
159-
160156
@impl true
161157
def init(opts) do
162158
from =
@@ -174,10 +170,17 @@ defmodule Plug.Static do
174170
|> maybe_add("br", ".br", Keyword.get(opts, :brotli, false))
175171
|> maybe_add("gzip", ".gz", Keyword.get(opts, :gzip, false))
176172

173+
only_status =
174+
if Keyword.get(opts, :raise_on_missing_only, false) do
175+
:raise
176+
else
177+
:forbidden
178+
end
179+
177180
%{
178181
encodings: encodings,
179-
only_rules: {Keyword.get(opts, :only, []), Keyword.get(opts, :only_matching, [])},
180-
raise_on_missing_only: Keyword.get(opts, :raise_on_missing_only, false),
182+
only_rules:
183+
{Keyword.get(opts, :only, []), Keyword.get(opts, :only_matching, []), only_status},
181184
qs_cache:
182185
Keyword.get(opts, :cache_control_for_vsn_requests, "public, max-age=31536000, immutable"),
183186
et_cache: Keyword.get(opts, :cache_control_for_etags, "public"),
@@ -197,60 +200,51 @@ defmodule Plug.Static do
197200
when meth in @allowed_methods do
198201
segments = subset(at, conn.path_info)
199202

200-
if allowed?(only_rules, segments) do
201-
segments = Enum.map(segments, &URI.decode/1)
203+
case path_status(only_rules, segments) do
204+
:forbidden ->
205+
conn
202206

203-
if invalid_path?(segments) do
204-
raise InvalidPathError, "invalid path for static asset: #{conn.request_path}"
205-
end
207+
status ->
208+
segments = Enum.map(segments, &URI.decode/1)
206209

207-
path = path(from, segments)
208-
range = get_req_header(conn, "range")
209-
encoding = file_encoding(conn, path, range, encodings)
210-
serve_static(encoding, conn, segments, range, options)
211-
else
212-
maybe_raise_on_missing_only(segments, from, options)
213-
conn
210+
if invalid_path?(segments) do
211+
raise InvalidPathError, "invalid path for static asset: #{conn.request_path}"
212+
end
213+
214+
path = path(from, segments)
215+
range = get_req_header(conn, "range")
216+
217+
case file_encoding(conn, path, range, encodings) do
218+
:error ->
219+
conn
220+
221+
triplet ->
222+
if status == :raise do
223+
raise InvalidPathError,
224+
"static file exists but is not in the :only list: #{Enum.join(segments, "/")}. " <>
225+
"Add it to the :only list or use :only_matching for prefix matching"
226+
end
227+
228+
serve_static(triplet, conn, segments, range, options)
229+
end
214230
end
215231
end
216232

217233
def call(conn, _options) do
218234
conn
219235
end
220236

221-
defp allowed?(_only_rules, []), do: false
222-
defp allowed?({[], []}, _list), do: true
223-
224-
defp allowed?({full, prefix}, [h | _]) do
225-
h in full or (prefix != [] and match?({0, _}, :binary.match(h, prefix)))
226-
end
227-
228-
defp maybe_raise_on_missing_only([], _from, _options), do: :ok
229-
230-
defp maybe_raise_on_missing_only(segments, from, %{
231-
raise_on_missing_only: true,
232-
only_rules: {only, _only_matching}
233-
})
234-
when only != [] do
235-
segments = Enum.map(segments, &URI.decode/1)
236-
237-
if not invalid_path?(segments) do
238-
path = path(from, segments)
239-
240-
case :prim_file.read_file_info(path, [:posix]) do
241-
{:ok, file_info(type: :regular)} ->
242-
raise MissingPathInOnlyFilterError,
243-
"static file exists but is not in the :only list: #{Enum.join(segments, "/")}. " <>
244-
"Add it to the :only list or use :only_matching for prefix matching"
237+
defp path_status(_only_rules, []), do: :forbidden
238+
defp path_status({[], [], _}, _list), do: :allowed
245239

246-
_ ->
247-
:ok
248-
end
240+
defp path_status({full, prefix, status}, [h | _]) do
241+
if h in full or (prefix != [] and match?({0, _}, :binary.match(h, prefix))) do
242+
:allowed
243+
else
244+
status
249245
end
250246
end
251247

252-
defp maybe_raise_on_missing_only(_segments, _from, _options), do: :ok
253-
254248
defp maybe_put_content_type(conn, false, _), do: conn
255249

256250
defp maybe_put_content_type(conn, types, filename) do
@@ -286,10 +280,6 @@ defmodule Plug.Static do
286280
end
287281
end
288282

289-
defp serve_static(:error, conn, _segments, _range, _options) do
290-
conn
291-
end
292-
293283
defp serve_range(conn, file_info, path, [range], options) do
294284
file_info(size: file_size) = file_info
295285

test/plug/static_test.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -851,7 +851,7 @@ defmodule Plug.StaticTest do
851851
end
852852

853853
test "raise_on_missing_only option validates static files against only list" do
854-
assert_raise Plug.Static.MissingPathInOnlyFilterError,
854+
assert_raise Plug.Static.InvalidPathError,
855855
~r/static file exists but is not in the :only list: file-deadbeef.txt/,
856856
fn ->
857857
RaiseOnMissingOnlyPlug.call(conn(:get, "/file-deadbeef.txt"), [])

0 commit comments

Comments
 (0)