mirror of
https://github.com/grafana/grafana.git
synced 2025-08-01 20:12:13 +08:00
Plugins: Fix and encode invalid gRPC header values (#107339)
* Plugins: Fix and encode invalid gRPC header values * Rename the method * Run sanitizeHTTPHeaderValueForGRPC only if string includes utf8 * Update test * Simplify * Update * do not double encode encoded characters * Update test * Update * Add test case based on review * Update test
This commit is contained in:
@ -2,8 +2,13 @@ package clientmiddleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"golang.org/x/text/encoding/charmap"
|
||||
"golang.org/x/text/transform"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/contexthandler"
|
||||
"github.com/grafana/grafana/pkg/services/query"
|
||||
@ -50,6 +55,9 @@ func (m *TracingHeaderMiddleware) applyHeaders(ctx context.Context, req backend.
|
||||
if gotVal == "" {
|
||||
continue
|
||||
}
|
||||
if !utf8.ValidString(gotVal) {
|
||||
gotVal = sanitizeHTTPHeaderValueForGRPC(gotVal)
|
||||
}
|
||||
req.SetHTTPHeader(headerName, gotVal)
|
||||
}
|
||||
}
|
||||
@ -102,3 +110,28 @@ func (m *TracingHeaderMiddleware) RunStream(ctx context.Context, req *backend.Ru
|
||||
m.applyHeaders(ctx, req)
|
||||
return m.BaseHandler.RunStream(ctx, req, sender)
|
||||
}
|
||||
|
||||
// sanitizeHTTPHeaderValueForGRPC sanitizes header values according to HTTP/2 gRPC specification.
|
||||
// The spec defines that header values must consist of printable ASCII characters 0x20 (space) - 0x7E(tilde) inclusive.
|
||||
// First attempts to decode any percent-encoded characters, then encodes invalid characters.
|
||||
func sanitizeHTTPHeaderValueForGRPC(value string) string {
|
||||
// First try to decode characters that were encoded by the frontend
|
||||
decoder := charmap.ISO8859_1.NewDecoder()
|
||||
decoded, _, err := transform.Bytes(decoder, []byte(value))
|
||||
// If decoding fails, work with the original value
|
||||
if err != nil {
|
||||
decoded = []byte(value)
|
||||
}
|
||||
var sanitized strings.Builder
|
||||
sanitized.Grow(len(decoded)) // Pre-allocate reasonable capacity
|
||||
// Then encode invalid characters
|
||||
for _, b := range decoded {
|
||||
if b >= 0x20 && b <= 0x7E {
|
||||
sanitized.WriteByte(b)
|
||||
} else {
|
||||
sanitized.WriteString(fmt.Sprintf("%%%02X", b))
|
||||
}
|
||||
}
|
||||
|
||||
return sanitized.String()
|
||||
}
|
||||
|
Reference in New Issue
Block a user