diff --git a/client.go b/client.go index 5d7e4f5..2020e3d 100644 --- a/client.go +++ b/client.go @@ -4,7 +4,6 @@ import ( "context" "crypto/tls" "crypto/x509" - "io" "net" "net/url" "time" @@ -221,55 +220,3 @@ func punycodeHostname(hostname string) (string, error) { } return idna.Lookup.ToASCII(hostname) } - -type contextReader struct { - ctx context.Context - done <-chan struct{} - cancel func() - rc io.ReadCloser -} - -func (r *contextReader) Read(p []byte) (int, error) { - select { - case <-r.done: - r.rc.Close() - return 0, r.ctx.Err() - default: - } - n, err := r.rc.Read(p) - if err != nil { - r.cancel() - } - return n, err -} - -func (r *contextReader) Close() error { - r.cancel() - return r.rc.Close() -} - -type contextWriter struct { - ctx context.Context - done <-chan struct{} - cancel func() - wc io.WriteCloser -} - -func (w *contextWriter) Write(b []byte) (int, error) { - select { - case <-w.done: - w.wc.Close() - return 0, w.ctx.Err() - default: - } - n, err := w.wc.Write(b) - if err != nil { - w.cancel() - } - return n, err -} - -func (w *contextWriter) Close() error { - w.cancel() - return w.wc.Close() -} diff --git a/io.go b/io.go new file mode 100644 index 0000000..3b9e540 --- /dev/null +++ b/io.go @@ -0,0 +1,104 @@ +package gemini + +import ( + "bufio" + "context" + "io" +) + +type contextReader struct { + ctx context.Context + done <-chan struct{} + cancel func() + rc io.ReadCloser +} + +func (r *contextReader) Read(p []byte) (int, error) { + select { + case <-r.done: + r.rc.Close() + return 0, r.ctx.Err() + default: + } + n, err := r.rc.Read(p) + if err != nil { + r.cancel() + } + return n, err +} + +func (r *contextReader) Close() error { + r.cancel() + return r.rc.Close() +} + +type contextWriter struct { + ctx context.Context + done <-chan struct{} + cancel func() + wc io.WriteCloser +} + +func (w *contextWriter) Write(b []byte) (int, error) { + select { + case <-w.done: + w.wc.Close() + return 0, w.ctx.Err() + default: + } + n, err := w.wc.Write(b) + if err != nil { + w.cancel() + } + return n, err +} + +func (w *contextWriter) Close() error { + w.cancel() + return w.wc.Close() +} + +type nopCloser struct { + io.Writer +} + +func (nopCloser) Close() error { + return nil +} + +type nopReadCloser struct{} + +func (nopReadCloser) Read(p []byte) (int, error) { + return 0, io.EOF +} + +func (nopReadCloser) Close() error { + return nil +} + +type bufReadCloser struct { + br *bufio.Reader // used until empty + io.ReadCloser +} + +func newBufReadCloser(br *bufio.Reader, rc io.ReadCloser) io.ReadCloser { + body := &bufReadCloser{ReadCloser: rc} + if br.Buffered() != 0 { + body.br = br + } + return body +} + +func (b *bufReadCloser) Read(p []byte) (n int, err error) { + if b.br != nil { + if n := b.br.Buffered(); len(p) > n { + p = p[:n] + } + n, err = b.br.Read(p) + if b.br.Buffered() == 0 { + b.br = nil + } + return n, err + } + return b.ReadCloser.Read(p) +} diff --git a/response.go b/response.go index 8c7febc..abbc757 100644 --- a/response.go +++ b/response.go @@ -81,7 +81,7 @@ func ReadResponse(rc io.ReadCloser) (*Response, error) { } if resp.Status.Class() == StatusSuccess { - resp.body = newReadCloserBody(br, rc) + resp.body = newBufReadCloser(br, rc) } else { resp.body = nopReadCloser{} rc.Close() @@ -89,43 +89,6 @@ func ReadResponse(rc io.ReadCloser) (*Response, error) { return resp, nil } -type nopReadCloser struct{} - -func (nopReadCloser) Read(p []byte) (int, error) { - return 0, io.EOF -} - -func (nopReadCloser) Close() error { - return nil -} - -type readCloserBody struct { - br *bufio.Reader // used until empty - io.ReadCloser -} - -func newReadCloserBody(br *bufio.Reader, rc io.ReadCloser) io.ReadCloser { - body := &readCloserBody{ReadCloser: rc} - if br.Buffered() != 0 { - body.br = br - } - return body -} - -func (b *readCloserBody) Read(p []byte) (n int, err error) { - if b.br != nil { - if n := b.br.Buffered(); len(p) > n { - p = p[:n] - } - n, err = b.br.Read(p) - if b.br.Buffered() == 0 { - b.br = nil - } - return n, err - } - return b.ReadCloser.Read(p) -} - // Read reads data from the response body. // The response body is streamed on demand as Read is called. func (r *Response) Read(p []byte) (n int, err error) { diff --git a/response_test.go b/response_test.go index 68e0884..2920d64 100644 --- a/response_test.go +++ b/response_test.go @@ -123,15 +123,3 @@ func TestReadWriteResponse(t *testing.T) { } } } - -type nopCloser struct { - io.Writer -} - -func (w nopCloser) Write(b []byte) (int, error) { - return w.Writer.Write(b) -} - -func (nopCloser) Close() error { - return nil -}