diff --git a/src/Downloads.jl b/src/Downloads.jl index 7259e00..b9f18c0 100644 --- a/src/Downloads.jl +++ b/src/Downloads.jl @@ -20,7 +20,7 @@ using ArgTools include("Curl/Curl.jl") using .Curl -export download, request, Downloader, Response, RequestError +export download, request, Downloader, Response, RequestError, pushhook!, deletehook! ## public API types ## @@ -65,6 +65,44 @@ const DOWNLOAD_LOCK = ReentrantLock() const DOWNLOADER = Ref{Union{Downloader, Nothing}}(nothing) const EASY_HOOK = Ref{Union{Function, Nothing}}(nothing) +## Allow for a set of global hooks that can customize each download (via setting parameters on the +## `Easy` object associated with a request +const HookKey = Int +current_key = 0 +GlobalHookEntry = Tuple{HookKey, Function} +const GLOBAL_HOOK_LOCK = ReentrantLock() +const GLOBAL_HOOKS = Array{GlobalHookEntry,1}(undef, 0) + +## Add hook +function pushhook!(hook::Function) :: HookKey + global current_key + key = -1 + lock(GLOBAL_HOOK_LOCK) do + key = current_key + push!(GLOBAL_HOOKS, (key, hook)) + current_key += 1 + end + return key +end + +function deletehook!(key::HookKey) + keep = x -> x[1] != key + lock(GLOBAL_HOOK_LOCK) do + count(keep, GLOBAL_HOOKS) < length(GLOBAL_HOOKS) || + warn("Downloads.jl: Hook key $(key) not found in global hooks") + filter!(keep, GLOBAL_HOOKS) + end +end + +function apply_global_hooks(easy::Easy, info::NamedTuple) + lock(GLOBAL_HOOK_LOCK) do + for (_,h) in GLOBAL_HOOKS + h(easy, info) + end + end +end + + """ struct Response proto :: String @@ -358,6 +396,8 @@ function request( progress !== nothing && enable_progress(easy) set_ca_roots(downloader, easy) info = (url = url, method = method, headers = headers) + + apply_global_hooks(easy, info) easy_hook(downloader, easy, info) # do the request diff --git a/test/runtests.jl b/test/runtests.jl index ddc963f..bff3601 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,6 +1,27 @@ include("setup.jl") @testset "Downloads.jl" begin + @testset "Global easy hooks" begin + trip_wire = 0 + original_hook_count = length(Downloads.GLOBAL_HOOKS) + url = "$server/get" + hook = (easy, info) -> trip_wire += 1 + key1 = pushhook!(hook) + _ = download_body(url) + @test trip_wire == 1 + key2 = pushhook!(hook) + _ = download_body(url) + @test trip_wire == 3 + deletehook!(key1) + _ = download_body(url) + @test trip_wire == 4 + deletehook!(key2) + _ = download_body(url) + @test trip_wire == 4 + + @test length(Downloads.GLOBAL_HOOKS) == original_hook_count + end + #= @testset "libcurl configuration" begin julia = "$(VERSION.major).$(VERSION.minor)" @test Curl.USER_AGENT == "curl/$(Curl.CURL_VERSION) julia/$julia" @@ -560,6 +581,7 @@ include("setup.jl") @test Downloads.content_length(["Accept"=>"*/*",]) === nothing @test Downloads.content_length(["Accept"=>"*/*", "Content-Length"=>"100"]) == 100 end + =# end Downloads.DOWNLOADER[] = nothing