podman events: check for an error after we finish reading events

The function that's handing us events will return an error after closing
the channel over which it's sending events, and its caller (in its own
goroutine) will then send that error over another channel.

The logic that started the goroutine is likely to notice that the events
channel is closed before noticing that the error channel has a result
for it to read, so any error that would have been communicated would be
lost.

When we finish reading events, check if the reader returned an error
before telling our caller that there was no error.

Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
This commit is contained in:
Nalin Dahyabhai
2024-05-13 13:29:09 -04:00
parent ef6619019f
commit c46884aa93
4 changed files with 27 additions and 6 deletions

View File

@ -43,7 +43,7 @@ func GetEvents(w http.ResponseWriter, r *http.Request) {
libpodFilters, err := util.FiltersFromRequest(r)
if err != nil {
utils.Error(w, http.StatusBadRequest, fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err))
utils.Error(w, http.StatusBadRequest, fmt.Errorf("failed to parse filters for %s: %w", r.URL.String(), err))
return
}
eventChannel := make(chan *events.Event)
@ -68,8 +68,13 @@ func GetEvents(w http.ResponseWriter, r *http.Request) {
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
flush()
wroteContent := false
defer func() {
if !wroteContent {
w.WriteHeader(http.StatusOK)
flush()
}
}()
coder := json.NewEncoder(w)
coder.SetEscapeHTML(true)
@ -78,8 +83,8 @@ func GetEvents(w http.ResponseWriter, r *http.Request) {
select {
case err := <-errorChannel:
if err != nil {
// FIXME StatusOK already sent above cannot send 500 here
utils.InternalServerError(w, err)
wroteContent = true
}
return
case evt := <-eventChannel:
@ -103,6 +108,7 @@ func GetEvents(w http.ResponseWriter, r *http.Request) {
if err := coder.Encode(e); err != nil {
logrus.Errorf("Unable to write json: %q", err)
}
wroteContent = true
flush()
case <-r.Context().Done():
return