aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRasmus Dahlberg <rasmus.dahlberg@kau.se>2022-04-26 16:52:52 +0200
committerRasmus Dahlberg <rasmus.dahlberg@kau.se>2022-04-26 19:39:55 +0200
commite4599334cf434f65cd49f92b604546acd39d4c39 (patch)
treed3fdde1f246ba16f4d92885ce7c5211906744469
parent2dcd7bca2f3e69fb6f1770ec0bf740d8956978ca (diff)
add url parsing for get-requests with input
Pair-programmed with ln5.
-rw-r--r--pkg/requests/requests.go86
-rw-r--r--pkg/requests/requests_test.go157
-rw-r--r--pkg/types/endpoint.go6
3 files changed, 138 insertions, 111 deletions
diff --git a/pkg/requests/requests.go b/pkg/requests/requests.go
index 4321b2b..bb63de0 100644
--- a/pkg/requests/requests.go
+++ b/pkg/requests/requests.go
@@ -1,9 +1,13 @@
package requests
import (
+ "fmt"
"io"
+ "strconv"
+ "strings"
"git.sigsum.org/sigsum-go/pkg/ascii"
+ "git.sigsum.org/sigsum-go/pkg/hex"
"git.sigsum.org/sigsum-go/pkg/types"
)
@@ -16,18 +20,18 @@ type Leaf struct {
}
type Leaves struct {
- StartSize uint64 `ascii:"start_size"`
- EndSize uint64 `ascii:"end_size"`
+ StartSize uint64
+ EndSize uint64
}
type InclusionProof struct {
- LeafHash types.Hash `ascii:"leaf_hash"`
- TreeSize uint64 `ascii:"tree_size"`
+ TreeSize uint64
+ LeafHash types.Hash
}
type ConsistencyProof struct {
- NewSize uint64 `ascii:"new_size"`
- OldSize uint64 `ascii:"old_size"`
+ OldSize uint64
+ NewSize uint64
}
type Cosignature struct {
@@ -39,16 +43,19 @@ func (req *Leaf) ToASCII(w io.Writer) error {
return ascii.StdEncoding.Serialize(w, req)
}
-func (req *Leaves) ToASCII(w io.Writer) error {
- return ascii.StdEncoding.Serialize(w, req)
+// ToURL encodes request parameters at the end of a slash-terminated URL
+func (req *Leaves) ToURL(url string) string {
+ return url + fmt.Sprintf("%d/%d", req.StartSize, req.EndSize)
}
-func (req *InclusionProof) ToASCII(w io.Writer) error {
- return ascii.StdEncoding.Serialize(w, req)
+// ToURL encodes request parameters at the end of a slash-terminated URL
+func (req *InclusionProof) ToURL(url string) string {
+ return url + fmt.Sprintf("%d/%s", req.TreeSize, hex.Serialize(req.LeafHash[:]))
}
-func (req *ConsistencyProof) ToASCII(w io.Writer) error {
- return ascii.StdEncoding.Serialize(w, req)
+// ToURL encodes request parameters at the end of a slash-terminated URL
+func (req *ConsistencyProof) ToURL(url string) string {
+ return url + fmt.Sprintf("%d/%d", req.OldSize, req.NewSize)
}
func (req *Cosignature) ToASCII(w io.Writer) error {
@@ -59,16 +66,59 @@ func (req *Leaf) FromASCII(r io.Reader) error {
return ascii.StdEncoding.Deserialize(r, req)
}
-func (req *Leaves) FromASCII(r io.Reader) error {
- return ascii.StdEncoding.Deserialize(r, req)
+// FromURL parses request parameters from a URL that is not slash-terminated
+func (req *Leaves) FromURL(url string) (err error) {
+ split := strings.Split(url, "/")
+ if len(split) < 2 {
+ return fmt.Errorf("not enough input")
+ }
+ startSize := split[len(split)-2]
+ if req.StartSize, err = strconv.ParseUint(startSize, 10, 64); err != nil {
+ return err
+ }
+ endSize := split[len(split)-1]
+ if req.EndSize, err = strconv.ParseUint(endSize, 10, 64); err != nil {
+ return err
+ }
+ return nil
}
-func (req *InclusionProof) FromASCII(r io.Reader) error {
- return ascii.StdEncoding.Deserialize(r, req)
+// FromURL parses request parameters from a URL that is not slash-terminated
+func (req *InclusionProof) FromURL(url string) (err error) {
+ split := strings.Split(url, "/")
+ if len(split) < 2 {
+ return fmt.Errorf("not enough input")
+ }
+ treeSize := split[len(split)-2]
+ if req.TreeSize, err = strconv.ParseUint(treeSize, 10, 64); err != nil {
+ return err
+ }
+ b, err := hex.Deserialize(split[len(split)-1])
+ if err != nil {
+ return err
+ }
+ if n := len(b); n != types.HashSize {
+ return fmt.Errorf("invalid hash size %d", n)
+ }
+ copy(req.LeafHash[:], b)
+ return nil
}
-func (req *ConsistencyProof) FromASCII(r io.Reader) error {
- return ascii.StdEncoding.Deserialize(r, req)
+// FromURL parses request parameters from a URL that is not slash-terminated
+func (req *ConsistencyProof) FromURL(url string) (err error) {
+ split := strings.Split(url, "/")
+ if len(split) < 2 {
+ return fmt.Errorf("not enough input")
+ }
+ oldSize := split[len(split)-2]
+ if req.OldSize, err = strconv.ParseUint(oldSize, 10, 64); err != nil {
+ return err
+ }
+ newSize := split[len(split)-1]
+ if req.NewSize, err = strconv.ParseUint(newSize, 10, 64); err != nil {
+ return err
+ }
+ return nil
}
func (req *Cosignature) FromASCII(r io.Reader) error {
diff --git a/pkg/requests/requests_test.go b/pkg/requests/requests_test.go
index 691507a..ccbd8e9 100644
--- a/pkg/requests/requests_test.go
+++ b/pkg/requests/requests_test.go
@@ -21,36 +21,30 @@ func TestLeafToASCII(t *testing.T) {
}
}
-func TestLeavesToASCII(t *testing.T) {
- desc := "valid"
- buf := bytes.NewBuffer(nil)
- if err := validLeaves(t).ToASCII(buf); err != nil {
- t.Fatalf("got error true but wanted false in test %q: %v", desc, err)
- }
- if got, want := string(buf.Bytes()), validLeavesASCII(t); got != want {
- t.Errorf("got leaves request\n\t%v\nbut wanted\n\t%v\nin test %q\n", got, want, desc)
+func TestLeavesToURL(t *testing.T) {
+ url := types.EndpointGetLeaves.Path("https://log.sigsum.com/sigsum/v0")
+ req := Leaves{1, 2}
+ want := url + "1/2"
+ if got := req.ToURL(url); got != want {
+ t.Errorf("got url %s but wanted %s", got, want)
}
}
-func TestInclusionProofToASCII(t *testing.T) {
- desc := "valid"
- buf := bytes.NewBuffer(nil)
- if err := validInclusionProof(t).ToASCII(buf); err != nil {
- t.Fatalf("got error true but wanted false in test %q: %v", desc, err)
- }
- if got, want := string(buf.Bytes()), validInclusionProofASCII(t); got != want {
- t.Errorf("got inclusion proof request\n\t%v\nbut wanted\n\t%v\nin test %q\n", got, want, desc)
+func TestInclusionProofToURL(t *testing.T) {
+ url := types.EndpointGetInclusionProof.Path("https://log.sigsum.com/sigsum/v0")
+ req := InclusionProof{1, types.Hash{}}
+ want := url + "1/0000000000000000000000000000000000000000000000000000000000000000"
+ if got := req.ToURL(url); got != want {
+ t.Errorf("got url %s but wanted %s", got, want)
}
}
-func TestConsistencyProofToASCII(t *testing.T) {
- desc := "valid"
- buf := bytes.NewBuffer(nil)
- if err := validConsistencyProof(t).ToASCII(buf); err != nil {
- t.Fatalf("got error true but wanted false in test %q: %v", desc, err)
- }
- if got, want := string(buf.Bytes()), validConsistencyProofASCII(t); got != want {
- t.Errorf("got consistency proof request\n\t%v\nbut wanted\n\t%v\nin test %q\n", got, want, desc)
+func TestConsistencyProofToURL(t *testing.T) {
+ url := types.EndpointGetConsistencyProof.Path("https://log.sigsum.com/sigsum/v0")
+ req := ConsistencyProof{1, 2}
+ want := url + "1/2"
+ if got := req.ToURL(url); got != want {
+ t.Errorf("got url %s but wanted %s", got, want)
}
}
@@ -100,107 +94,90 @@ func TestLeafFromASCII(t *testing.T) {
}
}
-func TestLeavesFromASCII(t *testing.T) {
+func TestLeavesFromURL(t *testing.T) {
for _, table := range []struct {
- desc string
- serialized io.Reader
- wantErr bool
- want *Leaves
+ desc string
+ input string
+ want Leaves
+ wantErr bool
}{
- {
- desc: "invalid: not a leaves request (unexpected key-value pair)",
- serialized: bytes.NewBuffer(
- append([]byte(validLeavesASCII(t)),
- []byte("key=4")...),
- ),
- wantErr: true,
- },
- {
- desc: "valid",
- serialized: bytes.NewBuffer([]byte(validLeavesASCII(t))),
- want: validLeaves(t),
- },
+ {"invalid: not enough parameters", "some-url", Leaves{}, true},
+ {"invalid: start size has a leading sign", "some-url/+1/2", Leaves{}, true},
+ {"invalid: start size is empty", "some-url//2", Leaves{}, true},
+ {"invalid: end size is empty", "some-url/1/", Leaves{}, true},
+ {"valid", "some-url/1/2", Leaves{1, 2}, false},
} {
var req Leaves
- err := req.FromASCII(table.serialized)
+ err := req.FromURL(table.input)
if got, want := err != nil, table.wantErr; got != want {
- t.Errorf("got error %v but wanted %v in test %q: %v", got, want, table.desc, err)
+ t.Errorf("%s: got error %v but wanted %v: %v", table.desc, got, want, err)
}
if err != nil {
continue
}
- if got, want := &req, table.want; !reflect.DeepEqual(got, want) {
- t.Errorf("got leaves request\n\t%v\nbut wanted\n\t%v\nin test %q\n", got, want, table.desc)
+
+ if got, want := req, table.want; !reflect.DeepEqual(got, want) {
+ t.Errorf("%s: got leaves request\n%v\nbut wanted\n%v", table.desc, got, want)
}
}
}
-func TestInclusionProofFromASCII(t *testing.T) {
+func TestInclusionProofFromURL(t *testing.T) {
+ badHex := "F000000000000000000000000000000000000000000000000000000000000000"
+ shortHex := "00ff"
+ zeroHash := "0000000000000000000000000000000000000000000000000000000000000000"
for _, table := range []struct {
- desc string
- serialized io.Reader
- wantErr bool
- want *InclusionProof
+ desc string
+ input string
+ want InclusionProof
+ wantErr bool
}{
- {
- desc: "invalid: not an inclusion proof request (unexpected key-value pair)",
- serialized: bytes.NewBuffer(append(
- []byte(validInclusionProofASCII(t)),
- []byte("key=4")...),
- ),
- wantErr: true,
- },
- {
- desc: "valid",
- serialized: bytes.NewBuffer([]byte(validInclusionProofASCII(t))),
- want: validInclusionProof(t),
- },
+ {"invalid: not enough parameters", "some-url", InclusionProof{}, true},
+ {"invalid: tree size has a leading sign", "some-url/+1/" + zeroHash, InclusionProof{}, true},
+ {"invalid: tree size is empty", "some-url//" + zeroHash, InclusionProof{}, true},
+ {"invalid: leaf hash is not lower-case hex", "some-url/1/" + badHex, InclusionProof{}, true},
+ {"invalid: leaf hash is hex but too short", "some-url/1/" + shortHex, InclusionProof{}, true},
+ {"valid", "some-url/1/" + zeroHash, InclusionProof{1, types.Hash{}}, false},
} {
var req InclusionProof
- err := req.FromASCII(table.serialized)
+ err := req.FromURL(table.input)
if got, want := err != nil, table.wantErr; got != want {
- t.Errorf("got error %v but wanted %v in test %q: %v", got, want, table.desc, err)
+ t.Errorf("%s: got error %v but wanted %v: %v", table.desc, got, want, err)
}
if err != nil {
continue
}
- if got, want := &req, table.want; !reflect.DeepEqual(got, want) {
- t.Errorf("got inclusion proof request\n\t%v\nbut wanted\n\t%v\nin test %q\n", got, want, table.desc)
+
+ if got, want := req, table.want; !reflect.DeepEqual(got, want) {
+ t.Errorf("%s: got inclusion proof request\n%v\nbut wanted\n%v", table.desc, got, want)
}
}
}
-func TestConsistencyProofFromASCII(t *testing.T) {
+func TestConsistencyProofFromURL(t *testing.T) {
for _, table := range []struct {
- desc string
- serialized io.Reader
- wantErr bool
- want *ConsistencyProof
+ desc string
+ input string
+ want ConsistencyProof
+ wantErr bool
}{
- {
- desc: "invalid: not a consistency proof request (unexpected key-value pair)",
- serialized: bytes.NewBuffer(
- append([]byte(validConsistencyProofASCII(t)),
- []byte("tree_size=4")...),
- ),
- wantErr: true,
- },
- {
- desc: "valid",
- serialized: bytes.NewBuffer([]byte(validConsistencyProofASCII(t))),
- want: validConsistencyProof(t),
- },
+ {"invalid: not enough parameters", "some-url", ConsistencyProof{}, true},
+ {"invalid: old size has a leading sign", "some-url/+1/2", ConsistencyProof{}, true},
+ {"invalid: old size is empty", "some-url//2", ConsistencyProof{}, true},
+ {"invalid: new size is empty", "some-url/1/", ConsistencyProof{}, true},
+ {"valid", "some-url/1/2", ConsistencyProof{1, 2}, false},
} {
var req ConsistencyProof
- err := req.FromASCII(table.serialized)
+ err := req.FromURL(table.input)
if got, want := err != nil, table.wantErr; got != want {
- t.Errorf("got error %v but wanted %v in test %q: %v", got, want, table.desc, err)
+ t.Errorf("%s: got error %v but wanted %v: %v", table.desc, got, want, err)
}
if err != nil {
continue
}
- if got, want := &req, table.want; !reflect.DeepEqual(got, want) {
- t.Errorf("got consistency proof request\n\t%v\nbut wanted\n\t%v\nin test %q\n", got, want, table.desc)
+
+ if got, want := req, table.want; !reflect.DeepEqual(got, want) {
+ t.Errorf("%s: got consistency proof request\n%v\nbut wanted\n%v", table.desc, got, want)
}
}
}
diff --git a/pkg/types/endpoint.go b/pkg/types/endpoint.go
index 0e4bab2..b93d2f6 100644
--- a/pkg/types/endpoint.go
+++ b/pkg/types/endpoint.go
@@ -10,9 +10,9 @@ const (
EndpointGetTreeHeadLatest = Endpoint("get-tree-head-latest")
EndpointGetTreeHeadToSign = Endpoint("get-tree-head-to-sign")
EndpointGetTreeHeadCosigned = Endpoint("get-tree-head-cosigned")
- EndpointGetInclusionProof = Endpoint("get-inclusion-proof")
- EndpointGetConsistencyProof = Endpoint("get-consistency-proof")
- EndpointGetLeaves = Endpoint("get-leaves")
+ EndpointGetInclusionProof = Endpoint("get-inclusion-proof/")
+ EndpointGetConsistencyProof = Endpoint("get-consistency-proof/")
+ EndpointGetLeaves = Endpoint("get-leaves/")
)
// Path joins a number of components to form a full endpoint path. For example,