Skip to content

Commit f50760c

Browse files
committed
#208 enable custom Content-Type for SendFile
1 parent 9433d8c commit f50760c

File tree

2 files changed

+71
-3
lines changed

2 files changed

+71
-3
lines changed

gorequest.go

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -734,10 +734,11 @@ func (s *SuperAgent) SendString(content string) *SuperAgent {
734734
type File struct {
735735
Filename string
736736
Fieldname string
737+
MimeType string
737738
Data []byte
738739
}
739740

740-
// SendFile function works only with type "multipart". The function accepts one mandatory and up to two optional arguments. The mandatory (first) argument is the file.
741+
// SendFile function works only with type "multipart". The function accepts one mandatory and up to three optional arguments. The mandatory (first) argument is the file.
741742
// The function accepts a path to a file as string:
742743
//
743744
// gorequest.New().
@@ -784,10 +785,20 @@ type File struct {
784785
// SendFile(b, "", "my_custom_fieldname"). // filename left blank, will become "example_file.ext"
785786
// End()
786787
//
788+
// The third optional argument (fourth argument overall) is the mimetype request form-data part. It defaults to "application/octet-stream".
789+
//
790+
// b, _ := ioutil.ReadFile("./example_file.ext")
791+
// gorequest.New().
792+
// Post("http://example.com").
793+
// Type("multipart").
794+
// SendFile(b, "filename", "my_custom_fieldname", "mime_type").
795+
// End()
796+
//
787797
func (s *SuperAgent) SendFile(file interface{}, args ...string) *SuperAgent {
788798

789799
filename := ""
790800
fieldname := "file"
801+
fileType := "application/octet-stream"
791802

792803
if len(args) >= 1 && len(args[0]) > 0 {
793804
filename = strings.TrimSpace(args[0])
@@ -798,6 +809,13 @@ func (s *SuperAgent) SendFile(file interface{}, args ...string) *SuperAgent {
798809
if fieldname == "file" || fieldname == "" {
799810
fieldname = "file" + strconv.Itoa(len(s.FileData)+1)
800811
}
812+
if len(args) >= 3 && len(args[2]) > 0 {
813+
fileType = strings.TrimSpace(args[2])
814+
}
815+
if fileType == "" {
816+
s.Errors = append(s.Errors, errors.New("The fourth SendFile method argument for MIME type cannot be an empty string"))
817+
return s
818+
}
801819

802820
switch v := reflect.ValueOf(file); v.Kind() {
803821
case reflect.String:
@@ -817,6 +835,7 @@ func (s *SuperAgent) SendFile(file interface{}, args ...string) *SuperAgent {
817835
s.FileData = append(s.FileData, File{
818836
Filename: filename,
819837
Fieldname: fieldname,
838+
MimeType: fileType,
820839
Data: data,
821840
})
822841
case reflect.Slice:
@@ -827,6 +846,7 @@ func (s *SuperAgent) SendFile(file interface{}, args ...string) *SuperAgent {
827846
f := File{
828847
Filename: filename,
829848
Fieldname: fieldname,
849+
MimeType: fileType,
830850
Data: make([]byte, len(slice)),
831851
}
832852
for i := range slice {
@@ -837,9 +857,12 @@ func (s *SuperAgent) SendFile(file interface{}, args ...string) *SuperAgent {
837857
if len(args) == 1 {
838858
return s.SendFile(v.Elem().Interface(), args[0])
839859
}
840-
if len(args) >= 2 {
860+
if len(args) == 2 {
841861
return s.SendFile(v.Elem().Interface(), args[0], args[1])
842862
}
863+
if len(args) >= 3 {
864+
return s.SendFile(v.Elem().Interface(), args[0], args[1], args[2])
865+
}
843866
return s.SendFile(v.Elem().Interface())
844867
default:
845868
if v.Type() == reflect.TypeOf(os.File{}) {
@@ -855,6 +878,7 @@ func (s *SuperAgent) SendFile(file interface{}, args ...string) *SuperAgent {
855878
s.FileData = append(s.FileData, File{
856879
Filename: filename,
857880
Fieldname: fieldname,
881+
MimeType: fileType,
858882
Data: data,
859883
})
860884
return s
@@ -1239,7 +1263,7 @@ func (s *SuperAgent) MakeRequest() (*http.Request, error) {
12391263
// add the files
12401264
if len(s.FileData) != 0 {
12411265
for _, file := range s.FileData {
1242-
fw, _ := mw.CreateFormFile(file.Fieldname, file.Filename)
1266+
fw, _ := CreateFormFile(mw, file.Fieldname, file.Filename, file.MimeType)
12431267
fw.Write(file.Data)
12441268
}
12451269
contentReader = buf
@@ -1299,6 +1323,23 @@ func (s *SuperAgent) MakeRequest() (*http.Request, error) {
12991323
return req, nil
13001324
}
13011325

1326+
var quoteEscaper = strings.NewReplacer("\\", "\\\\", `"`, "\\\"")
1327+
1328+
func escapeQuotes(s string) string {
1329+
return quoteEscaper.Replace(s)
1330+
}
1331+
1332+
// CreateFormFile is a convenience wrapper around CreatePart. It creates
1333+
// a new form-data header with the provided field name and file name.
1334+
func CreateFormFile(w *multipart.Writer, fieldname, filename string, contenttype string) (io.Writer, error) {
1335+
h := make(textproto.MIMEHeader)
1336+
h.Set("Content-Disposition",
1337+
fmt.Sprintf(`form-data; name="%s"; filename="%s"`,
1338+
escapeQuotes(fieldname), escapeQuotes(filename)))
1339+
h.Set("Content-Type", contenttype)
1340+
return w.CreatePart(h)
1341+
}
1342+
13021343
// AsCurlCommand returns a string representing the runnable `curl' command
13031344
// version of the request.
13041345
func (s *SuperAgent) AsCurlCommand() (string, error) {

gorequest_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -761,13 +761,15 @@ func TestMultipartRequest(t *testing.T) {
761761
const case10b_send_file_by_path_pointer = "/send_file_by_path_pointer"
762762
const case11_send_file_by_path_without_name = "/send_file_by_path_without_name"
763763
const case12_send_file_by_path_without_name_but_with_fieldname = "/send_file_by_path_without_name_but_with_fieldname"
764+
const case121_send_file_by_path_with_name_and_fieldname_and_mimetype = "/send_file_by_path_with_name_and_fieldname_and_mimetype"
764765

765766
const case13_send_file_by_content_without_name = "/send_file_by_content_without_name"
766767
const case13a_send_file_by_content_without_name_pointer = "/send_file_by_content_without_name_pointer"
767768
const case14_send_file_by_content_with_name = "/send_file_by_content_with_name"
768769

769770
const case15_send_file_by_content_without_name_but_with_fieldname = "/send_file_by_content_without_name_but_with_fieldname"
770771
const case16_send_file_by_content_with_name_and_with_fieldname = "/send_file_by_content_with_name_and_with_fieldname"
772+
const case161_send_file_by_content_with_name_and_fieldname_and_mimetype = "/send_file_by_content_with_name_and_fieldname_and_mimetype"
771773

772774
const case17_send_file_multiple_by_path_and_content_without_name = "/send_file_multiple_by_path_and_content_without_name"
773775
const case18_send_file_multiple_by_path_and_content_with_name = "/send_file_multiple_by_path_and_content_with_name"
@@ -998,6 +1000,21 @@ func TestMultipartRequest(t *testing.T) {
9981000
t.Error("Expected Header:Content-Type:application/octet-stream", "| but got", r.MultipartForm.File["my_fieldname"][0].Header["Content-Type"])
9991001
}
10001002
checkFile(t, r.MultipartForm.File["my_fieldname"][0])
1003+
case case161_send_file_by_content_with_name_and_fieldname_and_mimetype, case121_send_file_by_path_with_name_and_fieldname_and_mimetype:
1004+
if len(r.MultipartForm.File) != 1 {
1005+
t.Error("Expected length of files:[] == 1", "| but got", len(r.MultipartForm.File))
1006+
}
1007+
if _, ok := r.MultipartForm.File["my_fieldname"]; !ok {
1008+
keys := reflect.ValueOf(r.MultipartForm.File).MapKeys()
1009+
t.Error("Expected Fieldname:my_fieldname", "| but got", keys)
1010+
}
1011+
if r.MultipartForm.File["my_fieldname"][0].Filename != "MY_LICENSE" {
1012+
t.Error("Expected Filename:MY_LICENSE", "| but got", r.MultipartForm.File["my_fieldname"][0].Filename)
1013+
}
1014+
if r.MultipartForm.File["my_fieldname"][0].Header["Content-Type"][0] != "application/octet-stream" {
1015+
t.Error("Expected Header:Content-Type:application/json", "| but got", r.MultipartForm.File["my_fieldname"][0].Header["Content-Type"])
1016+
}
1017+
checkFile(t, r.MultipartForm.File["my_fieldname"][0])
10011018
case case17_send_file_multiple_by_path_and_content_without_name:
10021019
if len(r.MultipartForm.File) != 2 {
10031020
t.Error("Expected length of files:[] == 2", "| but got", len(r.MultipartForm.File))
@@ -1208,6 +1225,11 @@ func TestMultipartRequest(t *testing.T) {
12081225
SendFile(fileByPath, "", "my_fieldname").
12091226
End()
12101227

1228+
New().Post(ts.URL+ case121_send_file_by_path_with_name_and_fieldname_and_mimetype).
1229+
Type("multipart").
1230+
SendFile(fileByPath, "MY_LICENSE", "my_fieldname", "application/json").
1231+
End()
1232+
12111233
b, _ := ioutil.ReadFile("./LICENSE")
12121234
New().Post(ts.URL + case13_send_file_by_content_without_name).
12131235
Type("multipart").
@@ -1234,6 +1256,11 @@ func TestMultipartRequest(t *testing.T) {
12341256
SendFile(b, "MY_LICENSE", "my_fieldname").
12351257
End()
12361258

1259+
New().Post(ts.URL+case121_send_file_by_path_with_name_and_fieldname_and_mimetype).
1260+
Type("multipart").
1261+
SendFile(b, "MY_LICENSE", "my_fieldname", "application/json").
1262+
End()
1263+
12371264
New().Post(ts.URL + case17_send_file_multiple_by_path_and_content_without_name).
12381265
Type("multipart").
12391266
SendFile("./LICENSE").

0 commit comments

Comments
 (0)