summaryrefslogtreecommitdiffstats
path: root/request_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'request_test.go')
-rw-r--r--request_test.go341
1 files changed, 341 insertions, 0 deletions
diff --git a/request_test.go b/request_test.go
new file mode 100644
index 0000000..bb4aa9b
--- /dev/null
+++ b/request_test.go
@@ -0,0 +1,341 @@
+package cnp
+
+import (
+ "bytes"
+ "strconv"
+ "strings"
+ "testing"
+ "time"
+)
+
+type requestTest struct {
+ h, s string
+ p Parameters
+ e, v error
+}
+
+var requestTests = []requestTest{
+ // invalid intent
+ {"", "", nil, ErrorInvalid{}, nil},
+ {"", "foo/bar", nil, ErrorInvalid{}, nil},
+ {"foo/", "bar", nil, ErrorInvalid{}, nil},
+ {"foo/", "/bar", nil, ErrorInvalid{}, nil},
+
+ // invalid request params
+ {"", "/", Parameters{"length": "w"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"length": "-1"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"length": "03"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"name": "foo/bar"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"name": "foo\x00bar"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"type": "foo"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"type": "\x00"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"type": "text/plain\x00"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"type": "foo/bar "}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"type": " foo/bar"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"type": "foo /bar"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"type": "foo/ bar"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"type": "foo/bar\n"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"type": "foo/b(r"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"if_modified": "0"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"if_modified": "now"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"if_modified": "today"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"if_modified": "Thu Jan 1 00:00:00 UTC 1970"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"if_modified": "1970-01-01 00:00:00+00:00"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"if_modified": "1970-01-01 00:00:00 UTC"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"if_modified": "1970-01-01 00:00:00+0000"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"if_modified": "1970-01-01 00:00:00+00"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"if_modified": "1970-01-01T00:00:00+00:00"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"if_modified": "1970-01-01T00:00:00 UTC"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"if_modified": "1970-01-01T00:00:00+0000"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"if_modified": "1970-01-01T00:00:00+00"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"if_modified": "0000-00-01T00:00:00Z"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"if_modified": "0000-01-00T00:00:00Z"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"if_modified": "0000-01-01T24:00:00Z"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"if_modified": "0000-01-01T00:60:00Z"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"if_modified": "0000-01-01T00:00:60Z"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"if_modified": "0000-11-31T00:00:00Z"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"if_modified": "0001-02-29T00:00:00Z"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"if_modified": "0002-02-29T00:00:00Z"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"if_modified": "0003-02-29T00:00:00Z"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"if_modified": "0005-02-29T00:00:00Z"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"if_modified": "0100-02-29T00:00:00Z"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"if_modified": "1000-02-29T00:00:00Z"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"if_modified": "123-01-01T00:00:00Z"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"if_modified": "12345-01-01T00:00:00Z"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"if_modified": "-5-01-01T00:00:00Z"}, nil, ErrorInvalid{}},
+ {"", "/", Parameters{"if_modified": "-2005-01-01T00:00:00Z"}, nil, ErrorInvalid{}},
+
+ // valid simple requests
+ {"", "/", nil, nil, nil},
+ {"", "/foo/bar", nil, nil, nil},
+ {"cnp.example.com", "/", nil, nil, nil},
+ {"foo", "/bar", nil, nil, nil},
+ {"example.com", "/ f=#\\oo///.././.../~/\x01/\xff/ba\nr", nil, nil, nil},
+
+ // valid request params
+ {"", "/", Parameters{"length": "", "name": "", "type": "", "if_modified": "", "": "", "q\x00we": "=a s\nd"}, nil, nil},
+ {"", "/", Parameters{"length": "0"}, nil, nil},
+ {"", "/", Parameters{"length": "1"}, nil, nil},
+ {"", "/", Parameters{"length": "12345670089000000"}, nil, nil},
+ {"", "/", Parameters{"name": "foobar"}, nil, nil},
+ {"", "/", Parameters{"name": "x"}, nil, nil},
+ {"", "/", Parameters{"name": "..-~!foo bar\nbaz\rquux=qwe\\asd"}, nil, nil},
+ {"", "/", Parameters{"name": strings.Repeat("w", 1024*8)}, nil, nil},
+ {"", "/", Parameters{"type": "qwe/asd"}, nil, nil},
+ {"", "/", Parameters{"type": "qwe+asd/foo"}, nil, nil},
+ {"", "/", Parameters{"type": "qwe-asd/foo"}, nil, nil},
+ {"", "/", Parameters{"if_modified": "1970-01-01T00:00:00Z"}, nil, nil},
+ {"", "/", Parameters{"if_modified": "0000-01-01T00:00:00Z"}, nil, nil},
+ {"", "/", Parameters{"if_modified": "9999-12-31T23:59:59Z"}, nil, nil},
+ {"", "/", Parameters{"if_modified": "0123-05-06T07:08:09Z"}, nil, nil},
+ {"", "/", Parameters{"if_modified": "0000-02-29T00:00:00Z"}, nil, nil},
+ {"", "/", Parameters{"if_modified": "2000-02-29T00:00:00Z"}, nil, nil},
+}
+
+func TestNewRequest(t *testing.T) {
+ for _, tst := range requestTests {
+ req, err := NewRequest(tst.h, tst.s, []byte{})
+ if !errorEqual(tst.e, err) {
+ t.Errorf("NewRequest(%q, %q): expected error %+v, got %+v (%v)", tst.h, tst.s, tst.e, err, err)
+ continue
+ }
+ if tst.e == nil {
+ if tst.h != req.Host() {
+ t.Errorf("NewRequest(%q: %q): got unexpected host %q", tst.h, tst.s, req.Host())
+ } else if Clean(tst.s) != req.Path() {
+ t.Errorf("NewRequest(%q: %q): got unexpected path %q", tst.h, tst.s, req.Path())
+ }
+ }
+ }
+}
+
+type requestURLTest struct {
+ u string
+ h, p string
+ e error
+}
+
+var requestURLTests = []requestURLTest{
+ // invalid
+ {"cnp:example.com/path/to/file", "", "", ErrorURL{}},
+ {"http://example.com/path/to/file", "", "", ErrorURL{}},
+ {"cnp://foo@bar:example.com/path/to/file", "", "", ErrorURL{}},
+ {"cnp://foo:example.com/path/to/file", "", "", ErrorURL{}},
+ {"", "", "/", ErrorURL{}},
+ {"cnp://example.com/%5", "", "", ErrorURL{}},
+ //{"cnp://example.com/?%5", "", "", ErrorURL{}},
+
+ // valid
+ {"cnp://example.com/path/to/file", "example.com", "/path/to/file", nil},
+ {"cnp://2130706433/", "2130706433", "/", nil},
+ //{"cnp://02130706433/", "2130706433", "/", nil},
+ {"cnp://127.0.0.1/", "127.0.0.1", "/", nil},
+ //{"cnp://0127.0.00.01/", "127.0.0.1", "/", nil},
+ {"cnp://localhost", "localhost", "/", nil},
+ {"cnp://[::1]/foo%20bar", "[::1]", "/foo bar", nil},
+ {"cnp://[2001:db8::7334]/foo%0abar", "[2001:db8::7334]", "/foo\nbar", nil},
+ //{"cnp://[2001:0db8:0000::7334]/foo%0abar", "[2001:db8::7334]", "/foo\nbar", nil},
+ //{"cnp://example.com/qwe%20asd?foo=bar&baz=qu%20ux", "example.com", "/qwe asd?foo=bar&baz=qu ux", nil},
+ {"cnp://example.com/qwe%20asd?foo=bar&baz=qu%20ux", "example.com", "/qwe asd", nil},
+ {"cnp://localhost:25454", "localhost", "/", nil},
+ {"cnp://localhost:12345/foo/bar", "localhost:12345", "/foo/bar", nil},
+ {"cnp://localhost:25454/foo/bar", "localhost", "/foo/bar", nil},
+ {"cnp://2130706433:12345/foo/bar", "2130706433:12345", "/foo/bar", nil},
+ {"cnp://2130706433:25454/foo/bar", "2130706433", "/foo/bar", nil},
+ {"cnp://127.0.0.1:12345/foo/bar", "127.0.0.1:12345", "/foo/bar", nil},
+ {"cnp://127.0.0.1:25454/foo/bar", "127.0.0.1", "/foo/bar", nil},
+ {"cnp://[::1]:12345/foo/bar", "[::1]:12345", "/foo/bar", nil},
+ {"cnp://[::1]:25454/foo/bar", "[::1]", "/foo/bar", nil},
+ {"//example.com/path/", "example.com", "/path/", nil},
+ {"/example.com/path/", "", "/example.com/path/", nil},
+ {"/foo/bar", "", "/foo/bar", nil},
+ {"/", "", "/", nil},
+ {"cnp://example.com/ ™☺)\n", "example.com", "/ ™☺)\n", nil},
+ {"cnp://œ¤å₥¶ḹə.©°ɱ/baz/../foo/.//bar////.//../bar//", "œ¤å₥¶ḹə.©°ɱ", "/foo/bar/", nil},
+ {"cnp://foo/bar/", "foo", "/bar/", nil},
+ {"cnp:///foo/bar/", "", "/foo/bar/", nil},
+ {"cnp:////////foo/bar/", "", "/foo/bar/", nil},
+}
+
+func TestNewRequestURL(t *testing.T) {
+ for _, tst := range requestURLTests {
+ req, err := NewRequestURL(tst.u, nil)
+ if !errorEqual(tst.e, err) {
+ t.Errorf("NewRequestURL(%q, nil): expected error %+v, got %+v (%v)", tst.u, tst.e, err, err)
+ continue
+ }
+ if tst.e == nil {
+ if req.Host() != tst.h {
+ t.Errorf("NewRequestURL(%q, nil): expected host %q, got %q", tst.u, tst.h, req.Host())
+ } else if req.Path() != tst.p {
+ t.Errorf("NewRequestURL(%q, nil): expected path %q, got %q", tst.u, tst.p, req.Path())
+ }
+ }
+ }
+}
+
+func TestWriteParseRequest(t *testing.T) {
+ for _, tst := range requestTests {
+ if tst.e != nil {
+ continue // skip syntax errors but not invalid params
+ }
+ req := &Request{Message{Header{0, 3, "/", Parameters{}}, nil, nil}}
+ if err := req.SetHost(tst.h); err != nil {
+ t.Errorf("SetHost(%q) error: %v", tst.h, err)
+ continue
+ }
+ if err := req.SetPath(tst.s); err != nil {
+ t.Errorf("SetPath(%q) error: %v", tst.s, err)
+ continue
+ }
+ for k, v := range tst.p {
+ req.SetParam(k, v)
+ }
+
+ var buf bytes.Buffer
+ if err := req.Write(&buf); err != nil {
+ t.Errorf("%+v.Write: error %v", req, err)
+ continue
+ }
+
+ s := buf.String()
+ req2, err := ParseRequest(strings.NewReader(s))
+ if err != nil {
+ t.Errorf("ParseRequest(%q) error: %v", s, err)
+ continue
+ }
+ if !msgEqual(&req.Message, &req2.Message) {
+ t.Errorf("Write/Parse: expected %+v, got %+v", req, req2)
+ continue
+ }
+ }
+}
+
+func TestRequestValidate(t *testing.T) {
+ for _, tst := range requestTests {
+ if tst.e != nil {
+ continue
+ }
+ req := &Request{Message{Header{Intent: tst.h + tst.s, Parameters: tst.p}, nil, nil}}
+ if err := req.Validate(); !errorEqual(tst.v, err) {
+ t.Errorf("%+v.Validate(): expected error %+v, got %+v (%v)", req, tst.v, err, err)
+ }
+ }
+}
+
+func TestRequestGetSet(t *testing.T) {
+ e := func(k, v string, expect, err error) {
+ if !errorEqual(err, expect) {
+ t.Errorf("setting param %q to %q: expected %+v, got %+v (%v)", k, v, expect, err, err)
+ }
+ }
+ c := func(k, v string, expect error, p string) {
+ if expect == nil && v != p {
+ t.Errorf("getting param %q: expected %q, got %q", k, v, p)
+ }
+ }
+
+ for _, tst := range requestTests {
+ if tst.e != nil {
+ continue
+ }
+ req, _ := NewRequest(tst.h, tst.s, nil)
+ for k, v := range tst.p {
+ switch k {
+ case "length":
+ n, _ := strconv.ParseUint(v, 10, 63)
+ req.SetLength(int64(n))
+ s := strconv.FormatInt(req.Length(), 10)
+ if s == "0" && v == "" {
+ s = ""
+ }
+ c(k, v, tst.v, s)
+ case "name":
+ e(k, v, tst.v, req.SetName(v))
+ c(k, v, tst.v, req.Name())
+ case "type":
+ e(k, v, tst.v, req.SetType(v))
+ t := req.Type()
+ if t == "application/octet-stream" && v == "" {
+ t = ""
+ }
+ c(k, v, tst.v, t)
+ case "if_modified":
+ if tst.v != nil {
+ continue // invalid time format, can't even parse
+ }
+ var tm time.Time
+ if v != "" {
+ tm, _ = time.Parse(time.RFC3339, v)
+ }
+ req.SetIfModified(tm)
+ tm2 := ""
+ if !req.IfModified().IsZero() {
+ tm2 = req.IfModified().Format(time.RFC3339)
+ }
+ c(k, v, tst.v, tm2)
+ default:
+ req.SetParam(k, v)
+ c(k, v, tst.v, req.Param(k))
+ }
+ }
+ }
+}
+
+var urlTests = map[string]string{
+ "œ¤å₥¶ḹə.©°ɱ/foo/bar": "cnp://%C5%93%C2%A4%C3%A5%E2%82%A5%C2%B6%E1%B8%B9%C9%99.%C2%A9%C2%B0%C9%B1/foo/bar",
+ "2130706433/": "cnp://2130706433/",
+ "example.com/path/to/file/": "cnp://example.com/path/to/file/",
+ "[::1]/foo bar": "cnp://[::1]/foo%20bar",
+ "[2001:db8::7334]/foo\nbar": "cnp://[2001:db8::7334]/foo%0Abar",
+ "example.com/qwe asd": "cnp://example.com/qwe%20asd",
+ "example.com/ ™☺)\n": "cnp://example.com/%20%E2%84%A2%E2%98%BA%29%0A",
+}
+
+func TestRequestURL(t *testing.T) {
+ for k, v := range urlTests {
+ t.Run(v, func(t *testing.T) {
+ req, err := NewRequestURL(v, nil)
+ if err != nil {
+ t.Fatalf("NewRequestURL(%q): error: %v", v, err)
+ }
+ if req.Intent() != k {
+ t.Fatalf("NewRequestURL(%q).Intent(): expected %q, got %q", v, k, req.Intent())
+ }
+ if req.URL().String() != v {
+ t.Fatalf("NewRequestURL(%q).URL(): expected %q, got %q", v, v, req.URL())
+ }
+ })
+ }
+}
+
+var cleanTests = map[string]string{
+ "/../.././//foo/bar/..": "/foo",
+ "//foo/bar/../": "/foo/",
+ "/": "/",
+ "//": "/",
+ "/..": "/",
+ "/../..": "/",
+ "/../": "/",
+ "/.": "/",
+ "/./": "/",
+ "/./.": "/",
+ "/././": "/",
+ "/./../": "/",
+ "/.././": "/",
+ "/foo/bar/../baz": "/foo/baz",
+ "/foo/bar/../baz/": "/foo/baz/",
+ "/foo/../foo/bar/../bar/baz/quux/../": "/foo/bar/baz/",
+ "/foo/../foo/bar/../bar/baz/quux/..": "/foo/bar/baz",
+}
+
+func TestClean(t *testing.T) {
+ for k, v := range cleanTests {
+ t.Run(k, func(t *testing.T) {
+ c := Clean(k)
+ if c != v {
+ t.Fatalf("Clean(%q): expected %q, got %q", k, v, c)
+ }
+ })
+ }
+}