Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(server): spawn task sooner in listenloop #1102

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions docs/examples/cors_server.jl
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const CORS_RES_HEADERS = ["Access-Control-Allow-Origin" => "*"]
#=
JSONMiddleware minimizes code by automatically converting the request body
to JSON to pass to the other service functions automatically. JSONMiddleware
recieves the body of the response from the other service funtions and sends
receives the body of the response from the other service funtions and sends
back a success response code
=#
function JSONMiddleware(handler)
Expand All @@ -65,9 +65,9 @@ function JSONMiddleware(handler)
end

#= CorsMiddleware: handles preflight request with the OPTIONS flag
If a request was recieved with the correct headers, then a response will be
If a request was received with the correct headers, then a response will be
sent back with a 200 code, if the correct headers were not specified in the request,
then a CORS error will be recieved on the client side
then a CORS error will be received on the client side

Since each request passes throught the CORS Handler, then if the request is
not a preflight request, it will simply go to the JSONMiddleware to be passed to the
Expand Down
60 changes: 39 additions & 21 deletions src/Servers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,22 @@ accept(s::Listener{SSLConfig}) = getsslcontext(Sockets.accept(s.server), s.ssl)

function getsslcontext(tcp, sslconfig)
try
handshake_done = Ref{Bool}(false)
ssl = MbedTLS.SSLContext()
MbedTLS.setup!(ssl, sslconfig)
MbedTLS.associate!(ssl, tcp)
thistask = current_task()
# this task is meant to be super small while the handshake remains on the main task
@async begin
timedwait(2.0) do
handshake_done[] || istaskdone(thistask)
end
if !handshake_done[] && !istaskdone(thistask)
Base.throwto(thistask, Base.IOError("SSL handshake timed out", Base.ETIMEDOUT))
end
end
MbedTLS.handshake!(ssl)
handshake_done[] = true
return ssl
catch e
@try Base.IOError close(tcp)
Expand Down Expand Up @@ -369,26 +381,32 @@ function listenloop(f, listener, conns, tcpisvalid,
while isopen(listener)
try
Base.acquire(sem)
io = accept(listener)
if io === nothing
@warnv 1 "unable to accept new connection"
continue
elseif !tcpisvalid(io)
@warnv 1 "!tcpisvalid: $io"
close(io)
continue
end
conn = Connection(io)
conn.state = IDLE
push!(conns, conn)
conn.host, conn.port = listener.hostname, listener.hostport
@async try
handle_connection(f, conn, listener, readtimeout, access_log)
finally
# handle_connection is in charge of closing the underlying io
delete!(conns, conn)
Base.release(sem)
end
io = Sockets.accept(listener.server)
@async begin
local conn = nothing
try
if io === nothing
@warnv 1 "unable to accept new connection"
return
end
if !isnothing(listener.ssl)
io = getsslcontext(io, listener.ssl)
end
if !tcpisvalid(io)
close(io)
return
end
conn = Connection(io)
conn.state = IDLE
push!(conns, conn)
conn.host, conn.port = listener.hostname, listener.hostport
handle_connection(f, conn, listener, readtimeout, access_log)
finally
# handle_connection is in charge of closing the underlying io, but it may not get there
!isnothing(conn) && delete!(conns, conn)
Base.release(sem)
end
end # Task.@spawn
catch e
if e isa Base.IOError && e.code == Base.UV_ECONNABORTED
verbose >= 0 && @infov 1 "Server on $(listener.hostname):$(listener.hostport) closing"
Expand Down Expand Up @@ -445,7 +463,7 @@ function handle_connection(f, c::Connection, listener, readtimeout, access_log)
request.response.status = 200

try
# invokelatest becuase the perf is negligible, but this makes live-editing handlers more Revise friendly
# invokelatest because the perf is negligible, but this makes live-editing handlers more Revise friendly
@debugv 1 "invoking handler"
Base.invokelatest(f, http)
# If `startwrite()` was never called, throw an error so we send a 500 and log this
Expand Down
2 changes: 1 addition & 1 deletion src/WebSockets.jl
Original file line number Diff line number Diff line change
Expand Up @@ -589,7 +589,7 @@ function Base.close(ws::WebSocket, body::CloseFrameBody=CloseFrameBody(1000, "")
ws.readclosed = true
end
end
# we either recieved the responding CLOSE frame and readclosed was set
# we either received the responding CLOSE frame and readclosed was set
# or there was an error/timeout reading it; in any case, readclosed should be closed now
@assert ws.readclosed
# if we're the server, it's our job to close the underlying socket
Expand Down
Loading