[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [goptlib/master] parseServerTransportOptions.
commit 11d2149f1de4c0975ce70f8eaceb863b9058675c
Author: David Fifield <david@xxxxxxxxxxxxxxx>
Date: Sun Dec 8 01:59:57 2013 -0800
parseServerTransportOptions.
---
args.go | 70 +++++++++++++++++++++++++++++++++++++
args_test.go | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 180 insertions(+)
diff --git a/args.go b/args.go
index df3aced..a0a3bd5 100644
--- a/args.go
+++ b/args.go
@@ -103,3 +103,73 @@ func parseClientParameters(s string) (args Args, err error) {
}
return args, nil
}
+
+// Parse a transportâ??nameâ??value mapping as from TOR_PT_SERVER_TRANSPORT_OPTIONS.
+//
+// "<value> is a k=v string value with options that are to be passed to the
+// transport. Colons, semicolons, equal signs and backslashes must be escaped
+// with a backslash."
+// Example: trebuchet:secret=nou;trebuchet:cache=/tmp/cache;ballista:secret=yes
+func parseServerTransportOptions(s string) (opts map[string]Args, err error) {
+ opts = make(map[string]Args)
+ if len(s) == 0 {
+ return
+ }
+ i := 0
+ for {
+ var methodName, key, value string
+ var offset, begin int
+
+ begin = i
+ // Read the method name.
+ offset, methodName, err = indexUnescaped(s[i:], []byte{':', '=', ';'})
+ if err != nil {
+ return
+ }
+ i += offset
+ // End of string or no colon?
+ if i >= len(s) || s[i] != ':' {
+ err = errors.New(fmt.Sprintf("no colon in %q", s[begin:i]))
+ return
+ }
+ // Skip the colon.
+ i++
+ // Read the key.
+ offset, key, err = indexUnescaped(s[i:], []byte{'=', ';'})
+ if err != nil {
+ return
+ }
+ i += offset
+ // End of string or no equals sign?
+ if i >= len(s) || s[i] != '=' {
+ err = errors.New(fmt.Sprintf("no equals sign in %q", s[begin:i]))
+ return
+ }
+ // Skip the equals sign.
+ i++
+ // Read the value.
+ offset, value, err = indexUnescaped(s[i:], []byte{';'})
+ if err != nil {
+ return
+ }
+ i += offset
+ if len(methodName) == 0 {
+ err = errors.New(fmt.Sprintf("empty method name in %q", s[begin:i]))
+ return
+ }
+ if len(key) == 0 {
+ err = errors.New(fmt.Sprintf("empty key in %q", s[begin:i]))
+ return
+ }
+ if opts[methodName] == nil {
+ opts[methodName] = make(Args)
+ }
+ opts[methodName].Add(key, value)
+ if i >= len(s) {
+ break
+ }
+ // Skip the semicolon.
+ i++
+ }
+ return opts, nil
+}
diff --git a/args_test.go b/args_test.go
index 69194fd..078c79a 100644
--- a/args_test.go
+++ b/args_test.go
@@ -181,3 +181,113 @@ func TestParseClientParameters(t *testing.T) {
}
}
}
+
+func optsEqual(a, b map[string]Args) bool {
+ for k, av := range a {
+ bv, ok := b[k]
+ if !ok || !argsEqual(av, bv) {
+ return false
+ }
+ }
+ for k, bv := range b {
+ av, ok := a[k]
+ if !ok || !argsEqual(av, bv) {
+ return false
+ }
+ }
+ return true
+}
+
+func TestParseServerTransportOptions(t *testing.T) {
+ badTests := [...]string{
+ ":=",
+ "t:=",
+ ":k=",
+ ":=v",
+ "t:=v",
+ "t:=v",
+ "t:k=v;",
+ "abc",
+ "t:",
+ "key=value",
+ "=value",
+ "t:k=v\\",
+ "t1:k=v;t2:k=v\\",
+ "t:=key=value",
+ "t:==key=value",
+ "t:;key=value",
+ "t:key\\=value",
+ }
+ goodTests := [...]struct {
+ input string
+ expected map[string]Args
+ }{
+ {
+ "",
+ map[string]Args{},
+ },
+ {
+ "t:k=v",
+ map[string]Args{
+ "t": Args{"k": []string{"v"}},
+ },
+ },
+ {
+ "t1:k=v1;t2:k=v2;t1:k=v3",
+ map[string]Args{
+ "t1": Args{"k": []string{"v1", "v3"}},
+ "t2": Args{"k": []string{"v2"}},
+ },
+ },
+ {
+ "t\\:1:k=v;t\\=2:k=v;t\\;3:k=v;t\\\\4:k=v",
+ map[string]Args{
+ "t:1": Args{"k": []string{"v"}},
+ "t=2": Args{"k": []string{"v"}},
+ "t;3": Args{"k": []string{"v"}},
+ "t\\4": Args{"k": []string{"v"}},
+ },
+ },
+ {
+ "t:k\\:1=v;t:k\\=2=v;t:k\\;3=v;t:k\\\\4=v",
+ map[string]Args{
+ "t": Args{
+ "k:1": []string{"v"},
+ "k=2": []string{"v"},
+ "k;3": []string{"v"},
+ "k\\4": []string{"v"},
+ },
+ },
+ },
+ {
+ "t:k=v\\:1;t:k=v\\=2;t:k=v\\;3;t:k=v\\\\4",
+ map[string]Args{
+ "t": Args{"k": []string{"v:1", "v=2", "v;3", "v\\4"}},
+ },
+ },
+ {
+ "trebuchet:secret=nou;trebuchet:cache=/tmp/cache;ballista:secret=yes",
+ map[string]Args{
+ "trebuchet": Args{"secret": []string{"nou"}, "cache": []string{"/tmp/cache"}},
+ "ballista": Args{"secret": []string{"yes"}},
+ },
+ },
+ }
+
+ for _, input := range badTests {
+ _, err := parseServerTransportOptions(input)
+ if err == nil {
+ t.Errorf("%q unexpectedly succeeded", input)
+ }
+ }
+
+ for _, test := range goodTests {
+ opts, err := parseServerTransportOptions(test.input)
+ if err != nil {
+ t.Errorf("%q unexpectedly returned an error: %s", test.input, err)
+ }
+ if !optsEqual(opts, test.expected) {
+ t.Errorf("%q â?? %q (expected %q)", test.input, opts, test.expected)
+ }
+ }
+}
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits