@@ -2,6 +2,7 @@ package httprequest
22
33import (
44 "context"
5+ "fmt"
56 "io"
67 "mime/multipart"
78 "net/http"
@@ -55,6 +56,23 @@ func (r *Multipart) Timeout(duration time.Duration) *Multipart {
5556func (r * Multipart ) Send () (* http.Response , error ) {
5657 ctx := r .request .Context ()
5758
59+ // Pre-validate files to ensure they are not empty
60+ for i , field := range r .fields {
61+ if field .contentType == applicationOctetStream {
62+ // Read first byte to check if file has content
63+ buf := make ([]byte , 1 )
64+ n , err := field .file .Read (buf )
65+ if err != nil && err != io .EOF {
66+ return nil , fmt .Errorf ("failed to read file %s: %w" , field .value , err )
67+ }
68+ if n == 0 {
69+ return nil , fmt .Errorf ("empty file: %s" , field .value )
70+ }
71+ // Wrap reader to return the read byte back to the stream
72+ r .fields [i ].file = io .MultiReader (strings .NewReader (string (buf [:n ])), field .file )
73+ }
74+ }
75+
5876 pr , pw := io .Pipe ()
5977 mw := multipart .NewWriter (pw )
6078 r .request .Body = pr
@@ -72,18 +90,21 @@ func (r *Multipart) Send() (*http.Response, error) {
7290 return
7391 default :
7492 }
93+
7594 switch field .contentType {
7695 case multipartFormData :
7796 if err := mw .WriteField (field .key , field .value ); err != nil {
7897 pw .CloseWithError (err )
7998 return
8099 }
100+
81101 case applicationOctetStream :
82102 part , err := mw .CreateFormFile (field .key , field .value )
83103 if err != nil {
84104 pw .CloseWithError (err )
85105 return
86106 }
107+
87108 if _ , err := io .Copy (part , field .file ); err != nil {
88109 pw .CloseWithError (err )
89110 return
0 commit comments