diff options
Diffstat (limited to 'spartan/client.go')
-rw-r--r-- | spartan/client.go | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/spartan/client.go b/spartan/client.go new file mode 100644 index 0000000..154b18a --- /dev/null +++ b/spartan/client.go @@ -0,0 +1,70 @@ +package spartan + +import ( + "bytes" + "errors" + "io" + "net" + "strconv" + + "tildegit.org/tjp/gus" +) + +// Client is used for sending spartan requests and receiving responses. +// +// It carries no state and is reusable simultaneously by multiple goroutines. +// +// The zero value is immediately usabble. +type Client struct{} + +// RoundTrip sends a single spartan request and returns its response. +func (c Client) RoundTrip(request *gus.Request, body io.Reader) (*gus.Response, error) { + if request.Scheme != "spartan" && request.Scheme != "" { + return nil, errors.New("non-spartan protocols not supported") + } + + host, port, _ := net.SplitHostPort(request.Host) + if port == "" { + host = request.Host + port = "300" + } + addr := net.JoinHostPort(host, port) + + conn, err := net.Dial("tcp", addr) + if err != nil { + return nil, err + } + defer conn.Close() + + request.RemoteAddr = conn.RemoteAddr() + + var bodyBytes []byte = nil + if body != nil { + bodyBytes, err = io.ReadAll(body) + if err != nil { + return nil, err + } + } + + requestLine := host + " " + request.EscapedPath() + " " + strconv.Itoa(len(bodyBytes)) + "\r\n" + + if _, err := conn.Write([]byte(requestLine)); err != nil { + return nil, err + } + if _, err := conn.Write(bodyBytes); err != nil { + return nil, err + } + + response, err := ParseResponse(conn) + if err != nil { + return nil, err + } + + bodybuf, err := io.ReadAll(response.Body) + if err != nil { + return nil, err + } + response.Body = bytes.NewBuffer(bodybuf) + + return response, nil +} |