From f8bfa12215fdd6a23298c0288076a617c3e8df9d Mon Sep 17 00:00:00 2001 From: Aliaksandr Valialkin Date: Fri, 13 Nov 2015 16:13:22 +0200 Subject: [PATCH] Added Post() method to client --- client.go | 105 ++++++++++++++++++++++++++++--------------------- client_test.go | 68 ++++++++++++++++++++++++++++++-- 2 files changed, 125 insertions(+), 48 deletions(-) diff --git a/client.go b/client.go index e93821a..dcd44af 100644 --- a/client.go +++ b/client.go @@ -30,13 +30,17 @@ func Do(req *Request, resp *Response) error { } // Get fetches url contents into dst. +// +// Use Do for request customization. func Get(dst []byte, url string) (statusCode int, body []byte, err error) { return defaultClient.Get(dst, url) } -// GetBytes fetches url contents into dst. -func GetBytes(dst, url []byte) (statusCode int, body []byte, err error) { - return defaultClient.GetBytes(dst, url) +// Post sends POST request to the given url with the given POST arguments. +// +// Use Do for request customization. +func Post(dst []byte, url string, postArgs *Args) (statusCode int, body []byte, err error) { + return defaultClient.Post(dst, url, postArgs) } var defaultClient Client @@ -75,37 +79,17 @@ type Client struct { } // Get fetches url contents into dst. +// +// Use Do for request customization. func (c *Client) Get(dst []byte, url string) (statusCode int, body []byte, err error) { - v := urlBufPool.Get() - if v == nil { - v = make([]byte, 1024) - } - buf := v.([]byte) - buf = AppendBytesStr(buf[:0], url) - statusCode, body, err = c.GetBytes(dst, buf) - urlBufPool.Put(v) - return statusCode, body, err + return clientGetURL(dst, url, c) } -// GetBytes fetches url contents into dst. -func (c *Client) GetBytes(dst, url []byte) (statusCode int, body []byte, err error) { - req := acquireRequest() - req.Header.RequestURI = url - req.ParseURI() - - resp := acquireResponse() - resp.Body = dst - if err = c.Do(req, resp); err != nil { - return 0, nil, err - } - statusCode = resp.Header.StatusCode - body = resp.Body - resp.Body = nil - releaseResponse(resp) - - req.Header.RequestURI = nil - releaseRequest(req) - return statusCode, body, err +// Post sends POST request to the given url with the given POST arguments. +// +// Use Do for request customization. +func (c *Client) Post(dst []byte, url string, postArgs *Args) (statusCode int, body []byte, err error) { + return clientPostURL(dst, url, postArgs, c) } // Do performs the given http request and fills the given http response. @@ -277,25 +261,55 @@ func (c *HostClient) LastUseTime() time.Time { } // Get fetches url contents into dst. +// +// Use Do for request customization. func (c *HostClient) Get(dst []byte, url string) (statusCode int, body []byte, err error) { + return clientGetURL(dst, url, c) +} + +// Post sends POST request to the given url with the given POST arguments. +// +// Use Do for request customization. +func (c *HostClient) Post(dst []byte, url string, postArgs *Args) (statusCode int, body []byte, err error) { + return clientPostURL(dst, url, postArgs, c) +} + +type clientDoer interface { + Do(req *Request, resp *Response) error +} + +func clientGetURL(dst []byte, url string, c clientDoer) (statusCode int, body []byte, err error) { + req := acquireRequest() + + statusCode, body, err = doRequest(req, dst, url, c) + + releaseRequest(req) + return statusCode, body, err +} + +func clientPostURL(dst []byte, url string, postArgs *Args, c clientDoer) (statusCode int, body []byte, err error) { + req := acquireRequest() + req.Header.Method = strPost + req.Header.contentType = strPostArgsContentType + req.Body = postArgs.AppendBytes(req.Body[:0]) + + statusCode, body, err = doRequest(req, dst, url, c) + + req.Header.Method = nil + req.Header.contentType = nil + // there is no need in req.Body = nil, since Body belongs to req. + releaseRequest(req) + return statusCode, body, err +} + +func doRequest(req *Request, dst []byte, url string, c clientDoer) (statusCode int, body []byte, err error) { v := urlBufPool.Get() if v == nil { v = make([]byte, 1024) } buf := v.([]byte) buf = AppendBytesStr(buf[:0], url) - statusCode, body, err = c.GetBytes(dst, buf) - urlBufPool.Put(v) - return statusCode, body, err -} - -var urlBufPool sync.Pool - -// GetBytes fetches url contents into dst. -func (c *HostClient) GetBytes(dst, url []byte) (statusCode int, body []byte, err error) { - req := acquireRequest() - req.Header.RequestURI = url - req.ParseURI() + req.Header.RequestURI = buf resp := acquireResponse() resp.Body = dst @@ -308,11 +322,14 @@ func (c *HostClient) GetBytes(dst, url []byte) (statusCode int, body []byte, err releaseResponse(resp) req.Header.RequestURI = nil - releaseRequest(req) + urlBufPool.Put(v) + return statusCode, body, err } var ( + urlBufPool sync.Pool + requestPool sync.Pool responsePool sync.Pool ) diff --git a/client_test.go b/client_test.go index b37988d..0b95c5e 100644 --- a/client_test.go +++ b/client_test.go @@ -30,6 +30,7 @@ func TestClientHTTPSConcurrent(t *testing.T) { go func() { defer wg.Done() testClientGet(t, &defaultClient, addr, 3000) + testClientPost(t, &defaultClient, addr, 1000) }() } wg.Wait() @@ -51,6 +52,7 @@ func TestClientManyServers(t *testing.T) { go func() { defer wg.Done() testClientGet(t, &defaultClient, addr, 3000) + testClientPost(t, &defaultClient, addr, 1000) }() } wg.Wait() @@ -65,7 +67,16 @@ func TestClientGet(t *testing.T) { testClientGet(t, &defaultClient, addr, 100) } -func TestClientGetConcurrent(t *testing.T) { +func TestClientPost(t *testing.T) { + addr := "127.0.0.1:56798" + s := startEchoServer(t, "tcp", addr) + defer s.Stop() + + addr = "http://" + addr + testClientPost(t, &defaultClient, addr, 100) +} + +func TestClientConcurrent(t *testing.T) { addr := "127.0.0.1:56780" s := startEchoServer(t, "tcp", addr) defer s.Stop() @@ -77,6 +88,7 @@ func TestClientGetConcurrent(t *testing.T) { go func() { defer wg.Done() testClientGet(t, &defaultClient, addr, 3000) + testClientPost(t, &defaultClient, addr, 1000) }() } wg.Wait() @@ -91,8 +103,17 @@ func TestHostClientGet(t *testing.T) { testHostClientGet(t, c, 100) } -func TestHostClientGetConcurrent(t *testing.T) { - addr := "./TestHostClientGetConcurrent.unix" +func TestHostClientPost(t *testing.T) { + addr := "./TestHostClientPost.unix" + s := startEchoServer(t, "unix", addr) + defer s.Stop() + c := createEchoClient(t, "unix", addr) + + testHostClientPost(t, c, 100) +} + +func TestHostClientConcurrent(t *testing.T) { + addr := "./TestHostClientConcurrent.unix" s := startEchoServer(t, "unix", addr) defer s.Stop() c := createEchoClient(t, "unix", addr) @@ -103,6 +124,7 @@ func TestHostClientGetConcurrent(t *testing.T) { go func() { defer wg.Done() testHostClientGet(t, c, 3000) + testHostClientPost(t, c, 1000) }() } wg.Wait() @@ -130,10 +152,41 @@ func testClientGet(t *testing.T, c clientGetter, addr string, n int) { } } +func testClientPost(t *testing.T, c clientPoster, addr string, n int) { + var buf []byte + var args Args + for i := 0; i < n; i++ { + uri := fmt.Sprintf("%s/foo/%d?bar=baz", addr, i) + args.Set("xx", fmt.Sprintf("yy%d", i)) + args.Set("zzz", fmt.Sprintf("qwe_%d", i)) + argsS := args.String() + statusCode, body, err := c.Post(buf, uri, &args) + buf = body + if err != nil { + t.Fatalf("unexpected error when doing http request: %s", err) + } + if statusCode != StatusOK { + t.Fatalf("unexpected status code: %d. Expecting %d", statusCode, StatusOK) + } + s := string(body) + if s != argsS { + t.Fatalf("unexpected response %q. Expecting %q", s, argsS) + } + } +} + func testHostClientGet(t *testing.T, c *HostClient, n int) { testClientGet(t, c, "http://google.com", n) } +func testHostClientPost(t *testing.T, c *HostClient, n int) { + testClientPost(t, c, "http://post-host.com", n) +} + +type clientPoster interface { + Post(dst []byte, uri string, postArgs *Args) (int, []byte, error) +} + type clientGetter interface { Get(dst []byte, uri string) (int, []byte, error) } @@ -198,7 +251,14 @@ func startEchoServerExt(t *testing.T, network, addr string, isTLS bool) *testEch s := &Server{ Handler: func(ctx *RequestCtx) { ctx.Request.ParseURI() - ctx.Success("text/plain", ctx.Request.URI.URI) + if ctx.IsGet() { + ctx.Success("text/plain", ctx.Request.URI.URI) + } else if ctx.IsPost() { + if err := ctx.Request.ParsePostArgs(); err != nil { + t.Fatalf("cannot parse post arguments: %s", err) + } + ctx.SetResponseBody(ctx.Request.Body) + } }, } ch := make(chan struct{})