@@ -220,6 +220,149 @@ include("setup.jl")
220220 end
221221 end
222222
223+ @testset " download file names" begin
224+ @testset " url_filename helper" begin
225+ for url in urls_with_filename ()
226+ @test nothing === Downloads. url_filename (url)
227+ end
228+ for name in file_names,
229+ url in urls_with_filename (name)
230+ @test name === Downloads. url_filename (url)
231+ end
232+ # URLs that we shouldn't get a file name from
233+ for url in [
234+ " " ,
235+ " abc" ,
236+ " abc.txt" ,
237+ " abc:def" ,
238+ " file:/" ,
239+ " file://" ,
240+ " file:///" ,
241+ " $server /anything/%" ,
242+ " $server /anything/%.txt" ,
243+ " $server /anything/%0.txt" ,
244+ ]
245+ @test nothing === Downloads. url_filename (url)
246+ end
247+ end
248+ # set a more unique default file name
249+ default = Downloads. DEFAULT_FILENAME
250+ @testset " from URL" begin
251+ for url in rand (urls_with_filename (), 10 )
252+ @test default == splitdir (download (url))[2 ]
253+ url′ = " $server /redirect-to?url=" * url_escape (url)
254+ # would be reasonable for this to be `default` too but
255+ # currently we use the name from the original URL
256+ @test Downloads. url_filename (url′) ==
257+ splitdir (download (url′))[2 ]
258+ end
259+ for name in file_names
260+ Sys. iswindows () && ' "' in name && continue
261+ for url in rand (urls_with_filename (name), 3 )
262+ @test name == splitdir (download (url))[2 ]
263+ url′ = " $server /redirect-to?url=" * url_escape (url)
264+ @test name == splitdir (download (url′))[2 ]
265+ end
266+ end
267+ end
268+ @testset " unsafe names in URLs" begin
269+ bad_names = [
270+ url_escape (" ." )
271+ url_escape (" .." )
272+ url_escape (" \a " )
273+ " %ff"
274+ " %ff.txt"
275+ ]
276+ if Sys. iswindows ()
277+ push! (bad_names, url_escape (" file." ))
278+ push! (bad_names, url_escape (" file " ))
279+ push! (bad_names, url_escape (" file:txt" ))
280+ push! (bad_names, url_escape (" CON" ))
281+ push! (bad_names, url_escape (" LPT1.txt" ))
282+ end
283+ for name in bad_names
284+ url = " $server /anything/$name "
285+ @test default == splitdir (download (url))[2 ]
286+ end
287+ end
288+ @testset " from content disposition" begin
289+ for name in file_names
290+ Sys. iswindows () && ' "' in name && continue
291+ url = content_disposition_url (:utf8 => name)
292+ @test name == splitdir (download (url))[2 ]
293+ isascii (name) || continue
294+ url = content_disposition_url (:ascii => name)
295+ @test name == splitdir (download (url))[2 ]
296+ url = content_disposition_url (:ascii_1q => name)
297+ @test name == splitdir (download (url))[2 ]
298+ url = content_disposition_url (:ascii_2q => name)
299+ @test name == splitdir (download (url))[2 ]
300+ end
301+ let name = " ÿ.txt"
302+ url = content_disposition_url (:latin1 => name)
303+ @test name == splitdir (download (url))[2 ]
304+ end
305+ let name = " y.txt" , name⁺ = " ÿ.txt"
306+ url = content_disposition_url (:ascii => name, :utf8 => name⁺)
307+ @test name⁺ == splitdir (download (url))[2 ]
308+ url = content_disposition_url (:ascii => name, :latin1 => name⁺)
309+ @test name⁺ == splitdir (download (url))[2 ]
310+ url = content_disposition_url (:utf8 => name⁺, :ascii => name)
311+ @test name⁺ == splitdir (download (url))[2 ]
312+ url = content_disposition_url (:latin1 => name⁺, :ascii => name)
313+ @test name⁺ == splitdir (download (url))[2 ]
314+ url = content_disposition_url (:latin1 => name, :utf8 => name⁺)
315+ @test name⁺ == splitdir (download (url))[2 ]
316+ url = content_disposition_url (:utf8 => name, :latin1 => name⁺)
317+ @test name⁺ == splitdir (download (url))[2 ]
318+ end
319+ end
320+ @testset " invalid content disposition" begin
321+ # invalid content disposition header syntax
322+ values = [
323+ " \a\b "
324+ " inline"
325+ " attachment"
326+ " attachment; filename"
327+ " attachment; filename='"
328+ " attachment; filename=\" "
329+ " attachment; filename='unclosed"
330+ " attachment; filename=\" unclosed"
331+ " attachment; filename*=name.txt"
332+ " attachment; filename*='name.txt'"
333+ " attachment; filename*=\" name.txt\" "
334+ " attachment; filename*=utf-8''%"
335+ " attachment; filename*=utf-8''%.txt"
336+ ]
337+ bad_names = [
338+ " "
339+ " ."
340+ " .."
341+ " foo/bar"
342+ " foo\0 "
343+ " \a "
344+ " ding!\v "
345+ ]
346+ if Sys. iswindows ()
347+ push! (bad_names, " file." )
348+ push! (bad_names, " file " )
349+ push! (bad_names, " file:txt" )
350+ push! (bad_names, " CON" )
351+ push! (bad_names, " LPT1.txt" )
352+ end
353+ for name in bad_names
354+ push! (values, " attachment; filename*=utf-8''$(url_escape (name)) " )
355+ ' \0 ' in name && continue
356+ push! (values, " attachment; filename=\" $name \" " )
357+ end
358+ for value in values
359+ url = " $server /response-headers?content-disposition=" *
360+ url_escape (value)
361+ @test " response-headers" === splitdir (download (url))[2 ]
362+ end
363+ end
364+ end
365+
223366 @testset " debug callback" begin
224367 url = " $server /get"
225368 events = Pair{String,String}[]
0 commit comments