@@ -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 {
337342func (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