136 lines
3.1 KiB
Go
136 lines
3.1 KiB
Go
package requests
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"golang.org/x/net/html"
|
|
)
|
|
|
|
// ResponseHandler is used to validate or handle the response to a request.
|
|
type ResponseHandler = func(*http.Response) error
|
|
|
|
// ChainHandlers allows for the composing of validators or response handlers.
|
|
func ChainHandlers(handlers ...ResponseHandler) ResponseHandler {
|
|
return func(r *http.Response) error {
|
|
for _, h := range handlers {
|
|
if h == nil {
|
|
continue
|
|
}
|
|
if err := h(r); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func consumeBody(res *http.Response) (err error) {
|
|
const maxDiscardSize = 640 * 1 << 10
|
|
if _, err = io.CopyN(io.Discard, res.Body, maxDiscardSize); err == io.EOF {
|
|
err = nil
|
|
}
|
|
return err
|
|
}
|
|
|
|
// ToDeserializer decodes a response into v using a [Deserializer].
|
|
func ToDeserializer(d Deserializer, v any) ResponseHandler {
|
|
return func(res *http.Response) error {
|
|
data, err := io.ReadAll(res.Body)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err = d(data, v); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// ToJSON decodes a response as a JSON object.
|
|
//
|
|
// It uses [JSONDeserializer] to unmarshal the object.
|
|
func ToJSON(v any) ResponseHandler {
|
|
return ToDeserializer(JSONDeserializer, v)
|
|
}
|
|
|
|
// ToString writes the response body to the provided string pointer.
|
|
func ToString(sp *string) ResponseHandler {
|
|
return func(res *http.Response) error {
|
|
var buf strings.Builder
|
|
_, err := io.Copy(&buf, res.Body)
|
|
if err == nil {
|
|
*sp = buf.String()
|
|
}
|
|
return err
|
|
}
|
|
}
|
|
|
|
// ToBytesBuffer writes the response body to the provided bytes.Buffer.
|
|
func ToBytesBuffer(buf *bytes.Buffer) ResponseHandler {
|
|
return func(res *http.Response) error {
|
|
_, err := io.Copy(buf, res.Body)
|
|
return err
|
|
}
|
|
}
|
|
|
|
// ToBufioReader takes a callback which wraps the response body in a bufio.Reader.
|
|
func ToBufioReader(f func(r *bufio.Reader) error) ResponseHandler {
|
|
return func(res *http.Response) error {
|
|
return f(bufio.NewReader(res.Body))
|
|
}
|
|
}
|
|
|
|
// ToBufioScanner takes a callback which wraps the response body in a bufio.Scanner.
|
|
func ToBufioScanner(f func(r *bufio.Scanner) error) ResponseHandler {
|
|
return func(res *http.Response) error {
|
|
return f(bufio.NewScanner(res.Body))
|
|
}
|
|
}
|
|
|
|
// ToHTML parses the page with x/net/html.Parse.
|
|
func ToHTML(n *html.Node) ResponseHandler {
|
|
return ToBufioReader(func(r *bufio.Reader) error {
|
|
n2, err := html.Parse(r)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*n = *n2
|
|
return nil
|
|
})
|
|
}
|
|
|
|
// ToWriter copies the response body to w.
|
|
func ToWriter(w io.Writer) ResponseHandler {
|
|
return ToBufioReader(func(r *bufio.Reader) error {
|
|
_, err := io.Copy(w, r)
|
|
|
|
return err
|
|
})
|
|
}
|
|
|
|
// ToFile writes the response body at the provided file path.
|
|
// The file and its parent directories are created automatically.
|
|
func ToFile(name string) ResponseHandler {
|
|
return func(res *http.Response) error {
|
|
_ = os.MkdirAll(filepath.Dir(name), 0777)
|
|
|
|
f, err := os.Create(name)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
|
|
_, err = io.Copy(f, res.Body)
|
|
return err
|
|
}
|
|
}
|
|
|
|
// ToHeaders is an alias for backwards compatibility.
|
|
var ToHeaders = CopyHeaders
|