@@ -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
0 commit comments