summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJunegunn Choi <junegunn.c@gmail.com>2024-01-21 22:58:18 +0900
committerJunegunn Choi <junegunn.c@gmail.com>2024-01-21 23:04:37 +0900
commit7484292e63f0dabca4cccdca136f6a6d105b3b79 (patch)
tree90deb960a810a9a1125c3374f921097779d248cb /src
parent687c2741b8d5c0cfcd0b318596cd04914fecf4e9 (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.go16
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")
}