Repository: cloudwego/hertz
Pull request #412 (2022-11-23 09:41:30)

optimize(http1): try parse response even if get writing errors
#### 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.
HTTP/1.1 client场景，尝试在写请求失败后做一次响应体解析


#### (Optional) More detail description for this PR(en: English/zh: Chinese).
<!--
Provide more detailed info for review. If it is a perf type PR, perf data is suggested to give.
-->
en: For now, when hertz client is processing http/1.1 requests, if the connection is closed by the peer during the process of writing body, it will directly return the broken pipe error to the caller (the caller is actually confused when he gets this error) , this case often occurs in the scenario of writing an oversized packet that exceeds the size allowed by the server. Generally, the server side decides not to continue receiving packets after parsing the header. Generally, a 400 error & a body will be written back, and then The connection is closed. This optimization strategy is to make a parsing attempt of the response before returning the error to the caller for the case of writing half of the error. If a valid response is obtained, the response will be returned first instead of the bare connection error message.
zh(optional): 目前hertz client 在处理http/1.1的请求的时候如果在写body的过程中，连接就被对端关闭了会直接将broken pipe 报错返回给调用者（调用者拿到这个错误其实是比较迷茫的），这个case 常出现在写一个超大包，超出server允许的大小的场景，一般是server侧解析完header之后决定不再继续收包了，一般会写回一个400的错误 + 一个body文案，之后就关闭连接了。Client 的优化的策略是，针对这种写一半报错的case，在返回错误给调用者之前，做一次response的解析尝试，如果拿到一个valid的response，优先返回这个response而不是裸的连接错误信息。

#### Which issue(s) this PR fixes:
None

CLAassistant: [![CLA assistant check](https://cla-assistant.io/pull/badge/not_signed)](https://cla-assistant.io/cloudwego/hertz?pullRequest=412) <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=412) 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=412) it.</sub>
codecov[bot]: # [Codecov](https://codecov.io/gh/cloudwego/hertz/pull/412?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego) Report
Base: **67.62**% // Head: **67.64**% // Increases project coverage by **`+0.02%`** :tada:
> Coverage data is based on head [(`f0369a1`)](https://codecov.io/gh/cloudwego/hertz/pull/412?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego) compared to base [(`ec2ec49`)](https://codecov.io/gh/cloudwego/hertz/commit/ec2ec4991db9f05df5195fa0a59a4ea8bcef17f8?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego).
> Patch coverage: 50.00% of modified lines in pull request are covered.

> :exclamation: Current head f0369a1 differs from pull request most recent head 4172f8b. Consider uploading reports for the commit 4172f8b to get more accurate results

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


```diff
@@             Coverage Diff             @@
##           develop     #412      +/-   ##
===========================================
+ Coverage    67.62%   67.64%   +0.02%     
===========================================
  Files           89       89              
  Lines         8608     8627      +19     
===========================================
+ Hits          5821     5836      +15     
- Misses        2427     2432       +5     
+ Partials       360      359       -1     
```


| [Impacted Files](https://codecov.io/gh/cloudwego/hertz/pull/412?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego) | Coverage Δ | |
|---|---|---|
| [pkg/common/errors/errors.go](https://codecov.io/gh/cloudwego/hertz/pull/412/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego#diff-cGtnL2NvbW1vbi9lcnJvcnMvZXJyb3JzLmdv) | `87.95% <ø> (ø)` | |
| [pkg/network/netpoll/connection.go](https://codecov.io/gh/cloudwego/hertz/pull/412/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego#diff-cGtnL25ldHdvcmsvbmV0cG9sbC9jb25uZWN0aW9uLmdv) | `80.48% <0.00%> (-8.71%)` | :arrow_down: |
| [pkg/network/standard/connection.go](https://codecov.io/gh/cloudwego/hertz/pull/412/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego#diff-cGtnL25ldHdvcmsvc3RhbmRhcmQvY29ubmVjdGlvbi5nbw==) | `80.06% <20.00%> (-1.05%)` | :arrow_down: |
| [pkg/protocol/http1/client.go](https://codecov.io/gh/cloudwego/hertz/pull/412/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego#diff-cGtnL3Byb3RvY29sL2h0dHAxL2NsaWVudC5nbw==) | `51.00% <81.81%> (+1.72%)` | :arrow_up: |
| [pkg/common/compress/compress.go](https://codecov.io/gh/cloudwego/hertz/pull/412/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego#diff-cGtnL2NvbW1vbi9jb21wcmVzcy9jb21wcmVzcy5nbw==) | `80.95% <0.00%> (-2.86%)` | :arrow_down: |
| [pkg/common/timer/timer.go](https://codecov.io/gh/cloudwego/hertz/pull/412/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego#diff-cGtnL2NvbW1vbi90aW1lci90aW1lci5nbw==) | `80.95% <0.00%> (+19.04%)` | :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/412?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: Update:
1. Add a protection read timeout to avoid potential infinite loop. 
2. Adjust the non-sendfile error using standard network when writing request.

PTAL @wzekin @FGYFFFF @li-jin-gou 

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/client/client.go b/pkg/app/client/client.go
index 99d32a5..3fd2571 100644
--- a/pkg/app/client/client.go
+++ b/pkg/app/client/client.go
@@ -116,7 +116,8 @@ func Do(ctx context.Context, req *protocol.Request, resp *protocol.Response) err
 // Warning: DoTimeout does not terminate the request itself. The request will
 // continue in the background and the response will be discarded.
 // If requests take too long and the connection pool gets filled up please
-// try using a Client and setting a ReadTimeout.
+// try using a customized Client instance with a ReadTimeout config or set the request level read timeout like:
+// `req.SetOptions(config.WithReadTimeout(1 * time.Second))`
 func DoTimeout(ctx context.Context, req *protocol.Request, resp *protocol.Response, timeout time.Duration) error {
 	return defaultClient.DoTimeout(ctx, req, resp, timeout)
 }
@@ -144,6 +145,12 @@ func DoTimeout(ctx context.Context, req *protocol.Request, resp *protocol.Respon
 //
 // It is recommended obtaining req and resp via AcquireRequest
 // and AcquireResponse in performance-critical code.
+//
+// Warning: DoDeadline does not terminate the request itself. The request will
+// continue in the background and the response will be discarded.
+// If requests take too long and the connection pool gets filled up please
+// try using a customized Client instance with a ReadTimeout config or set the request level read timeout like:
+// `req.SetOptions(config.WithReadTimeout(1 * time.Second))`
 func DoDeadline(ctx context.Context, req *protocol.Request, resp *protocol.Response, deadline time.Time) error {
 	return defaultClient.DoDeadline(ctx, req, resp, deadline)
 }
@@ -178,8 +185,9 @@ func DoRedirects(ctx context.Context, req *protocol.Request, resp *protocol.Resp
 // is too small a new slice will be allocated.
 //
 // The function follows redirects. Use Do* for manually handling redirects.
-func Get(ctx context.Context, dst []byte, url string) (statusCode int, body []byte, err error) {
-	return defaultClient.Get(ctx, dst, url)
+//
+func Get(ctx context.Context, dst []byte, url string, requestOptions ...config.RequestOption) (statusCode int, body []byte, err error) {
+	return defaultClient.Get(ctx, dst, url, requestOptions...)
 }
 
 // GetTimeout returns the status code and body of url.
@@ -191,8 +199,14 @@ func Get(ctx context.Context, dst []byte, url string) (statusCode int, body []by
 //
 // errTimeout error is returned if url contents couldn't be fetched
 // during the given timeout.
-func GetTimeout(ctx context.Context, dst []byte, url string, timeout time.Duration) (statusCode int, body []byte, err error) {
-	return defaultClient.GetTimeout(ctx, dst, url, timeout)
+//
+// Warning: GetTimeout does not terminate the request itself. The request will
+// continue in the background and the response will be discarded.
+// If requests take too long and the connection pool gets filled up please
+// try using a customized Client instance with a ReadTimeout config or set the request level read timeout like:
+// `GetTimeout(ctx, dst, url, timeout, config.WithReadTimeout(1 * time.Second))`
+func GetTimeout(ctx context.Context, dst []byte, url string, timeout time.Duration, requestOptions ...config.RequestOption) (statusCode int, body []byte, err error) {
+	return defaultClient.GetTimeout(ctx, dst, url, timeout, requestOptions...)
 }
 
 // GetDeadline returns the status code and body of url.
@@ -204,8 +218,14 @@ func GetTimeout(ctx context.Context, dst []byte, url string, timeout time.Durati
 //
 // errTimeout error is returned if url contents couldn't be fetched
 // until the given deadline.
-func GetDeadline(ctx context.Context, dst []byte, url string, deadline time.Time) (statusCode int, body []byte, err error) {
-	return defaultClient.GetDeadline(ctx, dst, url, deadline)
+//
+// Warning: GetDeadline does not terminate the request itself. The request will
+// continue in the background and the response will be discarded.
+// If requests take too long and the connection pool gets filled up please
+// try using a customized Client instance with a ReadTimeout config or set the request level read timeout like:
+// `GetDeadline(ctx, dst, url, timeout, config.WithReadTimeout(1 * time.Second))`
+func GetDeadline(ctx context.Context, dst []byte, url string, deadline time.Time, requestOptions ...config.RequestOption) (statusCode int, body []byte, err error) {
+	return defaultClient.GetDeadline(ctx, dst, url, deadline, requestOptions...)
 }
 
 // Post sends POST request to the given url with the given POST arguments.
@@ -216,8 +236,8 @@ func GetDeadline(ctx context.Context, dst []byte, url string, deadline time.Time
 // The function follows redirects. Use Do* for manually handling redirects.
 //
 // Empty POST body is sent if postArgs is nil.
-func Post(ctx context.Context, dst []byte, url string, postArgs *protocol.Args) (statusCode int, body []byte, err error) {
-	return defaultClient.Post(ctx, dst, url, postArgs)
+func Post(ctx context.Context, dst []byte, url string, postArgs *protocol.Args, requestOptions ...config.RequestOption) (statusCode int, body []byte, err error) {
+	return defaultClient.Post(ctx, dst, url, postArgs, requestOptions...)
 }
 
 var defaultClient, _ = NewClient(WithDialTimeout(consts.DefaultDialTimeout))
@@ -353,7 +373,8 @@ func (c *Client) Post(ctx context.Context, dst []byte, url string, postArgs *pro
 // Warning: DoTimeout does not terminate the request itself. The request will
 // continue in the background and the response will be discarded.
 // If requests take too long and the connection pool gets filled up please
-// try setting a ReadTimeout.
+// try using a customized Client instance with a ReadTimeout config or set the request level read timeout like:
+// `req.SetOptions(config.WithReadTimeout(1 * time.Second))`
 func (c *Client) DoTimeout(ctx context.Context, req *protocol.Request, resp *protocol.Response, timeout time.Duration) error {
 	return client.DoTimeout(ctx, req, resp, timeout, c)
 }
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/common/errors/errors.go b/pkg/common/errors/errors.go
index dc3f4bb..e9cccdb 100644
--- a/pkg/common/errors/errors.go
+++ b/pkg/common/errors/errors.go
@@ -49,17 +49,18 @@ import (
 
 var (
 	// These errors are the base error, which are used for checking in errors.Is()
-	ErrNeedMore        = errors.New("need more data")
-	ErrChunkedStream   = errors.New("chunked stream")
-	ErrBodyTooLarge    = errors.New("body size exceeds the given limit")
-	ErrHijacked        = errors.New("connection has been hijacked")
-	ErrIdleTimeout     = errors.New("idle timeout")
-	ErrTimeout         = errors.New("timeout")
-	ErrReadTimeout     = errors.New("read timeout")
-	ErrWriteTimeout    = errors.New("write timeout")
-	ErrDialTimeout     = errors.New("dial timeout")
-	ErrNothingRead     = errors.New("nothing read")
-	ErrShortConnection = errors.New("short connection")
+	ErrNeedMore         = errors.New("need more data")
+	ErrChunkedStream    = errors.New("chunked stream")
+	ErrBodyTooLarge     = errors.New("body size exceeds the given limit")
+	ErrHijacked         = errors.New("connection has been hijacked")
+	ErrIdleTimeout      = errors.New("idle timeout")
+	ErrTimeout          = errors.New("timeout")
+	ErrReadTimeout      = errors.New("read timeout")
+	ErrWriteTimeout     = errors.New("write timeout")
+	ErrDialTimeout      = errors.New("dial timeout")
+	ErrNothingRead      = errors.New("nothing read")
+	ErrShortConnection  = errors.New("short connection")
+	ErrConnectionClosed = errors.New("connection closed")
 )
 
 // ErrorType is an unsigned 64-bit error code as defined in the hertz spec.
diff --git a/pkg/network/connection.go b/pkg/network/connection.go
index c963f2b..1559c1c 100644
--- a/pkg/network/connection.go
+++ b/pkg/network/connection.go
@@ -94,3 +94,7 @@ type ConnTLSer interface {
 type HandleSpecificError interface {
 	HandleSpecificError(err error, rip string) (needIgnore bool)
 }
+
+type ErrorNormalization interface {
+	ToHertzError(err error) error
+}
diff --git a/pkg/network/netpoll/connection.go b/pkg/network/netpoll/connection.go
index 9281e64..33d2875 100644
--- a/pkg/network/netpoll/connection.go
+++ b/pkg/network/netpoll/connection.go
@@ -25,15 +25,24 @@ import (
 	"strings"
 	"syscall"
 
+	errs "github.com/cloudwego/hertz/pkg/common/errors"
 	"github.com/cloudwego/hertz/pkg/common/hlog"
 	"github.com/cloudwego/hertz/pkg/network"
 	"github.com/cloudwego/netpoll"
+	"golang.org/x/sys/unix"
 )
 
 type Conn struct {
 	network.Conn
 }
 
+func (c *Conn) ToHertzError(err error) error {
+	if errors.Is(err, netpoll.ErrConnClosed) || errors.Is(err, unix.EPIPE) {
+		return errs.ErrConnectionClosed
+	}
+	return err
+}
+
 func (c *Conn) Peek(n int) (b []byte, err error) {
 	b, err = c.Conn.Peek(n)
 	err = normalizeErr(err)
diff --git a/pkg/network/standard/connection.go b/pkg/network/standard/connection.go
index b1d96e0..b9b2e83 100644
--- a/pkg/network/standard/connection.go
+++ b/pkg/network/standard/connection.go
@@ -18,13 +18,15 @@ package standard
 
 import (
 	"crypto/tls"
+	"errors"
 	"io"
 	"net"
 	"strconv"
 	"time"
 
-	"github.com/cloudwego/hertz/pkg/common/errors"
+	errs "github.com/cloudwego/hertz/pkg/common/errors"
 	"github.com/cloudwego/hertz/pkg/network"
+	"golang.org/x/sys/unix"
 )
 
 const (
@@ -44,6 +46,13 @@ type Conn struct {
 	maxSize      int      // history max malloc size
 }
 
+func (c *Conn) ToHertzError(err error) error {
+	if errors.Is(err, unix.EPIPE) || errors.Is(err, unix.ENOTCONN) {
+		return errs.ErrConnectionClosed
+	}
+	return err
+}
+
 func (c *Conn) SetWriteTimeout(t time.Duration) error {
 	if t <= 0 {
 		return c.c.SetWriteDeadline(time.Time{})
@@ -383,7 +392,7 @@ func (c *Conn) fill(i int) (err error) {
 func (c *Conn) Skip(n int) error {
 	// check whether enough or not.
 	if c.Len() < n {
-		return errors.NewPrivate("link buffer skip[" + strconv.Itoa(n) + "] not enough")
+		return errs.NewPrivate("link buffer skip[" + strconv.Itoa(n) + "] not enough")
 	}
 	c.inputBuffer.len -= n // re-cal length
 
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/client.go b/pkg/protocol/http1/client.go
index a1f18cb..6d42636 100644
--- a/pkg/protocol/http1/client.go
+++ b/pkg/protocol/http1/client.go
@@ -508,7 +508,32 @@ func (c *HostClient) doNonNilReqResp(req *protocol.Request, resp *protocol.Respo
 	}
 	// error happened when writing request, close the connection, and try another connection if retry is enabled
 	if err != nil {
-		c.closeConn(cc)
+		defer c.closeConn(cc)
+
+		errNorm, ok := conn.(network.ErrorNormalization)
+		if ok {
+			err = errNorm.ToHertzError(err)
+		}
+
+		if !errors.Is(err, errs.ErrConnectionClosed) {
+			return true, err
+		}
+
+		// set a protection timeout to avoid infinite loop.
+		if conn.SetReadTimeout(time.Second) != nil {
+			return true, err
+		}
+
+		// Only if the connection is closed while writing the request. Try to parse the response and return.
+		// In this case, the request/response is considered as successful.
+		// Otherwise, return the former error.
+
+		zr := c.acquireReader(conn)
+		defer zr.Release()
+		if respI.ReadHeaderAndLimitBody(resp, zr, c.MaxResponseBodySize) == nil {
+			return false, nil
+		}
+
 		return true, err
 	}
 
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/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/http1/client_test.go b/pkg/protocol/http1/client_test.go
index fa6d6c9..ad63f41 100644
--- a/pkg/protocol/http1/client_test.go
+++ b/pkg/protocol/http1/client_test.go
@@ -266,6 +266,46 @@ func TestReadTimeoutPriority(t *testing.T) {
 	}
 }
 
+func TestDoNonNilReqResp(t *testing.T) {
+	c := &HostClient{
+		ClientOptions: &ClientOptions{
+			Dialer: newSlowConnDialer(func(network, addr string) (network.Conn, error) {
+				return &writeErrConn{
+						Conn: mock.NewConn("HTTP/1.1 400 OK\nContent-Length: 6\n\n123456"),
+					},
+					nil
+			}),
+		},
+	}
+	req := protocol.AcquireRequest()
+	resp := protocol.AcquireResponse()
+	req.SetHost("foobar")
+	retry, err := c.doNonNilReqResp(req, resp)
+	assert.False(t, retry)
+	assert.Nil(t, err)
+	assert.DeepEqual(t, resp.StatusCode(), 400)
+	assert.DeepEqual(t, resp.Body(), []byte("123456"))
+}
+
+func TestDoNonNilReqResp1(t *testing.T) {
+	c := &HostClient{
+		ClientOptions: &ClientOptions{
+			Dialer: newSlowConnDialer(func(network, addr string) (network.Conn, error) {
+				return &writeErrConn{
+						Conn: mock.NewConn(""),
+					},
+					nil
+			}),
+		},
+	}
+	req := protocol.AcquireRequest()
+	resp := protocol.AcquireResponse()
+	req.SetHost("foobar")
+	retry, err := c.doNonNilReqResp(req, resp)
+	assert.True(t, retry)
+	assert.NotNil(t, err)
+}
+
 func TestWriteTimeoutPriority(t *testing.T) {
 	c := &HostClient{
 		ClientOptions: &ClientOptions{
@@ -289,7 +329,7 @@ func TestWriteTimeoutPriority(t *testing.T) {
 		ch <- c.Do(context.Background(), req, resp)
 	}()
 	select {
-	case <-time.After(time.Second * 2000):
+	case <-time.After(time.Second * 2):
 		t.Fatalf("should use writeTimeout in request options")
 	case err := <-ch:
 		assert.DeepEqual(t, errs.ErrWriteTimeout.Error(), err.Error())
@@ -323,3 +363,12 @@ func TestDialTimeoutPriority(t *testing.T) {
 		assert.DeepEqual(t, errs.ErrDialTimeout.Error(), err.Error())
 	}
 }
+
+// mockConn for getting error when write binary data.
+type writeErrConn struct {
+	network.Conn
+}
+
+func (w writeErrConn) WriteBinary(b []byte) (n int, err error) {
+	return 0, errs.ErrConnectionClosed
+}
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(), "")
+}