boihttp/client.go
Nadeen Udantha 4a3d59dea9 boi
2022-06-24 09:35:10 +05:30

101 lines
2.1 KiB
Go

// Copyright (c) 2022 Nadeen Udantha <me@nadeen.lk>. All rights reserved.
package boihttp
import (
"bufio"
"context"
"io"
"net"
url2 "net/url"
)
func DoConn(c *bufio.ReadWriter, method string, url string, hdrs Headers, reqbody io.Reader) (res *Message, resbody io.Reader, err error) {
resbody = EmptyBody
if reqbody == nil {
panic("wtf?")
}
u, err := url2.Parse(url)
if err != nil {
return
}
if hdrs == nil {
hdrs = make(Headers)
}
req := &Message{
Method: method,
Path: u.RequestURI(),
Version: VersionHTTP1_1,
Headers: hdrs,
}
req.Set("Host", u.Host)
req.Set("User-Agent", "boihttp-go/1.0")
err = req.WriteRequest(c.Writer)
if err != nil {
return
}
err = c.Writer.Flush()
if err != nil {
return
}
_, err = c.Writer.ReadFrom(reqbody)
if err != nil {
return
}
res = new(Message)
err = res.ReadResponse(c.Reader)
if err != nil {
return
}
resbody = res.body(c.Reader)
return
}
func Do(method string, url string, hdrs Headers, reqbody io.Reader, dial DialFunc, ctx context.Context) (res *Message, resbody io.Reader, err error) {
u, err := url2.Parse(url)
if err != nil {
return
}
if u.Scheme != "http" {
panic("wtf?")
}
host, port := u.Hostname(), u.Port()
if port == "" {
port = "80"
}
if dial == nil {
var d net.Dialer
dial = d.DialContext
}
c, err := dial(ctx, "tcp", net.JoinHostPort(host, port))
if err != nil {
return
}
rw := bufio.NewReadWriter(bufio.NewReader(c), bufio.NewWriter(c))
res, resbody, err = DoConn(rw, method, url, hdrs, reqbody)
if resbody == EmptyBody || resbody.(*io.LimitedReader).N == 0 {
c.Close()
}
resbody = &closeOnEOF{r: reqbody, c: c}
return
}
type closeOnEOF struct {
r io.Reader
c net.Conn
}
func (x *closeOnEOF) Read(p []byte) (n int, err error) {
n, err = x.r.Read(p)
if err == io.EOF {
x.c.Close()
}
return
}
type DialFunc func(ctx context.Context, network, addr string) (net.Conn, error)
func Get(url string, hdrs Headers, ctx context.Context) (res *Message, resbody io.Reader, err error) {
return Do("GET", url, hdrs, EmptyBody, nil, ctx)
}