package spartan import ( "bytes" "errors" "io" "net" "strconv" sr "tildegit.org/tjp/sliderule" ) // 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 *sr.Request, body io.Reader) (*sr.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 }