Repository: cloudwego/hertz
Pull request #1317 (2025-04-01 06:39:42)

fix(protocol): Peek() returns non-nil if key exists
#### What type of PR is this?
fix

<!--
Add one of the following kinds:

build: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
ci: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)
docs: Documentation only changes
feat: A new feature
optimize: A new optimization
fix: A bug fix
perf: A code change that improves performance
refactor: A code change that neither fixes a bug nor adds a feature
style: Changes that do not affect the meaning of the code (white space, formatting, missing semi-colons, etc)
test: Adding missing tests or correcting existing tests
chore: Changes to the build process or auxiliary tools and libraries such as documentation generation
-->

#### Check the PR title.
<!--
The description of the title will be attached in Release Notes, 
so please describe it from user-oriented, what this PR does / why we need it.
Please check your PR title with the below requirements:
-->
- [ ] This PR title match the format: \<type\>(optional scope): \<description\>
- [ ] The description of this PR title is user-oriented and clear enough for others to understand.
- [ ] Attach the PR updating the user documentation if the current PR requires user awareness at the usage level. [User docs repo](https://github.com/cloudwego/cloudwego.github.io)


#### (Optional) Translate the PR title into Chinese.
修复 Peek 对于 key 存在时，仍返回 nil 的问题

#### (Optional) More detailed description for this PR(en: English/zh: Chinese).
<!--
Provide more detailed info for review(e.g., it's recommended to provide perf data if this is a perf type PR).
-->
en:
zh(optional):

#### (Optional) Which issue(s) this PR fixes:
<!--
Automatically closes linked issue when PR is merged.
Eg: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
-->

#### (Optional) The PR that updates user documentation:
<!--
If the current PR requires user awareness at the usage level, please submit a PR to update user docs. [User docs repo](https://github.com/cloudwego/cloudwego.github.io)
-->

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/cloudwego/hertz/pull/1317?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 72.79%. Comparing base [(`aeb2ae5`)](https://app.codecov.io/gh/cloudwego/hertz/commit/aeb2ae5b1b8d317f8d344499aca095bf466de772?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego) to head [(`57555b0`)](https://app.codecov.io/gh/cloudwego/hertz/commit/57555b0b9db42f5e495e7c030d971579a597b306?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego).

<details><summary>Additional details and impacted files</summary>


```diff
@@             Coverage Diff             @@
##           develop    #1317      +/-   ##
===========================================
+ Coverage    72.76%   72.79%   +0.02%     
===========================================
  Files          139      139              
  Lines        16239    16240       +1     
===========================================
+ Hits         11817    11822       +5     
+ Misses        3825     3823       -2     
+ Partials       597      595       -2     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/cloudwego/hertz/pull/1317?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>

Patch:
diff --git a/pkg/protocol/args.go b/pkg/protocol/args.go
index fa2a670..abdd1cb 100644
--- a/pkg/protocol/args.go
+++ b/pkg/protocol/args.go
@@ -54,8 +54,6 @@ const (
 	ArgsHasValue = false
 )
 
-var nilByteSlice = []byte{}
-
 type argsScanner struct {
 	b []byte
 }
@@ -167,9 +165,15 @@ func allocArg(h []argsKV) ([]argsKV, *argsKV) {
 	n := len(h)
 	if cap(h) > n {
 		h = h[:n+1]
-	} else {
-		h = append(h, argsKV{})
+		kv := &h[n]
+		if kv.value == nil {
+			// bytes in value would be reused, and it's not always nil
+			// only set to empty when it's nil
+			kv.value = []byte{}
+		}
+		return h, kv
 	}
+	h = append(h, argsKV{value: []byte{}})
 	return h, &h[n]
 }
 
@@ -228,10 +232,7 @@ func peekArgBytes(h []argsKV, k []byte) []byte {
 	for i, n := 0, len(h); i < n; i++ {
 		kv := &h[i]
 		if bytes.Equal(kv.key, k) {
-			if kv.value != nil {
-				return kv.value
-			}
-			return nilByteSlice
+			return kv.value
 		}
 	}
 	return nil
diff --git a/pkg/protocol/trailer.go b/pkg/protocol/trailer.go
index 6820f87..a701cf4 100644
--- a/pkg/protocol/trailer.go
+++ b/pkg/protocol/trailer.go
@@ -163,7 +163,7 @@ func (t *Trailer) SetTrailers(trailers []byte) (err error) {
 		}
 
 		utils.NormalizeHeaderKey(trailerKey, t.disableNormalizing)
-		err = t.addArgBytes(trailerKey, nilByteSlice, argsNoValue)
+		err = t.addArgBytes(trailerKey, nil, argsNoValue)
 	}
 	return
 }


Test patch:
diff --git a/pkg/network/netpoll/transport_test.go b/pkg/network/netpoll/transport_test.go
index bfac325..d6383eb 100644
--- a/pkg/network/netpoll/transport_test.go
+++ b/pkg/network/netpoll/transport_test.go
@@ -124,7 +124,7 @@ func TestTransport(t *testing.T) {
 	t.Run("TestExceptionCase", func(t *testing.T) {
 		assert.Panic(t, func() { // listen err
 			transporter := NewTransporter(&config.Options{
-				Network: "unknow",
+				Network: "unknown",
 			})
 			transporter.ListenAndServe(func(ctx context.Context, conn interface{}) error {
 				return nil
diff --git a/pkg/protocol/args_test.go b/pkg/protocol/args_test.go
index 0e89f30..70970a9 100644
--- a/pkg/protocol/args_test.go
+++ b/pkg/protocol/args_test.go
@@ -130,6 +130,37 @@ func TestArgsVisitAll(t *testing.T) {
 	assert.DeepEqual(t, []string{"cloudwego", "hertz", "hello", "world"}, s)
 }
 
+func TestArgsCopyTo(t *testing.T) {
+	var a Args
+	a.Add("cloudwego", "")
+	a.Add("hello", "world")
+
+	var b Args
+	a.CopyTo(&b)
+	assert.Assert(t, b.Len() == 2)
+	assert.Assert(t, a.Peek("cloudwego") != nil && len(a.Peek("cloudwego")) == 0)
+	assert.Assert(t, string(a.Peek("hello")) == "world")
+	assert.Assert(t, a.Peek("key-not-exists") == nil)
+}
+
+func TestArgsPeek(t *testing.T) {
+	var a Args
+	a.Add("cloudwego", "")
+	a.Add("hello", "world")
+
+	assert.Assert(t, a.Peek("cloudwego") != nil && len(a.Peek("cloudwego")) == 0)
+	assert.Assert(t, string(a.Peek("hello")) == "world")
+	assert.Assert(t, a.Peek("key-not-exists") == nil)
+
+	// reset and reuse
+	a.Reset()
+	a.Add("cloudwego", "")
+	a.Add("hello", "world")
+	assert.Assert(t, a.Peek("cloudwego") != nil && len(a.Peek("cloudwego")) == 0)
+	assert.Assert(t, string(a.Peek("hello")) == "world")
+	assert.Assert(t, a.Peek("key-not-exists") == nil)
+}
+
 func TestArgsPeekMulti(t *testing.T) {
 	var a Args
 	a.Add("cloudwego", "hertz")
@@ -141,7 +172,7 @@ func TestArgsPeekMulti(t *testing.T) {
 	expectedVV := [][]byte{
 		[]byte("hertz"),
 		[]byte("kitex"),
-		[]byte(nil),
+		[]byte{},
 	}
 	assert.DeepEqual(t, expectedVV, vv)