forked from godbus/dbus
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introduce and use EscapeBusAddressValue
D-Bus specification [1] requires that the values in server address need to be escaped in a special way, and other clients perform the needed escaping (e.g. systemd [2] does that). More to say, if dbus sees a character that should have been escaped, it returns an error [3]. Add EscapeBusAddressValue function (with some tests and a benchmark), and use it from tryDiscoverDbusSessionBusAddress(). The function is exported as it might be of use to other packages (in particular, runc [4]). NOTE that the function does not escape '*' symbol, because de-facto it is the list of optionally-escaped characters since 2007, but that is not yet documented in D-Bus spec (see [5] for more details). [1] https://dbus.freedesktop.org/doc/dbus-specification.html#addresses [2] https://github.com/systemd/systemd/blob/5efbd0bf897a990ebe43d7dc69141d87c404ac9a/src/libsystemd/sd-bus/bus-internal.c#L294-L318 [3] https://gitlab.freedesktop.org/dbus/dbus/-/blob/37b76d13738e782fe2eb12abdd0179745c0b3f81/dbus/dbus-address.c#L330 [4] opencontainers/runc#3356 [5] https://gitlab.freedesktop.org/dbus/dbus/-/merge_requests/248 Signed-off-by: Kir Kolyshkin <[email protected]>
- Loading branch information
Showing
3 changed files
with
116 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package dbus | ||
|
||
import "strings" | ||
|
||
// EscapeBusAddressValue implements a requirement to escape the values | ||
// in D-Bus server addresses, as defined by the D-Bus specification at | ||
// https://dbus.freedesktop.org/doc/dbus-specification.html#addresses. | ||
func EscapeBusAddressValue(val string) string { | ||
toEsc := strNeedsEscape(val) | ||
if toEsc == 0 { | ||
// Avoid unneeded allocation/copying. | ||
return val | ||
} | ||
|
||
var out strings.Builder | ||
// Every to-be-escaped byte needs 3 bytes, i.e. 2 extra bytes. | ||
out.Grow(len(val) + 2*toEsc) | ||
|
||
for i := 0; i < len(val); i++ { | ||
ch := val[i] | ||
if !needsEscape(ch) { | ||
_ = out.WriteByte(ch) | ||
|
||
continue | ||
} | ||
// Convert ch to %xx, where xx is hex value. | ||
_ = out.WriteByte('%') | ||
_ = out.WriteByte(hexchar(ch >> 4)) | ||
_ = out.WriteByte(hexchar(ch & 0x0F)) | ||
} | ||
|
||
return out.String() | ||
} | ||
|
||
// hexchar returns an octal representation of a n, where n < 16. | ||
// For invalid values of n, the function panics. | ||
func hexchar(n byte) byte { | ||
const hex = "0123456789abcdef" | ||
|
||
// For n >= len(hex), runtime will panic. | ||
return hex[n] | ||
} | ||
|
||
// needsEscape tells if a byte is NOT one of optionally-escaped bytes. | ||
func needsEscape(c byte) bool { | ||
if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' { | ||
return false | ||
} | ||
switch c { | ||
case '-', '_', '/', '\\', '.', '*': | ||
return false | ||
} | ||
|
||
return true | ||
} | ||
|
||
// strNeedsEscape tells how many bytes in the string need escaping. | ||
func strNeedsEscape(val string) int { | ||
count := 0 | ||
|
||
for i := 0; i < len(val); i++ { | ||
if needsEscape(val[i]) { | ||
count++ | ||
} | ||
} | ||
|
||
return count | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package dbus | ||
|
||
import ( | ||
"net/url" | ||
"testing" | ||
) | ||
|
||
var escapeTestCases = []struct { | ||
in, out string | ||
}{ | ||
{in: "", out: ""}, | ||
{in: "ABCDabcdZYXzyx01289", out: "ABCDabcdZYXzyx01289"}, | ||
{in: `_-/\*`, out: `_-/\*`}, | ||
{in: `=+:~!`, out: `%3d%2b%3a%7e%21`}, | ||
{in: `space here`, out: `space%20here`}, | ||
{in: `Привет`, out: `%d0%9f%d1%80%d0%b8%d0%b2%d0%b5%d1%82`}, | ||
{in: `ჰეი`, out: `%e1%83%b0%e1%83%94%e1%83%98`}, | ||
{in: `你好`, out: `%e4%bd%a0%e5%a5%bd`}, | ||
{in: `こんにちは`, out: `%e3%81%93%e3%82%93%e3%81%ab%e3%81%a1%e3%81%af`}, | ||
} | ||
|
||
func TestEscapeBusAddressValue(t *testing.T) { | ||
for _, tc := range escapeTestCases { | ||
out := EscapeBusAddressValue(tc.in) | ||
if out != tc.out { | ||
t.Errorf("input: %q; want %q, got %q", tc.in, tc.out, out) | ||
} | ||
// Use QueryUnescape to unescape %xx back to bytes. | ||
in, err := url.QueryUnescape(out) | ||
if err != nil { | ||
t.Errorf("unescape error: %v", err) | ||
} else if in != tc.in { | ||
t.Errorf("unescape: want %q, got %q", tc.in, in) | ||
} | ||
} | ||
} | ||
|
||
func BenchmarkEscapeBusAddressValue(b *testing.B) { | ||
var out string | ||
|
||
for i := 0; i < b.N; i++ { | ||
for _, tc := range escapeTestCases { | ||
out = EscapeBusAddressValue(tc.in) | ||
} | ||
} | ||
b.Log("out:", out) | ||
} |