Skip to content

Commit

Permalink
fix: handle FDWatcher exception on closed sockets
Browse files Browse the repository at this point in the history
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
  • Loading branch information
tanmaykm committed Aug 9, 2024
1 parent b871386 commit 5643a85
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 3 deletions.
23 changes: 21 additions & 2 deletions src/Curl/Multi.jl
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,18 @@ 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
push!(multi.easies, 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()
Expand Down Expand Up @@ -179,7 +183,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)
Expand Down
6 changes: 5 additions & 1 deletion src/Downloads.jl
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,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
try # ensure handle is removed
@sync begin
@async for buf in easy.output
Expand Down

0 comments on commit 5643a85

Please sign in to comment.