-
-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathplain.go
93 lines (74 loc) · 2.64 KB
/
plain.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package herodot
import (
"context"
"fmt"
"net/http"
"github.com/pkg/errors"
)
// TextWriter outputs plain text
type TextWriter struct {
Reporter ErrorReporter
contentType string
}
var _ Writer = (*TextWriter)(nil)
// NewTextWriter returns a plain text writer
func NewTextWriter(reporter ErrorReporter, contentType string) *TextWriter {
if contentType == "" {
contentType = "plain"
}
writer := &TextWriter{
Reporter: reporter,
contentType: "text/" + contentType,
}
return writer
}
// Write a response object to the ResponseWriter with status code 200.
func (h *TextWriter) Write(w http.ResponseWriter, r *http.Request, e interface{}, _ ...EncoderOptions) {
h.WriteCode(w, r, http.StatusOK, e)
}
// WriteCode writes a response object to the ResponseWriter and sets a response code.
func (h *TextWriter) WriteCode(w http.ResponseWriter, r *http.Request, code int, e interface{}, _ ...EncoderOptions) {
if code == 0 {
code = http.StatusOK
}
if errors.Is(r.Context().Err(), context.Canceled) {
code = StatusClientClosedRequest
}
w.Header().Set("Content-Type", h.contentType)
w.WriteHeader(code)
fmt.Fprintf(w, "%s", e)
}
// WriteCreated writes a response object to the ResponseWriter with status code 201 and
// the Location header set to location.
func (h *TextWriter) WriteCreated(w http.ResponseWriter, r *http.Request, location string, e interface{}) {
w.Header().Set("Location", location)
h.WriteCode(w, r, http.StatusCreated, e)
}
// WriteError writes an error to ResponseWriter and tries to extract the error's status code by
// asserting statusCodeCarrier. If the error does not implement statusCodeCarrier, the status code
// is set to 500.
func (h *TextWriter) WriteError(w http.ResponseWriter, r *http.Request, err error, _ ...Option) {
if s, ok := errors.Cause(coalesceError(err)).(StatusCodeCarrier); ok {
h.WriteErrorCode(w, r, s.StatusCode(), err)
return
} else {
h.WriteErrorCode(w, r, http.StatusInternalServerError, err)
}
}
// WriteErrorCode writes an error to ResponseWriter and forces an error code.
func (h *TextWriter) WriteErrorCode(w http.ResponseWriter, r *http.Request, code int, err error, _ ...Option) {
err = coalesceError(err)
if code == 0 {
code = http.StatusInternalServerError
}
if errors.Is(r.Context().Err(), context.Canceled) {
code = StatusClientClosedRequest
}
// All errors land here, so it's a really good idea to do the logging here as well!
h.Reporter.ReportError(r, code, err, "An error occurred while handling a request")
w.Header().Set("Content-Type", h.contentType)
w.WriteHeader(code)
fmt.Fprintf(w, "%s", err)
}