Browse Source

etcdhttp: make TTL= equivalent to unset, and TTL=0 expire

Jonathan Boulle 11 years ago
parent
commit
2da1010cf7
2 changed files with 28 additions and 22 deletions
  1. 18 12
      etcdserver/etcdhttp/http.go
  2. 10 10
      etcdserver/etcdhttp/http_test.go

+ 18 - 12
etcdserver/etcdhttp/http.go

@@ -165,7 +165,7 @@ func parseRequest(r *http.Request, id int64) (etcdserverpb.Request, error) {
 	}
 	p := r.URL.Path[len(keysPrefix):]
 
-	var pIdx, wIdx, ttl uint64
+	var pIdx, wIdx uint64
 	if pIdx, err = getUint64(r.Form, "prevIndex"); err != nil {
 		return emptyReq, etcdErr.NewRequestError(
 			etcdErr.EcodeIndexNaN,
@@ -178,15 +178,6 @@ func parseRequest(r *http.Request, id int64) (etcdserverpb.Request, error) {
 			`invalid value for "waitIndex"`,
 		)
 	}
-	// An empty TTL value is equivalent to it being unset entirely
-	if len(r.FormValue("ttl")) > 0 {
-		if ttl, err = getUint64(r.Form, "ttl"); err != nil {
-			return emptyReq, etcdErr.NewRequestError(
-				etcdErr.EcodeTTLNaN,
-				`invalid value for "ttl"`,
-			)
-		}
-	}
 
 	var rec, sort, wait, dir, stream bool
 	if rec, err = getBool(r.Form, "recursive"); err != nil {
@@ -236,6 +227,20 @@ func parseRequest(r *http.Request, id int64) (etcdserverpb.Request, error) {
 		)
 	}
 
+	// TTL is nullable, so leave it null if not specified
+	// or an empty string
+	var ttl *uint64
+	if len(r.FormValue("ttl")) > 0 {
+		i, err := getUint64(r.Form, "ttl")
+		if err != nil {
+			return emptyReq, etcdErr.NewRequestError(
+				etcdErr.EcodeTTLNaN,
+				`invalid value for "ttl"`,
+			)
+		}
+		ttl = &i
+	}
+
 	// prevExist is nullable, so leave it null if not specified
 	var pe *bool
 	if _, ok := r.Form["prevExist"]; ok {
@@ -269,10 +274,11 @@ func parseRequest(r *http.Request, id int64) (etcdserverpb.Request, error) {
 		rr.PrevExist = pe
 	}
 
+	// Null TTL is equivalent to unset Expiration
 	// TODO(jonboulle): use fake clock instead of time module
 	// https://github.com/coreos/etcd/issues/1021
-	if ttl > 0 {
-		expr := time.Duration(ttl) * time.Second
+	if ttl != nil {
+		expr := time.Duration(*ttl) * time.Second
 		rr.Expiration = time.Now().Add(expr).UnixNano()
 	}
 

+ 10 - 10
etcdserver/etcdhttp/http_test.go

@@ -293,16 +293,6 @@ func TestGoodParseRequest(t *testing.T) {
 				Path:   "/foo",
 			},
 		},
-		{
-			// zero TTL specified
-			mustNewRequest(t, "foo?ttl=0"),
-			etcdserverpb.Request{
-				Id:         1234,
-				Method:     "GET",
-				Path:       "/foo",
-				Expiration: 0,
-			},
-		},
 		{
 			// empty TTL specified
 			mustNewRequest(t, "foo?ttl="),
@@ -433,6 +423,16 @@ func TestGoodParseRequest(t *testing.T) {
 	if got.Expiration <= now {
 		t.Fatalf("expiration = %v, wanted > %v", got.Expiration, now)
 	}
+
+	// ensure TTL=0 results in an expiration time
+	req = mustNewForm(t, "foo", url.Values{"ttl": []string{"0"}})
+	got, err = parseRequest(req, 1234)
+	if err != nil {
+		t.Fatalf("err = %v, want nil", err)
+	}
+	if got.Expiration <= now {
+		t.Fatalf("expiration = %v, wanted > %v", got.Expiration, now)
+	}
 }
 
 // eventingWatcher immediately returns a simple event of the given action on its channel