diff options
author | Junegunn Choi <junegunn.c@gmail.com> | 2024-01-21 22:58:18 +0900 |
---|---|---|
committer | Junegunn Choi <junegunn.c@gmail.com> | 2024-01-21 23:04:37 +0900 |
commit | 7484292e63f0dabca4cccdca136f6a6d105b3b79 (patch) | |
tree | 90deb960a810a9a1125c3374f921097779d248cb /src | |
parent | 687c2741b8d5c0cfcd0b318596cd04914fecf4e9 (diff) |
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.
Diffstat (limited to 'src')
-rw-r--r-- | src/server.go | 16 |
1 files changed, 13 insertions, 3 deletions
diff --git a/src/server.go b/src/server.go index e655896f..d5a148df 100644 --- a/src/server.go +++ b/src/server.go @@ -30,7 +30,9 @@ const ( httpOk = "HTTP/1.1 200 OK" + crlf httpBadRequest = "HTTP/1.1 400 Bad Request" + crlf httpUnauthorized = "HTTP/1.1 401 Unauthorized" + crlf + httpUnavailable = "HTTP/1.1 503 Service Unavailable" + crlf httpReadTimeout = 10 * time.Second + jsonContentType = "Content-Type: application/json" + crlf maxContentLength = 1024 * 1024 ) @@ -141,7 +143,7 @@ func (server *httpServer) handleHttpRequest(conn net.Conn) string { return answer(httpBadRequest, message) } 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)) scanner := bufio.NewScanner(conn) @@ -165,8 +167,16 @@ func (server *httpServer) handleHttpRequest(conn net.Conn) string { getMatch := getRegex.FindStringSubmatch(text) if len(getMatch) > 0 { server.actionChannel <- []*action{{t: actResponse, a: getMatch[1]}} - response := <-server.responseChannel - return good(response) + select { + case response := <-server.responseChannel: + 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") { return bad("invalid request method") } |