@@ -151,6 +151,7 @@ struct Client
151
151
escape_path_params:: Union{Nothing,Bool}
152
152
chunk_reader_type:: Union{Nothing,Type{<:AbstractChunkReader}}
153
153
long_polling_timeout:: Int
154
+ request_interrupt_supported:: Bool
154
155
155
156
function Client (root:: String ;
156
157
headers:: Dict{String,String} = Dict {String,String} (),
@@ -174,7 +175,8 @@ struct Client
174
175
# disable ALPN to support servers that enable both HTTP/2 and HTTP/1.1 on same port
175
176
Downloads. Curl. setopt (easy, LibCURL. CURLOPT_SSL_ENABLE_ALPN, 0 )
176
177
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)
178
180
end
179
181
end
180
182
@@ -556,6 +558,10 @@ function do_request(ctx::Ctx, stream::Bool=false; stream_to::Union{Channel,Nothi
556
558
557
559
try
558
560
if stream
561
+ interrupt = nothing
562
+ if ctx. client. request_interrupt_supported
563
+ kwargs[:interrupt ] = interrupt = Base. Event ()
564
+ end
559
565
@sync begin
560
566
download_task = @async begin
561
567
try
@@ -565,7 +571,10 @@ function do_request(ctx::Ctx, stream::Bool=false; stream_to::Union{Channel,Nothi
565
571
kwargs...
566
572
)
567
573
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)
569
578
@error (" exception invoking request" , exception= (ex,catch_backtrace ()))
570
579
rethrow ()
571
580
end
@@ -604,10 +613,25 @@ function do_request(ctx::Ctx, stream::Bool=false; stream_to::Union{Channel,Nothi
604
613
catch ex
605
614
isa (ex, InvalidStateException) || rethrow (ex)
606
615
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 )
608
633
end
609
634
end
610
- interrupted || istaskdone (download_task) || schedule (download_task, InterruptException (), error= true )
611
635
end
612
636
end
613
637
else
@@ -863,4 +887,13 @@ function deep_object_serialize(dict::Dict, parent_key::String = "")
863
887
return Dict (parts)
864
888
end
865
889
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
+
866
899
end # module Clients
0 commit comments