diff options
Diffstat (limited to 'spartan/response.go')
-rw-r--r-- | spartan/response.go | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/spartan/response.go b/spartan/response.go new file mode 100644 index 0000000..edc1db6 --- /dev/null +++ b/spartan/response.go @@ -0,0 +1,96 @@ +package spartan + +import ( + "bytes" + "io" + "sync" + + "tildegit.org/tjp/gus" +) + +// The spartan response types. +const ( + StatusSuccess gus.Status = 2 + StatusRedirect gus.Status = 3 + StatusClientError gus.Status = 4 + StatusServerError gus.Status = 5 +) + +// Success builds a successful spartan response. +func Success(mediatype string, body io.Reader) *gus.Response { + return &gus.Response{ + Status: StatusSuccess, + Meta: mediatype, + Body: body, + } +} + +// Redirect builds a spartan redirect response. +func Redirect(url string) *gus.Response { + return &gus.Response{ + Status: StatusRedirect, + Meta: url, + } +} + +// ClientError builds a "client error" spartan response. +func ClientError(err error) *gus.Response { + return &gus.Response{ + Status: StatusClientError, + Meta: err.Error(), + } +} + +// ServerError builds a "server error" spartan response. +func ServerError(err error) *gus.Response { + return &gus.Response{ + Status: StatusServerError, + Meta: err.Error(), + } +} + +// NewResponseReader builds a reader for a response. +func NewResponseReader(response *gus.Response) gus.ResponseReader { + return &responseReader{ + Response: response, + once: &sync.Once{}, + } +} + +type responseReader struct { + *gus.Response + reader io.Reader + once *sync.Once +} + +func (rdr *responseReader) Read(b []byte) (int, error) { + rdr.ensureReader() + return rdr.reader.Read(b) +} + +func (rdr *responseReader) WriteTo(dst io.Writer) (int64, error) { + rdr.ensureReader() + return rdr.reader.(io.WriterTo).WriteTo(dst) +} + +func (rdr *responseReader) ensureReader() { + rdr.once.Do(func() { + hdr := bytes.NewBuffer(rdr.headerLine()) + if rdr.Body != nil { + rdr.reader = io.MultiReader(hdr, rdr.Body) + } else { + rdr.reader = hdr + } + }) +} + +func (rdr *responseReader) headerLine() []byte { + meta := rdr.Meta.(string) + buf := make([]byte, len(meta)+4) + buf[0] = byte(rdr.Status) + '0' + buf[1] = ' ' + copy(buf[2:], meta) + buf[len(buf)-2] = '\r' + buf[len(buf)-1] = '\n' + return buf +} |