Repository: cloudwego/hertz
Pull request #748 (2023-04-24 08:08:19)

fix: WriteMultipartFormFile will fail when the Reader return EOF at first Read
#### What type of PR is this?
<!--
Add one of the following kinds:

build: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
ci: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)
docs: Documentation only changes
feat: A new feature
optimize: A new optimization
fix: A bug fix
perf: A code change that improves performance
refactor: A code change that neither fixes a bug nor adds a feature
style: Changes that do not affect the meaning of the code (white space, formatting, missing semi-colons, etc)
test: Adding missing tests or correcting existing tests
chore: Changes to the build process or auxiliary tools and libraries such as documentation generation
-->
fix
#### Check the PR title.
<!--
The description of the title will be attached in Release Notes, 
so please describe it from user-oriented, what this PR does / why we need it.
Please check your PR title with the below requirements:
-->
- [x] This PR title match the format: `<type>(optional scope): <description>`.
- [x] The description of this PR title is user-oriented and clear enough for others to understand.
- [x] Attach the PR updating the user documentation if the current PR requires user awareness at the usage level. [User docs repo](https://github.com/cloudwego/cloudwego.github.io).

#### (Optional) Translate the PR title into Chinese.
修复：当传入的 `Reader` 的第一次 `Read` 返回 EOF 时，`WriteMultipartFormFile`将会失败

#### (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: `WriteMultipartFormFile` does not check whether the return of Read is EOF. When Read returns EOF, `WriteMultipartForm` will return an error. Replace Read with `io.LimitedReader` to fix this
zh(optional): `WriteMultipartFormFile` 没有检查 Read 的返回是否是 EOF，当 Read 返回了 EOF 时， `WriteMultipartForm` 将会返回错误。将 Read 替换为 `io.LimitedReader` 来修复此问题

#### (Optional) Which issue(s) this PR fixes:
<!--
Automatically closes linked issue when PR is merged.
Eg: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
-->

Fixes https://github.com/cloudwego/hertz/issues/746

#### (Optional) The PR that updates user documentation:
<!--
If the current PR requires user awareness at the usage level, please submit a PR to update user docs. [User docs repo](https://github.com/cloudwego/cloudwego.github.io)
-->


codecov[bot]: ## [Codecov](https://codecov.io/gh/cloudwego/hertz/pull/748?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego) Report
Patch coverage: **`83.33`**% and project coverage change: **`-0.06`** :warning:
> Comparison is base [(`ce158d4`)](https://codecov.io/gh/cloudwego/hertz/commit/ce158d4cc354ec54091d19925085b0d0ebf54e9b?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego) 75.69% compared to head [(`dc76753`)](https://codecov.io/gh/cloudwego/hertz/pull/748?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego) 75.63%.

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

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


```diff
@@             Coverage Diff             @@
##           develop     #748      +/-   ##
===========================================
- Coverage    75.69%   75.63%   -0.06%     
===========================================
  Files           97       97              
  Lines         9464     9466       +2     
===========================================
- Hits          7164     7160       -4     
- Misses        1852     1856       +4     
- Partials       448      450       +2     
```


| [Impacted Files](https://codecov.io/gh/cloudwego/hertz/pull/748?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego) | Coverage Δ | |
|---|---|---|
| [pkg/protocol/multipart.go](https://codecov.io/gh/cloudwego/hertz/pull/748?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego#diff-cGtnL3Byb3RvY29sL211bHRpcGFydC5nbw==) | `77.77% <83.33%> (-1.97%)` | :arrow_down: |

... and [2 files with indirect coverage changes](https://codecov.io/gh/cloudwego/hertz/pull/748/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego)

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 in Codecov by Sentry](https://codecov.io/gh/cloudwego/hertz/pull/748?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/pkg/protocol/multipart.go b/pkg/protocol/multipart.go
index 4290491..e926c94 100644
--- a/pkg/protocol/multipart.go
+++ b/pkg/protocol/multipart.go
@@ -137,11 +137,11 @@ func WriteMultipartFormFile(w *multipart.Writer, fieldName, fileName string, r i
 	// Auto detect actual multipart content type
 	cbuf := make([]byte, 512)
 	size, err := r.Read(cbuf)
-	if err != nil {
+	if err != nil && err != io.EOF {
 		return err
 	}
 
-	partWriter, err := w.CreatePart(CreateMultipartHeader(fieldName, fileName, http.DetectContentType(cbuf)))
+	partWriter, err := w.CreatePart(CreateMultipartHeader(fieldName, fileName, http.DetectContentType(cbuf[:size])))
 	if err != nil {
 		return err
 	}


Test patch:
diff --git a/pkg/protocol/multipart_test.go b/pkg/protocol/multipart_test.go
index be93b89..86995d2 100644
--- a/pkg/protocol/multipart_test.go
+++ b/pkg/protocol/multipart_test.go
@@ -208,6 +208,9 @@ func TestWriteMultipartFormFile(t *testing.T) {
 		t.Fatalf("write multipart error: %s", err)
 	}
 	assert.False(t, strings.Contains(bodyBuffer.String(), f3.Name()))
+
+	// test empty file
+	assert.Nil(t, WriteMultipartFormFile(w, "empty_test", "test.data", bytes.NewBuffer(nil)))
 }
 
 func TestMarshalMultipartForm(t *testing.T) {