// Copyright (c) 2022 Nadeen Udantha . 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) }