Avoid use of `json.NewDecoder` if not needed
oxisto opened this issue · comments
We use both json.Unmarshal
(for the header) and json.NewDecoder
/Decode
in ParseUnverified
(for the claims). However, we only really need to use the decode type if we have UseNumber
enabled. The decoder has about a 30 % performance drawback compared to only using json.Unmarshal
+ more allocations.
var (
token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg"
)
func BenchmarkBearer(b *testing.B) {
b.Run("json.Unmarshal only", func(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
var header = map[string]any{}
var claims = map[string]any{}
var parts = strings.Split(token, ".")
headerBytes, _ := base64.URLEncoding.DecodeString(parts[0])
claimBytes, _ := base64.URLEncoding.DecodeString(parts[1])
json.Unmarshal(headerBytes, &header)
json.Unmarshal(claimBytes, &claims)
}
})
b.Run("json.Unmarshal + json.NewDecoder.Decode", func(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
var header = map[string]any{}
var claims = map[string]any{}
var parts = strings.Split(token, ".")
headerBytes, _ := base64.URLEncoding.DecodeString(parts[0])
claimBytes, _ := base64.URLEncoding.DecodeString(parts[1])
json.Unmarshal(headerBytes, &header)
dec := json.NewDecoder(bytes.NewReader(claimBytes))
dec.Decode(&claims)
}
})
}
Results:
Running tool: /opt/homebrew/bin/go test -benchmem -run=^$ -bench ^BenchmarkBearer$ github.com/golang-jwt/jwt/v5
2023/04/02 23:00:58 Listening...
goos: darwin
goarch: arm64
pkg: github.com/golang-jwt/jwt/v5
BenchmarkBearer/json.Unmarshal_only-8 1000000 1076 ns/op 1016 B/op 25 allocs/op
BenchmarkBearer/json.Unmarshal_+_json.NewDecoder.Decode-8 830516 1436 ns/op 3264 B/op 27 allocs/op
PASS
ok github.com/golang-jwt/jwt/v5 2.405s