
commit 9a9f9cb455d17bf82d02292953b945dcbb4a5029 Author: David Fifield <david@bamsoftware.com> Date: Sun Dec 8 02:53:38 2013 -0800 encodeSmethodArgs. --- args.go | 44 ++++++++++++++++++++++++++++++++++++++++++++ args_test.go | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/args.go b/args.go index a0a3bd5..9eacee5 100644 --- a/args.go +++ b/args.go @@ -4,6 +4,8 @@ import ( "bytes" "errors" "fmt" + "sort" + "strings" ) // Key–value mappings for the representation of client and server options. @@ -173,3 +175,45 @@ func parseServerTransportOptions(s string) (opts map[string]Args, err error) { } return opts, nil } + +// Escape backslashes and all the bytes that are in set. +func backslashEscape(s string, set []byte) string { + var buf bytes.Buffer + for _, b := range []byte(s) { + if b == '\\' || bytes.IndexByte(set, b) != -1 { + buf.WriteByte('\\') + } + buf.WriteByte(b) + } + return buf.String() +} + +// Encode a name–value mapping so that it is suitable to go in the ARGS option +// of an SMETHOD line. The output is sorted by key. The "ARGS:" prefix is not +// added. +// +// "Equal signs and commas [and backslashes] must be escaped with a backslash." +func encodeSmethodArgs(args Args) string { + if args == nil { + return "" + } + + keys := make([]string, 0, len(args)) + for key, _ := range args { + keys = append(keys, key) + } + sort.Strings(keys) + + escape := func(s string) string { + return backslashEscape(s, []byte{'=', ','}) + } + + var pairs []string + for _, key := range keys { + for _, value := range args[key] { + pairs = append(pairs, escape(key)+"="+escape(value)) + } + } + + return strings.Join(pairs, ",") +} diff --git a/args_test.go b/args_test.go index ece7a50..d62968c 100644 --- a/args_test.go +++ b/args_test.go @@ -299,3 +299,38 @@ func TestParseServerTransportOptions(t *testing.T) { } } } + +func TestEncodeSmethodArgs(t *testing.T) { + tests := [...]struct { + args Args + expected string + }{ + { + Args{}, + "", + }, + { + Args{"j": []string{"v1", "v2", "v3"}, "k": []string{"v1", "v2", "v3"}}, + "j=v1,j=v2,j=v3,k=v1,k=v2,k=v3", + }, + { + Args{"=,\\": []string{"=", ",", "\\"}}, + "\\=\\,\\\\=\\=,\\=\\,\\\\=\\,,\\=\\,\\\\=\\\\", + }, + { + Args{"secret": []string{"yes"}}, + "secret=yes", + }, + { + Args{"secret": []string{"nou"}, "cache": []string{"/tmp/cache"}}, + "cache=/tmp/cache,secret=nou", + }, + } + + for _, test := range tests { + encoded := encodeSmethodArgs(test.args) + if encoded != test.expected { + t.Errorf("%q → %q (expected %q)", test.args, encoded, test.expected) + } + } +}
participants (1)
-
dcf@torproject.org