Repository: cloudwego/hertz
Pull request #430 (2022-11-28 08:06:29)

optimize(http1): return 413 status code if request body is too large
#### What type of PR is this?
optimize

#### Check the PR title.
- [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.
如果请求body体超出限制，则返回 413 状态码

#### (Optional) More detail description for this PR(en: English/zh: Chinese).
en: server will return 413 error and with a body to describe the reason instead of 400 if request body size exceed the limit.
zh(optional): 如果请求正文大小超过限制，服务器将返回 413 错误并使用正文来描述原因而不是 400 解析错误。

#### Which issue(s) this PR fixes:


codecov[bot]: # [Codecov](https://codecov.io/gh/cloudwego/hertz/pull/430?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego) Report
Base: **68.14**% // Head: **68.07**% // Decreases project coverage by **`-0.06%`** :warning:
> Coverage data is based on head [(`02341ef`)](https://codecov.io/gh/cloudwego/hertz/pull/430?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego) compared to base [(`d39a818`)](https://codecov.io/gh/cloudwego/hertz/commit/d39a8186de8aaaabc10d1bd9eac4fedc7c30cd29?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego).
> Patch coverage: 0.00% of modified lines in pull request are covered.

> :exclamation: Current head 02341ef differs from pull request most recent head 297f673. Consider uploading reports for the commit 297f673 to get more accurate results

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


```diff
@@             Coverage Diff             @@
##           develop     #430      +/-   ##
===========================================
- Coverage    68.14%   68.07%   -0.07%     
===========================================
  Files           90       90              
  Lines         8632     8634       +2     
===========================================
- Hits          5882     5878       -4     
- Misses        2389     2395       +6     
  Partials       361      361              
```


| [Impacted Files](https://codecov.io/gh/cloudwego/hertz/pull/430?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego) | Coverage Δ | |
|---|---|---|
| [pkg/protocol/http1/server.go](https://codecov.io/gh/cloudwego/hertz/pull/430/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego#diff-cGtnL3Byb3RvY29sL2h0dHAxL3NlcnZlci5nbw==) | `0.00% <0.00%> (ø)` | |
| [pkg/common/timer/timer.go](https://codecov.io/gh/cloudwego/hertz/pull/430/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego#diff-cGtnL2NvbW1vbi90aW1lci90aW1lci5nbw==) | `61.90% <0.00%> (-19.05%)` | :arrow_down: |

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/430?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).


Patch:
diff --git a/README.md b/README.md
index 554319c..ab5c28c 100644
--- a/README.md
+++ b/README.md
@@ -58,32 +58,34 @@ 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                                                                                                                                                                    |
+|----------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| [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.                                                                                |
 | [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.                                                                        |
+| [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.                                                                               |
+| [Csrf](https://github.com/hertz-contrib/csrf)                                                      | Csrf middleware is used to prevent cross-site request forgery attacks.                                                                                                         |
+| [Loadbalance](https://github.com/hertz-contrib/loadbalance)                                        | Provides load balancing algorithms for Hertz.                                                                                                                                  |
 
 ## 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..be60589 100644
--- a/README_cn.md
+++ b/README_cn.md
@@ -58,32 +58,34 @@ 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并且达到开箱即用。                                 |
+| 拓展                                                                                                 | 描述                                                                                                |
+|----------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------|
+| [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并且达到开箱即用。                                        |
 | [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 日志框架的支持。                                              |
+| [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 日志框架的支持。                                                     |
+| [Csrf](https://github.com/hertz-contrib/csrf)                                                      | Csrf 中间件用于防止跨站点请求伪造攻击。                                                                            |
+| [Loadbalance](https://github.com/hertz-contrib/loadbalance)                                        | 提供适用于 Hertz 的负载均衡算法。                                                                              |
 
 ## 相关文章
 - [字节跳动在 Go 网络库上的实践](https://www.cloudwego.io/blog/2021/10/09/bytedance-practices-on-go-network-library/)
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())


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/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/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(), "")
+}