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 }