From ebe32689d4b2e058bad84ca18e1a02ff5fc61a8c Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Thu, 23 Oct 2014 16:01:40 -0700 Subject: [PATCH 1/3] client: s/v2Prefix/DefaultV2KeysPrefix/ --- client/http.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/client/http.go b/client/http.go index b19d1c67c..cad0ad682 100644 --- a/client/http.go +++ b/client/http.go @@ -31,8 +31,8 @@ import ( ) var ( - v2Prefix = "/v2/keys" - ErrTimeout = context.DeadlineExceeded + DefaultV2KeysPrefix = "/v2/keys" + ErrTimeout = context.DeadlineExceeded ) // transport mimics http.Transport to provide an interface which can be @@ -65,7 +65,7 @@ func NewHTTPClient(tr *http.Transport, ep string, timeout time.Duration) (*httpC } func (c *httpClient) SetPrefix(p string) { - v2Prefix = p + DefaultV2KeysPrefix = p } func (c *httpClient) Create(key, val string, ttl time.Duration) (*Response, error) { @@ -193,7 +193,7 @@ func (hw *httpWatcher) Next() (*Response, error) { } func v2URL(ep url.URL, key string) *url.URL { - ep.Path = path.Join(ep.Path, v2Prefix, key) + ep.Path = path.Join(ep.Path, DefaultV2KeysPrefix, key) return &ep } From a85a47c8f9536acc639ebed6d0645ea71b34d3de Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Thu, 23 Oct 2014 16:02:29 -0700 Subject: [PATCH 2/3] client: s/v2URL/v2KeysURL/ --- client/http.go | 8 ++++---- client/http_test.go | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/client/http.go b/client/http.go index cad0ad682..95947fbfe 100644 --- a/client/http.go +++ b/client/http.go @@ -192,7 +192,7 @@ func (hw *httpWatcher) Next() (*Response, error) { return resp, nil } -func v2URL(ep url.URL, key string) *url.URL { +func v2KeysURL(ep url.URL, key string) *url.URL { ep.Path = path.Join(ep.Path, DefaultV2KeysPrefix, key) return &ep } @@ -207,7 +207,7 @@ type getAction struct { } func (g *getAction) httpRequest(ep url.URL) *http.Request { - u := v2URL(ep, g.Key) + u := v2KeysURL(ep, g.Key) params := u.Query() params.Set("recursive", strconv.FormatBool(g.Recursive)) @@ -224,7 +224,7 @@ type waitAction struct { } func (w *waitAction) httpRequest(ep url.URL) *http.Request { - u := v2URL(ep, w.Key) + u := v2KeysURL(ep, w.Key) params := u.Query() params.Set("wait", "true") @@ -243,7 +243,7 @@ type createAction struct { } func (c *createAction) httpRequest(ep url.URL) *http.Request { - u := v2URL(ep, c.Key) + u := v2KeysURL(ep, c.Key) params := u.Query() params.Set("prevExist", "false") diff --git a/client/http_test.go b/client/http_test.go index c183c4e13..8b1777ad8 100644 --- a/client/http_test.go +++ b/client/http_test.go @@ -73,7 +73,7 @@ func TestV2URLHelper(t *testing.T) { } for i, tt := range tests { - got := v2URL(tt.endpoint, tt.key) + got := v2KeysURL(tt.endpoint, tt.key) if tt.want != *got { t.Errorf("#%d: want=%#v, got=%#v", i, tt.want, *got) } From 992e7c76e00089cb168a0d745bbcf10f1b8b7512 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Thu, 23 Oct 2014 16:14:33 -0700 Subject: [PATCH 3/3] client: copy v2KeysPrefix to httpClient It's poor form to muck with a global variable. Make a copy when the httpClient object is instantiated to make httpClient.SetPrefix safe. --- client/http.go | 29 ++++++++++++++++++++--------- client/http_test.go | 28 ++++++++++++++-------------- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/client/http.go b/client/http.go index 95947fbfe..4f94aba12 100644 --- a/client/http.go +++ b/client/http.go @@ -44,9 +44,10 @@ type transport interface { } type httpClient struct { - transport transport - endpoint url.URL - timeout time.Duration + transport transport + endpoint url.URL + timeout time.Duration + v2KeysPrefix string } func NewHTTPClient(tr *http.Transport, ep string, timeout time.Duration) (*httpClient, error) { @@ -56,16 +57,23 @@ func NewHTTPClient(tr *http.Transport, ep string, timeout time.Duration) (*httpC } c := &httpClient{ - transport: tr, - endpoint: *u, - timeout: timeout, + transport: tr, + endpoint: *u, + timeout: timeout, + v2KeysPrefix: DefaultV2KeysPrefix, } return c, nil } func (c *httpClient) SetPrefix(p string) { - DefaultV2KeysPrefix = p + c.v2KeysPrefix = p +} + +func (c *httpClient) Endpoint() url.URL { + ep := c.endpoint + ep.Path = path.Join(ep.Path, c.v2KeysPrefix) + return ep } func (c *httpClient) Create(key, val string, ttl time.Duration) (*Response, error) { @@ -112,7 +120,7 @@ type roundTripResponse struct { } func (c *httpClient) do(ctx context.Context, act httpAction) (*http.Response, []byte, error) { - req := act.httpRequest(c.endpoint) + req := act.httpRequest(c.Endpoint()) rtchan := make(chan roundTripResponse, 1) go func() { @@ -192,8 +200,11 @@ func (hw *httpWatcher) Next() (*Response, error) { return resp, nil } +// v2KeysURL forms a URL representing the location of a key. The provided +// endpoint must be the root of the etcd keys API. For example, a valid +// endpoint probably has the path "/v2/keys". func v2KeysURL(ep url.URL, key string) *url.URL { - ep.Path = path.Join(ep.Path, DefaultV2KeysPrefix, key) + ep.Path = path.Join(ep.Path, key) return &ep } diff --git a/client/http_test.go b/client/http_test.go index 8b1777ad8..816d1b32b 100644 --- a/client/http_test.go +++ b/client/http_test.go @@ -38,38 +38,38 @@ func TestV2URLHelper(t *testing.T) { }{ // key is empty, no problem { - endpoint: url.URL{Scheme: "http", Host: "example.com", Path: ""}, + endpoint: url.URL{Scheme: "http", Host: "example.com", Path: "/v2/keys"}, key: "", want: url.URL{Scheme: "http", Host: "example.com", Path: "/v2/keys"}, }, // key is joined to path { - endpoint: url.URL{Scheme: "http", Host: "example.com", Path: ""}, + endpoint: url.URL{Scheme: "http", Host: "example.com", Path: "/v2/keys"}, key: "/foo/bar", want: url.URL{Scheme: "http", Host: "example.com", Path: "/v2/keys/foo/bar"}, }, + // key is joined to path when path is empty + { + endpoint: url.URL{Scheme: "http", Host: "example.com", Path: ""}, + key: "/foo/bar", + want: url.URL{Scheme: "http", Host: "example.com", Path: "/foo/bar"}, + }, + // Host field carries through with port { - endpoint: url.URL{Scheme: "http", Host: "example.com:8080", Path: ""}, + endpoint: url.URL{Scheme: "http", Host: "example.com:8080", Path: "/v2/keys"}, key: "", want: url.URL{Scheme: "http", Host: "example.com:8080", Path: "/v2/keys"}, }, // Scheme carries through { - endpoint: url.URL{Scheme: "https", Host: "example.com", Path: ""}, + endpoint: url.URL{Scheme: "https", Host: "example.com", Path: "/v2/keys"}, key: "", want: url.URL{Scheme: "https", Host: "example.com", Path: "/v2/keys"}, }, - - // Path on endpoint is not ignored - { - endpoint: url.URL{Scheme: "https", Host: "example.com", Path: "/prefix"}, - key: "/foo", - want: url.URL{Scheme: "https", Host: "example.com", Path: "/prefix/v2/keys/foo"}, - }, } for i, tt := range tests { @@ -81,7 +81,7 @@ func TestV2URLHelper(t *testing.T) { } func TestGetAction(t *testing.T) { - ep := url.URL{Scheme: "http", Host: "example.com"} + ep := url.URL{Scheme: "http", Host: "example.com/v2/keys"} wantURL := &url.URL{ Scheme: "http", Host: "example.com", @@ -121,7 +121,7 @@ func TestGetAction(t *testing.T) { } func TestWaitAction(t *testing.T) { - ep := url.URL{Scheme: "http", Host: "example.com"} + ep := url.URL{Scheme: "http", Host: "example.com/v2/keys"} wantURL := &url.URL{ Scheme: "http", Host: "example.com", @@ -170,7 +170,7 @@ func TestWaitAction(t *testing.T) { } func TestCreateAction(t *testing.T) { - ep := url.URL{Scheme: "http", Host: "example.com"} + ep := url.URL{Scheme: "http", Host: "example.com/v2/keys"} wantURL := &url.URL{ Scheme: "http", Host: "example.com",