Skip to content

Commit 5643a85

Browse files
committed
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
1 parent b871386 commit 5643a85

File tree

2 files changed

+26
-3
lines changed

2 files changed

+26
-3
lines changed

src/Curl/Multi.jl

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,18 @@ end
4343

4444
function add_handle(multi::Multi, easy::Easy)
4545
connect_semaphore_acquire(easy)
46-
lock(multi.lock) do
46+
added = lock(multi.lock) do
4747
if isempty(multi.easies)
4848
preserve_handle(multi)
4949
end
5050
push!(multi.easies, easy)
5151
init!(multi)
5252
@check curl_multi_add_handle(multi.handle, easy.handle)
5353
end
54+
if added != 0
55+
connect_semaphore_release(easy)
56+
end
57+
return added
5458
end
5559

5660
const MULTIS_LOCK = Base.ReentrantLock()
@@ -179,7 +183,22 @@ function socket_callback(
179183
if action in (CURL_POLL_IN, CURL_POLL_OUT, CURL_POLL_INOUT)
180184
readable = action in (CURL_POLL_IN, CURL_POLL_INOUT)
181185
writable = action in (CURL_POLL_OUT, CURL_POLL_INOUT)
182-
watcher = FDWatcher(OS_HANDLE(sock), readable, writable)
186+
watcher = try
187+
FDWatcher(OS_HANDLE(sock), readable, writable)
188+
catch watcher_ex
189+
if watcher_ex isa Base.IOError
190+
task = @async begin
191+
lock(multi.lock) do
192+
@check curl_multi_socket_action(multi.handle, sock, CURL_CSELECT_ERR)
193+
check_multi_info(multi)
194+
end
195+
end
196+
@isdefined(errormonitor) && errormonitor(task)
197+
nothing
198+
else
199+
rethrow()
200+
end
201+
end
183202
preserve_handle(watcher)
184203
watcher_p = pointer_from_objref(watcher)
185204
@check curl_multi_assign(multi.handle, sock, watcher_p)

src/Downloads.jl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,11 @@ function request(
387387
easy_hook(downloader, easy, info)
388388

389389
# do the request
390-
add_handle(downloader.multi, easy)
390+
add_handle_error = add_handle(downloader.multi, easy)
391+
if add_handle_error != 0
392+
no_response = Response(nothing, "", 0, "", [])
393+
throw(RequestError(url, add_handle_error, "", no_response))
394+
end
391395
try # ensure handle is removed
392396
@sync begin
393397
@async for buf in easy.output

0 commit comments

Comments
 (0)