Browse Source

client: return ErrNoEndpoint when none available

In certain cases (for example, if a cluster peer is accessible but it
has no members listed), the httpClusterClient could have an empty set of
endpoints as a result of the Sync. This means that its Do function could
potentially return a nil response and nil error, with catastrophic
consequences for callers.

To be safe (particularly about this latter behaviour), this change
errors in both Sync and Do if no endpoints are available.
Jonathan Boulle 11 years ago
parent
commit
45b7c9a4ac
2 changed files with 15 additions and 0 deletions
  1. 7 0
      client/http.go
  2. 8 0
      client/http_test.go

+ 7 - 0
client/http.go

@@ -30,6 +30,7 @@ import (
 var (
 var (
 	ErrTimeout          = context.DeadlineExceeded
 	ErrTimeout          = context.DeadlineExceeded
 	ErrCanceled         = context.Canceled
 	ErrCanceled         = context.Canceled
+	ErrNoEndpoints      = errors.New("no endpoints available")
 	ErrTooManyRedirects = errors.New("too many redirects")
 	ErrTooManyRedirects = errors.New("too many redirects")
 
 
 	DefaultRequestTimeout = 5 * time.Second
 	DefaultRequestTimeout = 5 * time.Second
@@ -91,6 +92,9 @@ type httpClusterClient struct {
 }
 }
 
 
 func (c *httpClusterClient) Do(ctx context.Context, act HTTPAction) (resp *http.Response, body []byte, err error) {
 func (c *httpClusterClient) Do(ctx context.Context, act HTTPAction) (resp *http.Response, body []byte, err error) {
+	if len(c.endpoints) == 0 {
+		return nil, nil, ErrNoEndpoints
+	}
 	for _, hc := range c.endpoints {
 	for _, hc := range c.endpoints {
 		resp, body, err = hc.Do(ctx, act)
 		resp, body, err = hc.Do(ctx, act)
 		if err != nil {
 		if err != nil {
@@ -118,6 +122,9 @@ func (c *httpClusterClient) Sync(ctx context.Context) error {
 	for _, m := range ms {
 	for _, m := range ms {
 		eps = append(eps, m.ClientURLs...)
 		eps = append(eps, m.ClientURLs...)
 	}
 	}
+	if len(eps) == 0 {
+		return ErrNoEndpoints
+	}
 	nc, err := newHTTPClusterClient(c.transport, eps)
 	nc, err := newHTTPClusterClient(c.transport, eps)
 	if err != nil {
 	if err != nil {
 		return err
 		return err

+ 8 - 0
client/http_test.go

@@ -234,6 +234,14 @@ func TestHTTPClusterClientDo(t *testing.T) {
 			wantErr: ErrCanceled,
 			wantErr: ErrCanceled,
 		},
 		},
 
 
+		// return err if there are no endpoints
+		{
+			client: &httpClusterClient{
+				endpoints: []HTTPClient{},
+			},
+			wantErr: ErrNoEndpoints,
+		},
+
 		// return err if all endpoints return arbitrary errors
 		// return err if all endpoints return arbitrary errors
 		{
 		{
 			client: &httpClusterClient{
 			client: &httpClusterClient{