-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
httptransport: implement
apiError
using the new details
package
Signed-off-by: Hank Donnay <[email protected]>
- Loading branch information
Showing
2 changed files
with
24 additions
and
73 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,89 +1,40 @@ | ||
package httptransport | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
"encoding/json" | ||
"errors" | ||
"fmt" | ||
"net/http" | ||
|
||
"github.com/quay/zlog" | ||
"github.com/quay/clair/v4/httptransport/internal/details" | ||
) | ||
|
||
// StatusClientClosedRequest is a nonstandard HTTP status code used when the | ||
// client has gone away. | ||
// | ||
// This convention is cribbed from Nginx. | ||
const statusClientClosedRequest = 499 | ||
|
||
// ApiError writes an untyped (that is, "application/json") error with the | ||
// provided HTTP status code and message. | ||
// ApiError writes an error with the provided HTTP status code and message. | ||
// | ||
// ApiError does not return, but instead causes the goroutine to exit. | ||
// | ||
// Deprecated: This is implemented via [details.Error], which provides a | ||
// richer API. | ||
func apiError(ctx context.Context, w http.ResponseWriter, code int, f string, v ...interface{}) { | ||
const errheader = `Clair-Error` | ||
disconnect := false | ||
select { | ||
case <-ctx.Done(): | ||
disconnect = true | ||
default: | ||
} | ||
if ev := zlog.Debug(ctx); ev.Enabled() { | ||
ev. | ||
Bool("disconnect", disconnect). | ||
Int("code", code). | ||
Str("error", fmt.Sprintf(f, v...)). | ||
Msg("http error response") | ||
} else { | ||
ev.Send() | ||
} | ||
if disconnect { | ||
// Exit immediately if there's no client to read the response, anyway. | ||
w.WriteHeader(statusClientClosedRequest) | ||
panic(http.ErrAbortHandler) | ||
err := genericError{ | ||
status: code, | ||
err: fmt.Errorf(f, v...), | ||
} | ||
details.Error(ctx, w, &err) | ||
} | ||
|
||
type genericError struct { | ||
status int | ||
err error | ||
} | ||
|
||
h := w.Header() | ||
h.Del("link") | ||
h.Set("content-type", "application/json") | ||
h.Set("x-content-type-options", "nosniff") | ||
h.Set("trailer", errheader) | ||
w.WriteHeader(code) | ||
func (e *genericError) Error() string { | ||
return e.err.Error() | ||
} | ||
|
||
var buf bytes.Buffer | ||
buf.WriteString(`{"code":"`) | ||
switch code { | ||
case http.StatusBadRequest: | ||
buf.WriteString("bad-request") | ||
case http.StatusMethodNotAllowed: | ||
buf.WriteString("method-not-allowed") | ||
case http.StatusNotFound: | ||
buf.WriteString("not-found") | ||
case http.StatusTooManyRequests: | ||
buf.WriteString("too-many-requests") | ||
default: | ||
buf.WriteString("internal-error") | ||
} | ||
buf.WriteByte('"') | ||
if f != "" { | ||
buf.WriteString(`,"message":`) | ||
b, _ := json.Marshal(fmt.Sprintf(f, v...)) // OK use of encoding/json. | ||
buf.Write(b) | ||
} | ||
buf.WriteByte('}') | ||
func (e *genericError) Unwrap() error { | ||
return e.err | ||
} | ||
|
||
if _, err := buf.WriteTo(w); err != nil { | ||
h.Set(errheader, err.Error()) | ||
} | ||
switch err := http.NewResponseController(w).Flush(); { | ||
case errors.Is(err, nil): | ||
case errors.Is(err, http.ErrNotSupported): | ||
// Skip | ||
default: | ||
zlog.Warn(ctx). | ||
Err(err). | ||
Msg("unable to flush http response") | ||
} | ||
panic(http.ErrAbortHandler) | ||
func (e *genericError) ErrorStatus() int { | ||
return e.status | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters