mirror of
https://github.com/Llewellynvdm/fzf.git
synced 2024-06-13 20:52:21 +00:00
Avoid deadlocks by adding a 2 second timeout to GET / endpoint
Because fzf processes HTTP GET requests in the main event loop, accessing the endpoint from within execute/transform actions would result in a deadlock and hang fzf indefinitely. This commit sets a 2 second timeout to avoid the deadlock.
This commit is contained in:
parent
687c2741b8
commit
7484292e63
|
@ -831,12 +831,14 @@ e.g.
|
||||||
\fB# Start HTTP server on port 6266
|
\fB# Start HTTP server on port 6266
|
||||||
fzf --listen 6266
|
fzf --listen 6266
|
||||||
|
|
||||||
# Get program state in JSON format (experimental)
|
|
||||||
curl localhost:6266
|
|
||||||
|
|
||||||
# Send action to the server
|
# Send action to the server
|
||||||
curl -XPOST localhost:6266 -d 'reload(seq 100)+change-prompt(hundred> )'
|
curl -XPOST localhost:6266 -d 'reload(seq 100)+change-prompt(hundred> )'
|
||||||
|
|
||||||
|
# Get program state in JSON format (experimental)
|
||||||
|
# * Make sure NOT to access this endpoint from execute/transform actions
|
||||||
|
# as it will result in a timeout
|
||||||
|
curl localhost:6266
|
||||||
|
|
||||||
# Start HTTP server on port 6266 with remote connections allowed
|
# Start HTTP server on port 6266 with remote connections allowed
|
||||||
# * Listening on non-localhost address requires using an API key
|
# * Listening on non-localhost address requires using an API key
|
||||||
export FZF_API_KEY="$(head -c 32 /dev/urandom | base64)"
|
export FZF_API_KEY="$(head -c 32 /dev/urandom | base64)"
|
||||||
|
|
|
@ -30,7 +30,9 @@ const (
|
||||||
httpOk = "HTTP/1.1 200 OK" + crlf
|
httpOk = "HTTP/1.1 200 OK" + crlf
|
||||||
httpBadRequest = "HTTP/1.1 400 Bad Request" + crlf
|
httpBadRequest = "HTTP/1.1 400 Bad Request" + crlf
|
||||||
httpUnauthorized = "HTTP/1.1 401 Unauthorized" + crlf
|
httpUnauthorized = "HTTP/1.1 401 Unauthorized" + crlf
|
||||||
|
httpUnavailable = "HTTP/1.1 503 Service Unavailable" + crlf
|
||||||
httpReadTimeout = 10 * time.Second
|
httpReadTimeout = 10 * time.Second
|
||||||
|
jsonContentType = "Content-Type: application/json" + crlf
|
||||||
maxContentLength = 1024 * 1024
|
maxContentLength = 1024 * 1024
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -141,7 +143,7 @@ func (server *httpServer) handleHttpRequest(conn net.Conn) string {
|
||||||
return answer(httpBadRequest, message)
|
return answer(httpBadRequest, message)
|
||||||
}
|
}
|
||||||
good := func(message string) string {
|
good := func(message string) string {
|
||||||
return answer(httpOk+"Content-Type: application/json"+crlf, message)
|
return answer(httpOk+jsonContentType, message)
|
||||||
}
|
}
|
||||||
conn.SetReadDeadline(time.Now().Add(httpReadTimeout))
|
conn.SetReadDeadline(time.Now().Add(httpReadTimeout))
|
||||||
scanner := bufio.NewScanner(conn)
|
scanner := bufio.NewScanner(conn)
|
||||||
|
@ -165,8 +167,16 @@ func (server *httpServer) handleHttpRequest(conn net.Conn) string {
|
||||||
getMatch := getRegex.FindStringSubmatch(text)
|
getMatch := getRegex.FindStringSubmatch(text)
|
||||||
if len(getMatch) > 0 {
|
if len(getMatch) > 0 {
|
||||||
server.actionChannel <- []*action{{t: actResponse, a: getMatch[1]}}
|
server.actionChannel <- []*action{{t: actResponse, a: getMatch[1]}}
|
||||||
response := <-server.responseChannel
|
select {
|
||||||
|
case response := <-server.responseChannel:
|
||||||
return good(response)
|
return good(response)
|
||||||
|
case <-time.After(2 * time.Second):
|
||||||
|
go func() {
|
||||||
|
// Drain the channel
|
||||||
|
<-server.responseChannel
|
||||||
|
}()
|
||||||
|
return answer(httpUnavailable+jsonContentType, `{"error":"timeout"}`)
|
||||||
|
}
|
||||||
} else if !strings.HasPrefix(text, "POST / HTTP") {
|
} else if !strings.HasPrefix(text, "POST / HTTP") {
|
||||||
return bad("invalid request method")
|
return bad("invalid request method")
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user