From 2115a86a6d876d16310152ddda697eea5f294961 Mon Sep 17 00:00:00 2001 From: tan Date: Fri, 9 Aug 2024 14:50:05 +0530 Subject: [PATCH 1/2] fix: handle FDWatcher exception on closed sockets Adding checks to handle exception thrown while constructing FDWatcher if the socket handle is closed. Also checking the curl return code while adding handle to multi, and not proceeding if that failed. Should fix #253 --- src/Curl/Multi.jl | 23 +++++++++++++++++++++-- src/Downloads.jl | 6 +++++- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/Curl/Multi.jl b/src/Curl/Multi.jl index d2be032..a21db78 100644 --- a/src/Curl/Multi.jl +++ b/src/Curl/Multi.jl @@ -43,7 +43,7 @@ end function add_handle(multi::Multi, easy::Easy) connect_semaphore_acquire(easy) - lock(multi.lock) do + added = lock(multi.lock) do if isempty(multi.easies) preserve_handle(multi) end @@ -51,6 +51,10 @@ function add_handle(multi::Multi, easy::Easy) init!(multi) @check curl_multi_add_handle(multi.handle, easy.handle) end + if added != 0 + connect_semaphore_release(easy) + end + return added end const MULTIS_LOCK = Base.ReentrantLock() @@ -170,7 +174,22 @@ function socket_callback( if action in (CURL_POLL_IN, CURL_POLL_OUT, CURL_POLL_INOUT) readable = action in (CURL_POLL_IN, CURL_POLL_INOUT) writable = action in (CURL_POLL_OUT, CURL_POLL_INOUT) - watcher = FDWatcher(OS_HANDLE(sock), readable, writable) + watcher = try + FDWatcher(OS_HANDLE(sock), readable, writable) + catch watcher_ex + if watcher_ex isa Base.IOError + task = @async begin + lock(multi.lock) do + @check curl_multi_socket_action(multi.handle, sock, CURL_CSELECT_ERR) + check_multi_info(multi) + end + end + @isdefined(errormonitor) && errormonitor(task) + nothing + else + rethrow() + end + end preserve_handle(watcher) watcher_p = pointer_from_objref(watcher) @check curl_multi_assign(multi.handle, sock, watcher_p) diff --git a/src/Downloads.jl b/src/Downloads.jl index 1fe95fa..958410c 100644 --- a/src/Downloads.jl +++ b/src/Downloads.jl @@ -395,7 +395,11 @@ function request( easy_hook(downloader, easy, info) # do the request - add_handle(downloader.multi, easy) + add_handle_error = add_handle(downloader.multi, easy) + if add_handle_error != 0 + no_response = Response(nothing, "", 0, "", []) + throw(RequestError(url, add_handle_error, "", no_response)) + end interrupted = Threads.Atomic{Bool}(false) if interrupt !== nothing interrupt_task = @async begin From 133b28540c43e7e37eae82a3366e7fbc588acbce Mon Sep 17 00:00:00 2001 From: tan Date: Wed, 18 Sep 2024 09:39:00 +0530 Subject: [PATCH 2/2] fix --- src/Curl/Multi.jl | 3 +++ src/Downloads.jl | 7 ++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Curl/Multi.jl b/src/Curl/Multi.jl index a21db78..f1447d5 100644 --- a/src/Curl/Multi.jl +++ b/src/Curl/Multi.jl @@ -190,6 +190,9 @@ function socket_callback( rethrow() end end + if watcher === nothing + return -1 + end preserve_handle(watcher) watcher_p = pointer_from_objref(watcher) @check curl_multi_assign(multi.handle, sock, watcher_p) diff --git a/src/Downloads.jl b/src/Downloads.jl index 958410c..dae9566 100644 --- a/src/Downloads.jl +++ b/src/Downloads.jl @@ -398,7 +398,12 @@ function request( add_handle_error = add_handle(downloader.multi, easy) if add_handle_error != 0 no_response = Response(nothing, "", 0, "", []) - throw(RequestError(url, add_handle_error, "", no_response)) + request_error = RequestError(url, add_handle_error, "", no_response) + if throw + Base.throw(request_error) + else + return request_error + end end interrupted = Threads.Atomic{Bool}(false) if interrupt !== nothing