Skip to content

Commit b961146

Browse files
committed
ipn/ipnlocal: q-encode (RFC 2047) Tailscale serve header values
Updates tailscale#11603 RELNOTE=Tailscale serve headers are now RFC 2047 Q-encoded Change-Id: I1314b65ecf5d39a5a601676346ec2c334fdef042 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
1 parent 262fa8a commit b961146

File tree

2 files changed

+37
-2
lines changed

2 files changed

+37
-2
lines changed

ipn/ipnlocal/serve.go

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"errors"
1313
"fmt"
1414
"io"
15+
"mime"
1516
"net"
1617
"net/http"
1718
"net/http/httputil"
@@ -25,6 +26,7 @@ import (
2526
"sync"
2627
"sync/atomic"
2728
"time"
29+
"unicode/utf8"
2830

2931
"golang.org/x/net/http2"
3032
"tailscale.com/ipn"
@@ -717,12 +719,27 @@ func (b *LocalBackend) addTailscaleIdentityHeaders(r *httputil.ProxyRequest) {
717719
// Only currently set for nodes with user identities.
718720
return
719721
}
720-
r.Out.Header.Set("Tailscale-User-Login", user.LoginName)
721-
r.Out.Header.Set("Tailscale-User-Name", user.DisplayName)
722+
r.Out.Header.Set("Tailscale-User-Login", encTailscaleHeaderValue(user.LoginName))
723+
r.Out.Header.Set("Tailscale-User-Name", encTailscaleHeaderValue(user.DisplayName))
722724
r.Out.Header.Set("Tailscale-User-Profile-Pic", user.ProfilePicURL)
723725
r.Out.Header.Set("Tailscale-Headers-Info", "https://tailscale.com/s/serve-headers")
724726
}
725727

728+
// encTailscaleHeaderValue cleans or encodes as necessary v, to be suitable in
729+
// an HTTP header value. See
730+
// https://github.com/tailscale/tailscale/issues/11603.
731+
//
732+
// If v is not a valid UTF-8 string, it returns an empty string.
733+
// If v is a valid ASCII string, it returns v unmodified.
734+
// If v is a valid UTF-8 string with non-ASCII characters, it returns a
735+
// RFC 2047 Q-encoded string.
736+
func encTailscaleHeaderValue(v string) string {
737+
if !utf8.ValidString(v) {
738+
return ""
739+
}
740+
return mime.QEncoding.Encode("utf-8", v)
741+
}
742+
726743
// serveWebHandler is an http.HandlerFunc that maps incoming requests to the
727744
// correct *http.
728745
func (b *LocalBackend) serveWebHandler(w http.ResponseWriter, r *http.Request) {

ipn/ipnlocal/serve_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -823,3 +823,21 @@ func Test_isGRPCContentType(t *testing.T) {
823823
}
824824
}
825825
}
826+
827+
func TestEncTailscaleHeaderValue(t *testing.T) {
828+
tests := []struct {
829+
in string
830+
want string
831+
}{
832+
{"", ""},
833+
{"Alice Smith", "Alice Smith"},
834+
{"Bad\xffUTF-8", ""},
835+
{"Krūmiņa", "=?utf-8?q?Kr=C5=ABmi=C5=86a?="},
836+
}
837+
for _, tt := range tests {
838+
got := encTailscaleHeaderValue(tt.in)
839+
if got != tt.want {
840+
t.Errorf("encTailscaleHeaderValue(%q) = %q, want %q", tt.in, got, tt.want)
841+
}
842+
}
843+
}

0 commit comments

Comments
 (0)