Skip to content

Commit 9d491e7

Browse files
committed
filesync: fix handling non-ascii in file paths
Signed-off-by: Tonis Tiigi <[email protected]>
1 parent 6e483a2 commit 9d491e7

File tree

1 file changed

+46
-0
lines changed

1 file changed

+46
-0
lines changed

session/filesync/filesync.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ import (
44
"context"
55
"fmt"
66
io "io"
7+
"net/url"
78
"os"
89
"strings"
10+
"unicode"
911

1012
"github.com/moby/buildkit/session"
1113
"github.com/pkg/errors"
@@ -82,6 +84,7 @@ func (sp *fsSyncProvider) handle(method string, stream grpc.ServerStream) (retEr
8284
}
8385

8486
opts, _ := metadata.FromIncomingContext(stream.Context()) // if no metadata continue with empty object
87+
opts = decodeOpts(opts)
8588

8689
dirName := ""
8790
name, ok := opts[keyDirName]
@@ -209,6 +212,8 @@ func FSSync(ctx context.Context, c session.Caller, opt FSSendRequestOpt) error {
209212

210213
var stream grpc.ClientStream
211214

215+
opts = encodeOpts(opts)
216+
212217
ctx = metadata.NewOutgoingContext(ctx, opts)
213218

214219
switch pr.name {
@@ -337,3 +342,44 @@ func (e InvalidSessionError) Error() string {
337342
func (e InvalidSessionError) Unwrap() error {
338343
return e.err
339344
}
345+
346+
func encodeOpts(opts map[string][]string) map[string][]string {
347+
md := make(map[string][]string, len(opts))
348+
for k, v := range opts {
349+
out := make([]string, len(v))
350+
for i, s := range v {
351+
out[i] = encodeStringForHeader(s)
352+
}
353+
md[k] = out
354+
}
355+
return md
356+
}
357+
358+
func decodeOpts(opts map[string][]string) map[string][]string {
359+
md := make(map[string][]string, len(opts))
360+
for k, v := range opts {
361+
out := make([]string, len(v))
362+
for i, s := range v {
363+
out[i], _ = url.QueryUnescape(s)
364+
}
365+
md[k] = out
366+
}
367+
return md
368+
}
369+
370+
// encodeStringForHeader encodes a string value so it can be used in grpc header. This encoding
371+
// is backwards compatible and avoids encoding ASCII characters.
372+
func encodeStringForHeader(input string) string {
373+
var output strings.Builder
374+
for _, runeVal := range input {
375+
// Only encode non-ASCII characters.
376+
if runeVal > unicode.MaxASCII {
377+
// Encode each non-ASCII character individually.
378+
output.WriteString(url.QueryEscape(string(runeVal)))
379+
} else {
380+
// Directly append ASCII characters and '*' to the output.
381+
output.WriteRune(runeVal)
382+
}
383+
}
384+
return output.String()
385+
}

0 commit comments

Comments
 (0)