response: Implement Write method

This commit is contained in:
Adnan Maolood 2021-02-18 00:07:43 -05:00
parent a3a995df35
commit aab3ac4dfe
2 changed files with 52 additions and 9 deletions

View File

@ -3,6 +3,7 @@ package gemini
import ( import (
"bufio" "bufio"
"crypto/tls" "crypto/tls"
"fmt"
"io" "io"
"strconv" "strconv"
) )
@ -135,6 +136,24 @@ func (b *readCloserBody) Read(p []byte) (n int, err error) {
return b.ReadCloser.Read(p) return b.ReadCloser.Read(p)
} }
// Write writes r to w in the Gemini response format, including the
// header and body.
//
// This method consults the Status, Meta, and Body fields of the response.
// The Response Body is closed after it is sent.
func (r *Response) Write(w io.Writer) error {
if _, err := fmt.Fprintf(w, "%02d %s\r\n", r.Status, r.Meta); err != nil {
return err
}
if r.Body != nil {
defer r.Body.Close()
if _, err := io.Copy(w, r.Body); err != nil {
return err
}
}
return nil
}
// A ResponseWriter interface is used by a Gemini handler to construct // A ResponseWriter interface is used by a Gemini handler to construct
// a Gemini response. // a Gemini response.
// //

View File

@ -6,13 +6,14 @@ import (
"testing" "testing"
) )
func TestReadResponse(t *testing.T) { func TestReadWriteResponse(t *testing.T) {
tests := []struct { tests := []struct {
Raw string Raw string
Status int Status int
Meta string Meta string
Body string Body string
Err error Err error
SkipWrite bool
}{ }{
{ {
Raw: "20 text/gemini\r\nHello, world!\nWelcome to my capsule.", Raw: "20 text/gemini\r\nHello, world!\nWelcome to my capsule.",
@ -34,6 +35,7 @@ func TestReadResponse(t *testing.T) {
Raw: "31 /redirect\r\nThis body is ignored.", Raw: "31 /redirect\r\nThis body is ignored.",
Status: 31, Status: 31,
Meta: "/redirect", Meta: "/redirect",
SkipWrite: true, // skip write test since result won't match Raw
}, },
{ {
Raw: "99 Unknown status code\r\n", Raw: "99 Unknown status code\r\n",
@ -100,4 +102,26 @@ func TestReadResponse(t *testing.T) {
t.Errorf("expected body = %#v, got %#v", test.Body, body) t.Errorf("expected body = %#v, got %#v", test.Body, body)
} }
} }
for _, test := range tests {
if test.Err != nil || test.SkipWrite {
continue
}
resp := &Response{
Status: test.Status,
Meta: test.Meta,
Body: io.NopCloser(strings.NewReader(test.Body)),
}
var b strings.Builder
if err := resp.Write(&b); err != nil {
t.Error(err)
continue
}
got := b.String()
if got != test.Raw {
t.Errorf("expected %#v, got %#v", test.Raw, got)
}
}
} }