Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid use of json.NewDecoder if not needed #303

Closed
oxisto opened this issue Apr 2, 2023 · 0 comments · Fixed by #313
Closed

Avoid use of json.NewDecoder if not needed #303

oxisto opened this issue Apr 2, 2023 · 0 comments · Fixed by #313

Comments

@oxisto
Copy link
Collaborator

oxisto commented Apr 2, 2023

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
oxisto pushed a commit that referenced this issue Aug 15, 2023
* Avoid use of json.NewDecoder

Avoid use of json.NewDecoder if not needed.

Resolves #303
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant