@@ -151,6 +151,7 @@ struct Client
151151 escape_path_params:: Union{Nothing,Bool}
152152 chunk_reader_type:: Union{Nothing,Type{<:AbstractChunkReader}}
153153 long_polling_timeout:: Int
154+ request_interrupt_supported:: Bool
154155
155156 function Client (root:: String ;
156157 headers:: Dict{String,String} = Dict {String,String} (),
@@ -174,7 +175,8 @@ struct Client
174175 # disable ALPN to support servers that enable both HTTP/2 and HTTP/1.1 on same port
175176 Downloads. Curl. setopt (easy, LibCURL. CURLOPT_SSL_ENABLE_ALPN, 0 )
176177 end
177- new (root, headers, get_return_type, clntoptions, downloader, Ref {Int} (timeout), pre_request_hook, escape_path_params, chunk_reader_type, long_polling_timeout)
178+ interruptable = request_supports_interrupt ()
179+ new (root, headers, get_return_type, clntoptions, downloader, Ref {Int} (timeout), pre_request_hook, escape_path_params, chunk_reader_type, long_polling_timeout, interruptable)
178180 end
179181end
180182
@@ -556,6 +558,10 @@ function do_request(ctx::Ctx, stream::Bool=false; stream_to::Union{Channel,Nothi
556558
557559 try
558560 if stream
561+ interrupt = nothing
562+ if ctx. client. request_interrupt_supported
563+ kwargs[:interrupt ] = interrupt = Base. Event ()
564+ end
559565 @sync begin
560566 download_task = @async begin
561567 try
@@ -565,7 +571,10 @@ function do_request(ctx::Ctx, stream::Bool=false; stream_to::Union{Channel,Nothi
565571 kwargs...
566572 )
567573 catch ex
568- if ! isa (ex, InterruptException)
574+ # If request method does not support interrupt natively, InterrptException is used to
575+ # signal the download task to stop. Otherwise, InterrptException is not handled and is rethrown.
576+ # Any exception other than InterruptException is rethrown always.
577+ if ctx. client. request_interrupt_supported || ! isa (ex, InterruptException)
569578 @error (" exception invoking request" , exception= (ex,catch_backtrace ()))
570579 rethrow ()
571580 end
@@ -604,10 +613,25 @@ function do_request(ctx::Ctx, stream::Bool=false; stream_to::Union{Channel,Nothi
604613 catch ex
605614 isa (ex, InvalidStateException) || rethrow (ex)
606615 interrupted = true
607- istaskdone (download_task) || schedule (download_task, InterruptException (), error= true )
616+ if ! istaskdone (download_task)
617+ # If the download task is still running, interrupt it.
618+ # If it supports interrupt natively, then use event to signal it.
619+ # Otherwise, throw an InterruptException to stop the download task.
620+ if ctx. client. request_interrupt_supported
621+ notify (interrupt)
622+ else
623+ schedule (download_task, InterruptException (), error= true )
624+ end
625+ end
626+ end
627+ end
628+ if ! interrupted && ! istaskdone (download_task)
629+ if ctx. client. request_interrupt_supported
630+ notify (interrupt)
631+ else
632+ schedule (download_task, InterruptException (), error= true )
608633 end
609634 end
610- interrupted || istaskdone (download_task) || schedule (download_task, InterruptException (), error= true )
611635 end
612636 end
613637 else
@@ -863,4 +887,13 @@ function deep_object_serialize(dict::Dict, parent_key::String = "")
863887 return Dict (parts)
864888end
865889
890+ function request_supports_interrupt ()
891+ for m in methods (request)
892+ if :interrupt in Base. kwarg_decl (m)
893+ return true
894+ end
895+ end
896+ return false
897+ end
898+
866899end # module Clients
0 commit comments