Repository: cloudwego/hertz
Pull request #404 (2022-11-21 08:20:17)

test: add more tests for pkg/app/context
#### What type of PR is this?
test: Adding missing tests or correcting existing tests
pkg/app/context test coverage increased from 68.6% to 73.8%
<!--
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:
-->
- [x] This PR title match the format: \<type\>(optional scope): \<description\>
- [x] The description of this PR title is user-oriented and clear enough for others to understand.


#### (Optional) Translate the PR title into Chinese.
为pkg/app/context添加更多测试

#### (Optional) More detail description for this PR(en: English/zh: Chinese).
en: Add tests for TraceInfo Get and Set operations for pkg/app/context
zh(optional): 为pkg/app/context添加TraceInfo读写操作的测试
<!--
Provide more detailed info for review. If it is a perf type PR, perf data is suggested to give.
-->


#### Which issue(s) this PR fixes:
#257 
<!--
Automatically closes linked issue when PR is merged.
Eg: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
-->


codecov[bot]: # [Codecov](https://codecov.io/gh/cloudwego/hertz/pull/404?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego) Report
Base: **67.53**% // Head: **67.57**% // Increases project coverage by **`+0.04%`** :tada:
> Coverage data is based on head [(`be4f2b8`)](https://codecov.io/gh/cloudwego/hertz/pull/404?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego) compared to base [(`d601515`)](https://codecov.io/gh/cloudwego/hertz/commit/d6015151ca9272b31da539e3a6503722dd9dfde4?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego).
> Patch has no changes to coverable lines.

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


```diff
@@             Coverage Diff             @@
##           develop     #404      +/-   ##
===========================================
+ Coverage    67.53%   67.57%   +0.04%     
===========================================
  Files           89       89              
  Lines         8608     8608              
===========================================
+ Hits          5813     5817       +4     
+ Misses        2435     2431       -4     
  Partials       360      360              
```


| [Impacted Files](https://codecov.io/gh/cloudwego/hertz/pull/404?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego) | Coverage Δ | |
|---|---|---|
| [pkg/app/context.go](https://codecov.io/gh/cloudwego/hertz/pull/404/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego#diff-cGtnL2FwcC9jb250ZXh0Lmdv) | `69.67% <0.00%> (+0.87%)` | :arrow_up: |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego)

</details>

[:umbrella: View full report at Codecov](https://codecov.io/gh/cloudwego/hertz/pull/404?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego).   
:loudspeaker: Do you have feedback about the report comment? [Let us know in this issue](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego).

welkeyever: Thanks for your committing! Please follow the template's rule in the PR description - maybe check the other PR in history.
mamil: @welkeyever description updated
CLAassistant: [![CLA assistant check](https://cla-assistant.io/pull/badge/not_signed)](https://cla-assistant.io/cloudwego/hertz?pullRequest=404) <br/>Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our [Contributor License Agreement](https://cla-assistant.io/cloudwego/hertz?pullRequest=404) before we can accept your contribution.<br/><sub>You have signed the CLA already but the status is still pending? Let us [recheck](https://cla-assistant.io/check/cloudwego/hertz?pullRequest=404) it.</sub>
li-jin-gou: @mamil  Hello [mamil](https://github.com/mamil) Would you like to increase the coverage to around 80%?
mamil: @li-jin-gou I will add more test cases in the future, but I think submitting too much code at one time will put pressure on the reviewer, what do you think?
li-jin-gou: > @li-jin-gou I will add more test cases in the future, but I think submitting too much code at one time will put pressure on the reviewer, what do you think?

Ok
mamil: @li-jin-gou coverage reached 73.8%, I think we should commit the code first.

Patch:
diff --git a/README.md b/README.md
index 554319c..387b2f4 100644
--- a/README.md
+++ b/README.md
@@ -58,32 +58,35 @@ Hertz [həːts] is a high-usability, high-performance and high-extensibility Gol
 - [Example](https://github.com/cloudwego/hertz-examples): Use examples of Hertz.
 ## Extensions
 
-| Extensions                                                                                         | Description                                                                                                                                                             |
-|----------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| [Websocket](https://github.com/hertz-contrib/websocket)                                            | Enable Hertz to support the Websocket protocol.                                                                                                                         |
-| [Pprof](https://github.com/hertz-contrib/pprof)                                                    | Extension for Hertz integration with Pprof.                                                                                                                             |
-| [Sessions](https://github.com/hertz-contrib/sessions)                                              | Session middleware with multi-state store support.                                                                                                                      |
-| [Obs-opentelemetry](https://github.com/hertz-contrib/obs-opentelemetry)                            | Hertz's Opentelemetry extension that supports Metric, Logger, Tracing and works out of the box.                                                                         |
+| Extensions                                                                                         | Description                                                                                                                                                                    |
+|----------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| [Autotls](https://github.com/hertz-contrib/autotls)                                                | Make Hertz support Let's Encrypt.                                                                                                                                              |
+| [Http2](https://github.com/hertz-contrib/http2)                                                    | HTTP2 support for Hertz.                                                                                                                                                       |
+| [Websocket](https://github.com/hertz-contrib/websocket)                                            | Enable Hertz to support the Websocket protocol.                                                                                                                                |
+| [Limiter](https://github.com/hertz-contrib/limiter)                                                | Provides a current limiter based on the bbr algorithm.                                                                                                                         |
+| [Monitor-prometheus](https://github.com/hertz-contrib/monitor-prometheus)                          | Provides service monitoring based on Prometheus.                                                                                                                               |
+| [Obs-opentelemetry](https://github.com/hertz-contrib/obs-opentelemetry)                            | Hertz's Opentelemetry extension that supports Metric, Logger, Tracing and works out of the box.                                                                                |
+| [Opensergo](https://github.com/hertz-contrib/opensergo)                                            | The Opensergo extension.                                                                                                                                                       |
+| [Pprof](https://github.com/hertz-contrib/pprof)                                                    | Extension for Hertz integration with Pprof.                                                                                                                                    |
 | [Registry](https://github.com/hertz-contrib/registry)                                              | Provides service registry and discovery functions. So far, the supported service discovery extensions are nacos, consul, etcd, eureka, polaris, servicecomb, zookeeper, redis. |
-| [Keyauth](https://github.com/hertz-contrib/keyauth)                                                | Provides token-based authentication.                                                                                                                                    |
-| [Secure](https://github.com/hertz-contrib/secure)                                                  | Secure middleware with multiple configuration items.                                                                                                                    |
-| [Sentry](https://github.com/hertz-contrib/hertzsentry)                                             | Sentry extension provides some unified interfaces to help users perform real-time error monitoring.                                                                     |
-| [Requestid](https://github.com/hertz-contrib/requestid)                                            | Add request id in response.                                                                                                                                             |
-| [Limiter](https://github.com/hertz-contrib/limiter)                                                | Provides a current limiter based on the bbr algorithm.                                                                                                                  |
-| [Jwt](https://github.com/hertz-contrib/jwt)                                                        | Jwt extension.                                                                                                                                                          |
-| [Autotls](https://github.com/hertz-contrib/autotls)                                                | Make Hertz support Let's Encrypt.                                                                                                                                       |
-| [Monitor-prometheus](https://github.com/hertz-contrib/monitor-prometheus)                          | Provides service monitoring based on Prometheus.                                                                                                                        |
-| [I18n](https://github.com/hertz-contrib/i18n)                                                      | Helps translate Hertz programs into multi programming languages.                                                                                                        |
-| [Reverseproxy](https://github.com/hertz-contrib/reverseproxy)                                      | Implement a reverse proxy.                                                                                                                                              |
-| [Opensergo](https://github.com/hertz-contrib/opensergo)                                            | The Opensergo extension.                                                                                                                                                |
-| [Gzip](https://github.com/hertz-contrib/gzip)                                                      | A Gzip extension with multiple options.                                                                                                                                 |
-| [Cors](https://github.com/hertz-contrib/cors)                                                      | Provides cross-domain resource sharing support.                                                                                                                         |
-| [Swagger](https://github.com/hertz-contrib/swagger)                                                | Automatically generate RESTful API documentation with Swagger 2.0.                                                                                                      |
-| [Tracer](https://github.com/hertz-contrib/tracer)                                                  | Link tracing based on Opentracing.                                                                                                                                      |
-| [Recovery](https://github.com/cloudwego/hertz/tree/develop/pkg/app/middlewares/server/recovery)    | Recovery middleware for Hertz.                                                                                                                                          |
-| [Basicauth](https://github.com/cloudwego/hertz/tree/develop/pkg/app/middlewares/server/basic_auth) | Basicauth middleware can provide HTTP basic authentication.                                                                                                             |
-| [Lark](https://github.com/hertz-contrib/lark-hertz)                                                | Use hertz handle Lark/Feishu card message and event callback.                                                                                                           |
-| [Logger](https://github.com/hertz-contrib/logger)                                                  | Logger extension for Hertz, which provides support for zap, logrus, zerologs logging frameworks.                                                                        |
+| [Sentry](https://github.com/hertz-contrib/hertzsentry)                                             | Sentry extension provides some unified interfaces to help users perform real-time error monitoring.                                                                            |
+| [Tracer](https://github.com/hertz-contrib/tracer)                                                  | Link tracing based on Opentracing.                                                                                                                                             |
+| [Basicauth](https://github.com/cloudwego/hertz/tree/develop/pkg/app/middlewares/server/basic_auth) | Basicauth middleware can provide HTTP basic authentication.                                                                                                                    |
+| [Jwt](https://github.com/hertz-contrib/jwt)                                                        | Jwt extension.                                                                                                                                                                 |
+| [Keyauth](https://github.com/hertz-contrib/keyauth)                                                | Provides token-based authentication.                                                                                                                                           |
+| [Requestid](https://github.com/hertz-contrib/requestid)                                            | Add request id in response.                                                                                                                                                    |
+| [Sessions](https://github.com/hertz-contrib/sessions)                                              | Session middleware with multi-state store support.                                                                                                                             |
+| [Cors](https://github.com/hertz-contrib/cors)                                                      | Provides cross-domain resource sharing support.                                                                                                                                |
+| [Csrf](https://github.com/hertz-contrib/csrf)                                                      | Csrf middleware is used to prevent cross-site request forgery attacks.                                                                                                         |
+| [Secure](https://github.com/hertz-contrib/secure)                                                  | Secure middleware with multiple configuration items.                                                                                                                           |
+| [Gzip](https://github.com/hertz-contrib/gzip)                                                      | A Gzip extension with multiple options.                                                                                                                                        |
+| [I18n](https://github.com/hertz-contrib/i18n)                                                      | Helps translate Hertz programs into multi programming languages.                                                                                                               |
+| [Lark](https://github.com/hertz-contrib/lark-hertz)                                                | Use hertz handle Lark/Feishu card message and event callback.                                                                                                                  |
+| [Loadbalance](https://github.com/hertz-contrib/loadbalance)                                        | Provides load balancing algorithms for Hertz.                                                                                                                                  |
+| [Logger](https://github.com/hertz-contrib/logger)                                                  | Logger extension for Hertz, which provides support for zap, logrus, zerologs logging frameworks.                                                                               |
+| [Recovery](https://github.com/cloudwego/hertz/tree/develop/pkg/app/middlewares/server/recovery)    | Recovery middleware for Hertz.                                                                                                                                                 |
+| [Reverseproxy](https://github.com/hertz-contrib/reverseproxy)                                      | Implement a reverse proxy.                                                                                                                                                     |
+| [Swagger](https://github.com/hertz-contrib/swagger)                                                | Automatically generate RESTful API documentation with Swagger 2.0.                                                                                                             |
 
 ## Blogs
 - [ByteDance Practice on Go Network Library](https://www.cloudwego.io/blog/2021/10/09/bytedance-practices-on-go-network-library/)
diff --git a/README_cn.md b/README_cn.md
index 942b743..2ca5823 100644
--- a/README_cn.md
+++ b/README_cn.md
@@ -58,32 +58,35 @@ Hertz[həːts] 是一个 Golang 微服务 HTTP 框架，在设计之初参考了
 - [Example](https://github.com/cloudwego/hertz-examples): Hertz 使用例子
 ## 相关拓展
 
-| 拓展                                                                                                 | 描述                                                                                         |
-|----------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------|
-| [Websocket](https://github.com/hertz-contrib/websocket)                                            | 使 Hertz 支持 Websocket 协议。                                                                   |
-| [Pprof](https://github.com/hertz-contrib/pprof)                                                    | Hertz 集成 Pprof 的扩展。                                                                        |
-| [Sessions](https://github.com/hertz-contrib/sessions)                                              | 具有多状态存储支持的 Session 中间件。                                                                    |
-| [Obs-opentelemetry](https://github.com/hertz-contrib/obs-opentelemetry)                            | Hertz 的 Opentelemetry 扩展，支持 Metric、Logger、Tracing并且达到开箱即用。                                 |
+| 拓展                                                                                                 | 描述                                                                                                |
+|----------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------|
+| [Autotls](https://github.com/hertz-contrib/autotls)                                                | 为 Hertz 支持 Let's Encrypt 。                                                                        |
+| [Http2](https://github.com/hertz-contrib/http2)                                                    | 提供对 HTTP2 的支持。                                                                                    |
+| [Websocket](https://github.com/hertz-contrib/websocket)                                            | 使 Hertz 支持 Websocket 协议。                                                                          |
+| [Limiter](https://github.com/hertz-contrib/limiter)                                                | 提供了基于 bbr 算法的限流器。                                                                                 |
+| [Monitor-prometheus](https://github.com/hertz-contrib/monitor-prometheus)                          | 提供基于 Prometheus 服务监控功能。                                                                           |
+| [Obs-opentelemetry](https://github.com/hertz-contrib/obs-opentelemetry)                            | Hertz 的 Opentelemetry 扩展，支持 Metric、Logger、Tracing并且达到开箱即用。                                        |
+| [Opensergo](https://github.com/hertz-contrib/opensergo)                                            | Opensergo 扩展。                                                                                     |
+| [Pprof](https://github.com/hertz-contrib/pprof)                                                    | Hertz 集成 Pprof 的扩展。                                                                               |
 | [Registry](https://github.com/hertz-contrib/registry)                                              | 提供服务注册与发现功能。到现在为止，支持的服务发现拓展有 nacos， consul， etcd， eureka， polaris， servicecomb， zookeeper， redis。 |
-| [Keyauth](https://github.com/hertz-contrib/keyauth)                                                | 提供基于 token 的身份验证。                                                                          |
-| [Secure](https://github.com/hertz-contrib/secure)                                                  | 具有多配置项的 Secure 中间件。                                                                        |
-| [Sentry](https://github.com/hertz-contrib/hertzsentry)                                             | Sentry 拓展提供了一些统一的接口来帮助用户进行实时的错误监控。                                                         |
-| [Requestid](https://github.com/hertz-contrib/requestid)                                            | 在 response 中添加 request id。                                                                 |
-| [Limiter](https://github.com/hertz-contrib/limiter)                                                | 提供了基于 bbr 算法的限流器。                                                                          |
-| [Jwt](https://github.com/hertz-contrib/jwt)                                                        | Jwt 拓展。                                                                                    |
-| [Autotls](https://github.com/hertz-contrib/autotls)                                                | 为 Hertz 支持 Let's Encrypt 。                                                                 |
-| [Monitor-prometheus](https://github.com/hertz-contrib/monitor-prometheus)                          | 提供基于 Prometheus 服务监控功能。                                                                    |
-| [I18n](https://github.com/hertz-contrib/i18n)                                                      | 可帮助将 Hertz 程序翻译成多种语言。                                                                      |
-| [Reverseproxy](https://github.com/hertz-contrib/reverseproxy)                                      | 实现反向代理。                                                                                    |
-| [Opensergo](https://github.com/hertz-contrib/opensergo)                                            | Opensergo 扩展。                                                                              |
-| [Gzip](https://github.com/hertz-contrib/gzip)                                                      | 含多个可选项的 Gzip 拓展。                                                                           |
-| [Cors](https://github.com/hertz-contrib/cors)                                                      | 提供跨域资源共享支持。                                                                                |
-| [Swagger](https://github.com/hertz-contrib/swagger)                                                | 使用 Swagger 2.0 自动生成 RESTful API 文档。                                                        |
-| [Tracer](https://github.com/hertz-contrib/tracer)                                                  | 基于 Opentracing 的链路追踪。                                                                      |
-| [Recovery](https://github.com/cloudwego/hertz/tree/develop/pkg/app/middlewares/server/recovery)    | Hertz 的异常恢复中间件。                                                                            |
-| [Basicauth](https://github.com/cloudwego/hertz/tree/develop/pkg/app/middlewares/server/basic_auth) | Basicauth 中间件能够提供 HTTP 基本身份验证。                                                             |
-| [Lark](https://github.com/hertz-contrib/lark-hertz)                                                | 在 Hertz 中处理 Lark/飞书的卡片消息和事件的回调。                                                            |
-| [Logger](https://github.com/hertz-contrib/logger)                                                  | Hertz 的日志拓展，提供了对 zap、logrus、zerologs 日志框架的支持。                                              |
+| [Sentry](https://github.com/hertz-contrib/hertzsentry)                                             | Sentry 拓展提供了一些统一的接口来帮助用户进行实时的错误监控。                                                                |
+| [Tracer](https://github.com/hertz-contrib/tracer)                                                  | 基于 Opentracing 的链路追踪。                                                                             |
+| [Basicauth](https://github.com/cloudwego/hertz/tree/develop/pkg/app/middlewares/server/basic_auth) | Basicauth 中间件能够提供 HTTP 基本身份验证。                                                                    |
+| [Jwt](https://github.com/hertz-contrib/jwt)                                                        | Jwt 拓展。                                                                                           |
+| [Keyauth](https://github.com/hertz-contrib/keyauth)                                                | 提供基于 token 的身份验证。                                                                                 |
+| [Requestid](https://github.com/hertz-contrib/requestid)                                            | 在 response 中添加 request id。                                                                        |
+| [Sessions](https://github.com/hertz-contrib/sessions)                                              | 具有多状态存储支持的 Session 中间件。                                                                           |
+| [Cors](https://github.com/hertz-contrib/cors)                                                      | 提供跨域资源共享支持。                                                                                       |
+| [Csrf](https://github.com/hertz-contrib/csrf)                                                      | Csrf 中间件用于防止跨站点请求伪造攻击。                                                                            |
+| [Secure](https://github.com/hertz-contrib/secure)                                                  | 具有多配置项的 Secure 中间件。                                                                               |
+| [Gzip](https://github.com/hertz-contrib/gzip)                                                      | 含多个可选项的 Gzip 拓展。                                                                                  |
+| [I18n](https://github.com/hertz-contrib/i18n)                                                      | 可帮助将 Hertz 程序翻译成多种语言。                                                                             |
+| [Lark](https://github.com/hertz-contrib/lark-hertz)                                                | 在 Hertz 中处理 Lark/飞书的卡片消息和事件的回调。                                                                   |
+| [Loadbalance](https://github.com/hertz-contrib/loadbalance)                                        | 提供适用于 Hertz 的负载均衡算法。                                                                              |
+| [Logger](https://github.com/hertz-contrib/logger)                                                  | Hertz 的日志拓展，提供了对 zap、logrus、zerologs 日志框架的支持。                                                     |
+| [Recovery](https://github.com/cloudwego/hertz/tree/develop/pkg/app/middlewares/server/recovery)    | Hertz 的异常恢复中间件。                                                                                   |
+| [Reverseproxy](https://github.com/hertz-contrib/reverseproxy)                                      | 实现反向代理。                                                                                           |
+| [Swagger](https://github.com/hertz-contrib/swagger)                                                | 使用 Swagger 2.0 自动生成 RESTful API 文档。                                                               |
 
 ## 相关文章
 - [字节跳动在 Go 网络库上的实践](https://www.cloudwego.io/blog/2021/10/09/bytedance-practices-on-go-network-library/)
diff --git a/pkg/app/server/hertz.go b/pkg/app/server/hertz.go
index 651b1ed..72a19c8 100644
--- a/pkg/app/server/hertz.go
+++ b/pkg/app/server/hertz.go
@@ -95,8 +95,13 @@ func (h *Hertz) SetCustomSignalWaiter(f func(err chan error) error) {
 // SIGTERM triggers immediately close.
 // SIGHUP|SIGINT triggers graceful shutdown.
 func waitSignal(errCh chan error) error {
+	signalToNotify := []os.Signal{syscall.SIGINT, syscall.SIGHUP, syscall.SIGTERM}
+	if signal.Ignored(syscall.SIGHUP) {
+		signalToNotify = []os.Signal{syscall.SIGINT, syscall.SIGTERM}
+	}
+
 	signals := make(chan os.Signal, 1)
-	signal.Notify(signals, syscall.SIGINT, syscall.SIGHUP, syscall.SIGTERM)
+	signal.Notify(signals, signalToNotify...)
 
 	select {
 	case sig := <-signals:
@@ -105,6 +110,7 @@ func waitSignal(errCh chan error) error {
 			// force exit
 			return errors.New(sig.String()) // nolint
 		case syscall.SIGHUP, syscall.SIGINT:
+			hlog.SystemLogger().Infof("Received signal: %s\n", sig)
 			// graceful shutdown
 			return nil
 		}
diff --git a/pkg/protocol/client/client.go b/pkg/protocol/client/client.go
index 33d7c39..e770547 100644
--- a/pkg/protocol/client/client.go
+++ b/pkg/protocol/client/client.go
@@ -220,7 +220,9 @@ func doRequestFollowRedirectsBuffer(ctx context.Context, req *protocol.Request,
 
 	statusCode, _, err = DoRequestFollowRedirects(ctx, req, resp, url, defaultMaxRedirectsCount, c)
 
-	body = bodyBuf.B
+	// In HTTP2 scenario, client use stream mode to create a request and its body is in body stream.
+	// In HTTP1, only client recv body exceed max body size and client is in stream mode can trig it.
+	body = resp.Body()
 	bodyBuf.B = oldBody
 	protocol.ReleaseResponse(resp)
 
diff --git a/pkg/protocol/http1/server.go b/pkg/protocol/http1/server.go
index 16a65b5..6ff8d7d 100644
--- a/pkg/protocol/http1/server.go
+++ b/pkg/protocol/http1/server.go
@@ -374,6 +374,8 @@ func writeResponse(ctx *app.RequestContext, w network.Writer) error {
 func defaultErrorHandler(ctx *app.RequestContext, err error) {
 	if netErr, ok := err.(*net.OpError); ok && netErr.Timeout() {
 		ctx.AbortWithMsg("Request timeout", consts.StatusRequestTimeout)
+	} else if errors.Is(err, errs.ErrBodyTooLarge) {
+		ctx.AbortWithMsg("Request Entity Too Large", consts.StatusRequestEntityTooLarge)
 	} else {
 		ctx.AbortWithMsg("Error when parsing request", consts.StatusBadRequest)
 	}
diff --git a/pkg/protocol/response.go b/pkg/protocol/response.go
index a170ffd..f46395b 100644
--- a/pkg/protocol/response.go
+++ b/pkg/protocol/response.go
@@ -193,6 +193,13 @@ func (resp *Response) SetBodyStream(bodyStream io.Reader, bodySize int) {
 	resp.Header.SetContentLength(bodySize)
 }
 
+// SetBodyStreamNoReset is almost the same as SetBodyStream,
+// but it doesn't reset the bodyStream before.
+func (resp *Response) SetBodyStreamNoReset(bodyStream io.Reader, bodySize int) {
+	resp.bodyStream = bodyStream
+	resp.Header.SetContentLength(bodySize)
+}
+
 // BodyE returns response body.
 func (resp *Response) BodyE() ([]byte, error) {
 	if resp.bodyStream != nil {
diff --git a/pkg/route/engine.go b/pkg/route/engine.go
index 94d6d22..0096eb5 100644
--- a/pkg/route/engine.go
+++ b/pkg/route/engine.go
@@ -353,10 +353,6 @@ func (engine *Engine) Run() (err error) {
 }
 
 func (engine *Engine) Init() error {
-	if !h2Enable(engine.options) {
-		engine.protocolSuite.Delete(suite.HTTP2)
-	}
-
 	// add built-in http1 server by default
 	if !engine.HasServer(suite.HTTP1) {
 		engine.AddProtocol(suite.HTTP1, factory.NewServerFactory(newHttp1OptionFromEngine(engine)))
@@ -371,7 +367,6 @@ func (engine *Engine) Init() error {
 
 	if engine.alpnEnable() {
 		engine.options.TLS.NextProtos = append(engine.options.TLS.NextProtos, suite.HTTP1)
-		engine.options.TLS.NextProtos = append(engine.options.TLS.NextProtos, suite.HTTP2)
 	}
 
 	if !atomic.CompareAndSwapUint32(&engine.status, 0, statusInitialized) {
@@ -584,10 +579,6 @@ func initTrace(engine *Engine) stats.Level {
 	return traceLevel
 }
 
-func h2Enable(opt *config.Options) bool {
-	return opt.H2C || (opt.TLS != nil && opt.ALPN)
-}
-
 func debugPrintRoute(httpMethod, absolutePath string, handlers app.HandlersChain) {
 	nuHandlers := len(handlers)
 	handlerName := app.GetHandlerName(handlers.Last())
diff --git a/version.go b/version.go
index 006b989..2f877ce 100644
--- a/version.go
+++ b/version.go
@@ -19,5 +19,5 @@ package hertz
 // Name and Version info of this framework, used for statistics and debug
 const (
 	Name    = "Hertz"
-	Version = "v0.4.1"
+	Version = "v0.4.2"
 )


Test patch:
diff --git a/pkg/app/client/client_test.go b/pkg/app/client/client_test.go
index 8c86aff..e325a0e 100644
--- a/pkg/app/client/client_test.go
+++ b/pkg/app/client/client_test.go
@@ -68,6 +68,7 @@ import (
 	"github.com/cloudwego/hertz/pkg/app/client/retry"
 	"github.com/cloudwego/hertz/pkg/common/config"
 	errs "github.com/cloudwego/hertz/pkg/common/errors"
+	"github.com/cloudwego/hertz/pkg/common/test/assert"
 	"github.com/cloudwego/hertz/pkg/network"
 	"github.com/cloudwego/hertz/pkg/network/dialer"
 	"github.com/cloudwego/hertz/pkg/network/netpoll"
@@ -193,6 +194,39 @@ func TestClientGetWithBody(t *testing.T) {
 	}
 }
 
+func TestClientPostBodyStream(t *testing.T) {
+	t.Parallel()
+
+	opt := config.NewOptions([]config.Option{})
+	opt.Addr = "unix-test-10102"
+	opt.Network = "unix"
+	engine := route.NewEngine(opt)
+	engine.POST("/", func(c context.Context, ctx *app.RequestContext) {
+		body := ctx.Request.Body()
+		ctx.Write(body) //nolint:errcheck
+	})
+	go engine.Run()
+	defer func() {
+		engine.Close()
+	}()
+	time.Sleep(time.Millisecond * 500)
+
+	cStream, _ := NewClient(WithDialer(newMockDialerWithCustomFunc(opt.Network, opt.Addr, 1*time.Second, nil)), WithResponseBodyStream(true))
+	args := &protocol.Args{}
+	// There is some data in databuf and others is in bodystream, so we need
+	// to let the data exceed the max bodysize of bodystream
+	v := ""
+	for i := 0; i < 10240; i++ {
+		v += "b"
+	}
+	args.Add("a", v)
+	_, body, err := cStream.Post(context.Background(), nil, "http://example.com", args)
+	if err != nil {
+		t.Fatal(err)
+	}
+	assert.DeepEqual(t, "a="+v, string(body))
+}
+
 func TestClientURLAuth(t *testing.T) {
 	t.Parallel()
 
diff --git a/pkg/app/client/discovery/discovery_test.go b/pkg/app/client/discovery/discovery_test.go
new file mode 100644
index 0000000..50242c6
--- /dev/null
+++ b/pkg/app/client/discovery/discovery_test.go
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2022 CloudWeGo Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package discovery
+
+import (
+	"context"
+	"testing"
+
+	"github.com/cloudwego/hertz/pkg/app/server/registry"
+	"github.com/cloudwego/hertz/pkg/common/test/assert"
+)
+
+func TestInstance(t *testing.T) {
+	network := "192.168.1.1"
+	address := "/hello"
+	weight := 1
+	instance := NewInstance(network, address, weight, nil)
+
+	assert.DeepEqual(t, network, instance.Address().Network())
+	assert.DeepEqual(t, address, instance.Address().String())
+	assert.DeepEqual(t, weight, instance.Weight())
+	val, ok := instance.Tag("name")
+	assert.DeepEqual(t, "", val)
+	assert.False(t, ok)
+
+	instance2 := NewInstance("", "", 0, nil)
+	assert.DeepEqual(t, registry.DefaultWeight, instance2.Weight())
+}
+
+func TestSynthesizedResolver(t *testing.T) {
+	targetFunc := func(ctx context.Context, target *TargetInfo) string {
+		return "hello"
+	}
+	resolveFunc := func(ctx context.Context, key string) (Result, error) {
+		return Result{CacheKey: "name"}, nil
+	}
+	nameFunc := func() string {
+		return "raymonder"
+	}
+	resolver := SynthesizedResolver{
+		TargetFunc:  targetFunc,
+		ResolveFunc: resolveFunc,
+		NameFunc:    nameFunc,
+	}
+
+	assert.DeepEqual(t, "hello", resolver.Target(context.Background(), &TargetInfo{}))
+	res, err := resolver.Resolve(context.Background(), "")
+	assert.DeepEqual(t, "name", res.CacheKey)
+	assert.Nil(t, err)
+	assert.DeepEqual(t, "raymonder", resolver.Name())
+
+	resolver2 := SynthesizedResolver{
+		TargetFunc:  nil,
+		ResolveFunc: nil,
+		NameFunc:    nil,
+	}
+	assert.DeepEqual(t, "", resolver2.Target(context.Background(), &TargetInfo{}))
+	assert.DeepEqual(t, "", resolver2.Name())
+}
diff --git a/pkg/app/client/retry/retry_test.go b/pkg/app/client/retry/retry_test.go
new file mode 100644
index 0000000..c77c4f0
--- /dev/null
+++ b/pkg/app/client/retry/retry_test.go
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2022 CloudWeGo Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package retry
+
+import (
+	"math"
+	"testing"
+	"time"
+
+	"github.com/cloudwego/hertz/pkg/common/test/assert"
+)
+
+func TestApply(t *testing.T) {
+	delayPolicyFunc := func(attempts uint, err error, retryConfig *Config) time.Duration {
+		return time.Second
+	}
+	options := []Option{}
+	options = append(options, WithMaxAttemptTimes(100), WithInitDelay(time.Second),
+		WithMaxDelay(time.Second), WithDelayPolicy(delayPolicyFunc), WithMaxJitter(time.Second))
+
+	config := Config{}
+	config.Apply(options)
+
+	assert.DeepEqual(t, uint(100), config.MaxAttemptTimes)
+	assert.DeepEqual(t, time.Second, config.Delay)
+	assert.DeepEqual(t, time.Second, config.MaxDelay)
+	assert.DeepEqual(t, time.Second, Delay(0, nil, &config))
+	assert.DeepEqual(t, time.Second, config.MaxJitter)
+}
+
+func TestPolicy(t *testing.T) {
+	dur := DefaultDelayPolicy(0, nil, nil)
+	assert.DeepEqual(t, 0*time.Millisecond, dur)
+
+	config := Config{
+		Delay: time.Second,
+	}
+	dur = FixedDelayPolicy(0, nil, &config)
+	assert.DeepEqual(t, time.Second, dur)
+
+	dur = RandomDelayPolicy(0, nil, &config)
+	assert.DeepEqual(t, 0*time.Millisecond, dur)
+	config.MaxJitter = time.Second * 1
+	dur = RandomDelayPolicy(0, nil, &config)
+	assert.NotEqual(t, time.Second*1, dur)
+
+	dur = BackOffDelayPolicy(0, nil, &config)
+	assert.DeepEqual(t, time.Second*1, dur)
+	config.Delay = time.Duration(-1)
+	dur = BackOffDelayPolicy(0, nil, &config)
+	assert.DeepEqual(t, time.Second*0, dur)
+	config.Delay = time.Duration(1)
+	dur = BackOffDelayPolicy(63, nil, &config)
+	durExp := config.Delay << 62
+	assert.DeepEqual(t, durExp, dur)
+
+	dur = Delay(0, nil, &config)
+	assert.DeepEqual(t, 0*time.Millisecond, dur)
+	delayPolicyFunc := func(attempts uint, err error, retryConfig *Config) time.Duration {
+		return time.Second
+	}
+	config.DelayPolicy = delayPolicyFunc
+	config.MaxDelay = time.Second / 2
+	dur = Delay(0, nil, &config)
+	assert.DeepEqual(t, config.MaxDelay, dur)
+
+	delayPolicyFunc2 := func(attempts uint, err error, retryConfig *Config) time.Duration {
+		return time.Duration(math.MaxInt64)
+	}
+	delayFunc := CombineDelay(delayPolicyFunc2, delayPolicyFunc)
+	dur = delayFunc(0, nil, &config)
+	assert.DeepEqual(t, time.Duration(math.MaxInt64), dur)
+}
diff --git a/pkg/app/context_test.go b/pkg/app/context_test.go
index 2e55eeb..6161506 100644
--- a/pkg/app/context_test.go
+++ b/pkg/app/context_test.go
@@ -21,6 +21,7 @@ import (
 	"errors"
 	"fmt"
 	"io/ioutil"
+	"reflect"
 	"strings"
 	"testing"
 	"time"
@@ -32,7 +33,9 @@ import (
 	"github.com/cloudwego/hertz/pkg/common/test/assert"
 	"github.com/cloudwego/hertz/pkg/common/test/mock"
 	"github.com/cloudwego/hertz/pkg/common/testdata/proto"
+	"github.com/cloudwego/hertz/pkg/common/tracer/traceinfo"
 	"github.com/cloudwego/hertz/pkg/common/utils"
+	"github.com/cloudwego/hertz/pkg/network"
 	"github.com/cloudwego/hertz/pkg/protocol"
 	"github.com/cloudwego/hertz/pkg/protocol/consts"
 	"github.com/cloudwego/hertz/pkg/protocol/http1/req"
@@ -135,6 +138,23 @@ func TestNotFound(t *testing.T) {
 	}
 }
 
+func TestRedirect(t *testing.T) {
+	ctx := NewContext(0)
+	ctx.Redirect(302, []byte("/hello"))
+	assert.DeepEqual(t, 302, ctx.Response.StatusCode())
+
+	ctx.redirect([]byte("/hello"), 301)
+	assert.DeepEqual(t, 301, ctx.Response.StatusCode())
+}
+
+func TestGetRedirectStatusCode(t *testing.T) {
+	val := getRedirectStatusCode(301)
+	assert.DeepEqual(t, 301, val)
+
+	val = getRedirectStatusCode(404)
+	assert.DeepEqual(t, 302, val)
+}
+
 func TestCookie(t *testing.T) {
 	ctx := NewContext(0)
 	ctx.Request.Header.SetCookie("cookie", "test cookie")
@@ -171,6 +191,15 @@ func TestPost(t *testing.T) {
 	}
 }
 
+func TestGet(t *testing.T) {
+	ctx := NewContext(0)
+	ctx.Request.Header.SetMethod(consts.MethodPost)
+	assert.False(t, ctx.IsGet())
+
+	ctx.Request.Header.SetMethod(consts.MethodGet)
+	assert.True(t, ctx.IsGet())
+}
+
 func TestCopy(t *testing.T) {
 	t.Parallel()
 	ctx := NewContext(0)
@@ -311,6 +340,36 @@ hello=world`)
 	}
 }
 
+func TestDefaultPostForm(t *testing.T) {
+	ctx := makeCtxByReqString(t, `POST /upload HTTP/1.1
+Host: localhost:10000
+Content-Length: 521
+Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryJwfATyF8tmxSJnLg
+
+------WebKitFormBoundaryJwfATyF8tmxSJnLg
+Content-Disposition: form-data; name="f1"
+
+value1
+------WebKitFormBoundaryJwfATyF8tmxSJnLg
+Content-Disposition: form-data; name="fileaaa"; filename="TODO"
+Content-Type: application/octet-stream
+
+- SessionClient with referer and cookies support.
+- Client with requests' pipelining support.
+- ProxyHandler similar to FSHandler.
+- WebSockets. See https://tools.ietf.org/html/rfc6455 .
+- HTTP/2.0. See https://tools.ietf.org/html/rfc7540 .
+
+------WebKitFormBoundaryJwfATyF8tmxSJnLg--
+`)
+
+	val := ctx.DefaultPostForm("f1", "no val")
+	assert.DeepEqual(t, "value1", val)
+
+	val = ctx.DefaultPostForm("f99", "no val")
+	assert.DeepEqual(t, "no val", val)
+}
+
 func TestRequestContext_FormFile(t *testing.T) {
 	t.Parallel()
 
@@ -497,6 +556,17 @@ func TestRequestContext_Handler(t *testing.T) {
 	}
 }
 
+func TestRequestContext_Handlers(t *testing.T) {
+	c := NewContext(0)
+	hc := HandlersChain{testFunc, testFunc2}
+	c.SetHandlers(hc)
+	c.Handlers()[1](context.Background(), c)
+	val := c.GetString("key")
+	if val != "123" {
+		t.Fatalf("unexpected %v. Expecting %v", val, "123")
+	}
+}
+
 func TestRequestContext_HandlerName(t *testing.T) {
 	c := NewContext(0)
 	c.handlers = HandlersChain{testFunc, testFunc2}
@@ -617,6 +687,14 @@ func TestClientIp(t *testing.T) {
 	}
 }
 
+func TestSetClientIPFunc(t *testing.T) {
+	fn := func(ctx *RequestContext) string {
+		return ""
+	}
+	SetClientIPFunc(fn)
+	assert.DeepEqual(t, reflect.ValueOf(fn).Pointer(), reflect.ValueOf(defaultClientIP).Pointer())
+}
+
 func TestGetQuery(t *testing.T) {
 	c := NewContext(0)
 	c.Request.SetRequestURI("http://aaa.com?a=1&b=")
@@ -906,6 +984,131 @@ func TestContextGetStringMapStringSlice(t *testing.T) {
 	assert.DeepEqual(t, expected, c.GetStringMapStringSlice("string"))
 }
 
+func TestContextTraceInfo(t *testing.T) {
+	ctx := NewContext(0)
+	traceIn := traceinfo.NewTraceInfo()
+	ctx.SetTraceInfo(traceIn)
+	traceOut := ctx.GetTraceInfo()
+
+	assert.DeepEqual(t, traceIn, traceOut)
+}
+
+func TestEnableTrace(t *testing.T) {
+	ctx := NewContext(0)
+	ctx.SetEnableTrace(true)
+	trace := ctx.IsEnableTrace()
+	assert.True(t, trace)
+}
+
+func TestForEachKey(t *testing.T) {
+	ctx := NewContext(0)
+	ctx.Set("1", "2")
+	handle := func(k string, v interface{}) {
+		res := k + v.(string)
+		assert.DeepEqual(t, res, "12")
+	}
+	ctx.ForEachKey(handle)
+	val, ok := ctx.Get("1")
+	assert.DeepEqual(t, val, "2")
+	assert.True(t, ok)
+}
+
+func TestHijackHandler(t *testing.T) {
+	ctx := NewContext(0)
+	handle := func(c network.Conn) {
+		c.SetReadTimeout(time.Duration(1) * time.Second)
+	}
+	ctx.SetHijackHandler(handle)
+	handleRes := ctx.GetHijackHandler()
+
+	val1 := reflect.ValueOf(handle).Pointer()
+	val2 := reflect.ValueOf(handleRes).Pointer()
+	assert.DeepEqual(t, val1, val2)
+}
+
+func TestIndex(t *testing.T) {
+	ctx := NewContext(0)
+	ctx.ResetWithoutConn()
+	res := ctx.GetIndex()
+	exc := int8(-1)
+	assert.DeepEqual(t, exc, res)
+}
+
+func TestHandlerName(t *testing.T) {
+	h := func(c context.Context, ctx *RequestContext) {}
+	SetHandlerName(h, "test")
+	name := GetHandlerName(h)
+	assert.DeepEqual(t, "test", name)
+}
+
+func TestHijack(t *testing.T) {
+	ctx := NewContext(0)
+	h := func(c network.Conn) {}
+	ctx.Hijack(h)
+	assert.True(t, ctx.Hijacked())
+}
+
+func TestFinished(t *testing.T) {
+	ctx := NewContext(0)
+	ctx.Finished()
+
+	ch := make(chan struct{})
+	ctx.finished = ch
+	chRes := ctx.Finished()
+
+	send := func() {
+		time.Sleep(time.Duration(1) * time.Millisecond)
+		ch <- struct{}{}
+	}
+	go send()
+	val := <-chRes
+	assert.DeepEqual(t, struct{}{}, val)
+}
+
+func TestString(t *testing.T) {
+	ctx := NewContext(0)
+	ctx.String(200, "ok")
+	assert.DeepEqual(t, 200, ctx.Response.StatusCode())
+}
+
+func TestFullPath(t *testing.T) {
+	ctx := NewContext(0)
+	str := "/hello"
+	ctx.SetFullPath(str)
+	val := ctx.FullPath()
+	assert.DeepEqual(t, str, val)
+}
+
+func TestReset(t *testing.T) {
+	ctx := NewContext(0)
+	ctx.Reset()
+	assert.DeepEqual(t, nil, ctx.conn)
+}
+
+// func TestParam(t *testing.T) {
+// 	ctx := NewContext(0)
+// 	val := ctx.Param("/user/john")
+// 	assert.DeepEqual(t, "john", val)
+// }
+
+func TestGetHeader(t *testing.T) {
+	ctx := NewContext(0)
+	ctx.Request.Header.SetContentTypeBytes([]byte("text/plain; charset=utf-8"))
+	val := ctx.GetHeader("Content-Type")
+	assert.DeepEqual(t, "text/plain; charset=utf-8", string(val))
+}
+
+func TestGetRawData(t *testing.T) {
+	ctx := NewContext(0)
+	ctx.Request.SetBody([]byte("hello"))
+	val := ctx.GetRawData()
+	assert.DeepEqual(t, "hello", string(val))
+
+	val2, err := ctx.Body()
+	assert.DeepEqual(t, val, val2)
+	assert.Nil(t, err)
+}
+
 func TestRequestContext_GetRequest(t *testing.T) {
 	c := &RequestContext{}
 	c.Request.Header.Set("key1", "value1")
diff --git a/pkg/app/server/hertz_test.go b/pkg/app/server/hertz_test.go
index 80ddc0c..f15db14 100644
--- a/pkg/app/server/hertz_test.go
+++ b/pkg/app/server/hertz_test.go
@@ -23,6 +23,7 @@ import (
 	"fmt"
 	"html/template"
 	"io"
+	"io/ioutil"
 	"net"
 	"net/http"
 	"os"
@@ -379,8 +380,11 @@ func TestNotEnoughBodySize(t *testing.T) {
 	r.ParseForm()
 	r.Form.Add("xxxxxx", "xxx")
 	body := strings.NewReader(r.Form.Encode())
-	resp, _ := http.Post("http://127.0.0.1:8889/test", "application/x-www-form-urlencoded", body)
-	assert.DeepEqual(t, 400, resp.StatusCode)
+	resp, err := http.Post("http://127.0.0.1:8889/test", "application/x-www-form-urlencoded", body)
+	assert.Nil(t, err)
+	assert.DeepEqual(t, 413, resp.StatusCode)
+	bodyBytes, _ := ioutil.ReadAll(resp.Body)
+	assert.DeepEqual(t, "Request Entity Too Large", string(bodyBytes))
 }
 
 func TestEnoughBodySize(t *testing.T) {
diff --git a/pkg/protocol/response_test.go b/pkg/protocol/response_test.go
index 7195eec..4f2f56e 100644
--- a/pkg/protocol/response_test.go
+++ b/pkg/protocol/response_test.go
@@ -229,3 +229,30 @@ func TestResponseAcquireResponse(t *testing.T) {
 	ReleaseResponse(resp1)
 	assert.Nil(t, resp1.body)
 }
+
+type closeBuffer struct {
+	*bytes.Buffer
+}
+
+func (b *closeBuffer) Close() error {
+	b.Reset()
+	return nil
+}
+
+func TestSetBodyStreamNoReset(t *testing.T) {
+	t.Parallel()
+	resp := Response{}
+	bsA := &closeBuffer{bytes.NewBufferString("A")}
+	bsB := &closeBuffer{bytes.NewBufferString("B")}
+	bsC := &closeBuffer{bytes.NewBufferString("C")}
+
+	resp.SetBodyStream(bsA, 1)
+	resp.SetBodyStreamNoReset(bsB, 1)
+	// resp.Body() has closed bsB
+	assert.DeepEqual(t, string(resp.Body()), "B")
+	assert.DeepEqual(t, bsA.String(), "A")
+
+	resp.bodyStream = bsA
+	resp.SetBodyStream(bsC, 1)
+	assert.DeepEqual(t, bsA.String(), "")
+}