Skip to content

Commit

Permalink
#208 enable custom Content-Type for SendFile
Browse files Browse the repository at this point in the history
  • Loading branch information
vellotis committed Dec 13, 2018
1 parent 9433d8c commit 55c40c4
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 3 deletions.
47 changes: 44 additions & 3 deletions gorequest.go
Original file line number Diff line number Diff line change
Expand Up @@ -734,10 +734,11 @@ func (s *SuperAgent) SendString(content string) *SuperAgent {
type File struct {
Filename string
Fieldname string
MimeType string
Data []byte
}

// 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.
// 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.
// The function accepts a path to a file as string:
//
// gorequest.New().
Expand Down Expand Up @@ -784,10 +785,20 @@ type File struct {
// SendFile(b, "", "my_custom_fieldname"). // filename left blank, will become "example_file.ext"
// End()
//
// The third optional argument (fourth argument overall) is the mimetype request form-data part. It defaults to "application/octet-stream".
//
// b, _ := ioutil.ReadFile("./example_file.ext")
// gorequest.New().
// Post("http://example.com").
// Type("multipart").
// SendFile(b, "filename", "my_custom_fieldname", "mime_type").
// End()
//
func (s *SuperAgent) SendFile(file interface{}, args ...string) *SuperAgent {

filename := ""
fieldname := "file"
fileType := "application/octet-stream"

if len(args) >= 1 && len(args[0]) > 0 {
filename = strings.TrimSpace(args[0])
Expand All @@ -798,6 +809,13 @@ func (s *SuperAgent) SendFile(file interface{}, args ...string) *SuperAgent {
if fieldname == "file" || fieldname == "" {
fieldname = "file" + strconv.Itoa(len(s.FileData)+1)
}
if len(args) >= 3 && len(args[2]) > 0 {
fileType = strings.TrimSpace(args[2])
}
if fileType == "" {
s.Errors = append(s.Errors, errors.New("The fourth SendFile method argument for MIME type cannot be an empty string"))
return s
}

switch v := reflect.ValueOf(file); v.Kind() {
case reflect.String:
Expand All @@ -817,6 +835,7 @@ func (s *SuperAgent) SendFile(file interface{}, args ...string) *SuperAgent {
s.FileData = append(s.FileData, File{
Filename: filename,
Fieldname: fieldname,
MimeType: fileType,
Data: data,
})
case reflect.Slice:
Expand All @@ -827,6 +846,7 @@ func (s *SuperAgent) SendFile(file interface{}, args ...string) *SuperAgent {
f := File{
Filename: filename,
Fieldname: fieldname,
MimeType: fileType,
Data: make([]byte, len(slice)),
}
for i := range slice {
Expand All @@ -837,9 +857,12 @@ func (s *SuperAgent) SendFile(file interface{}, args ...string) *SuperAgent {
if len(args) == 1 {
return s.SendFile(v.Elem().Interface(), args[0])
}
if len(args) >= 2 {
if len(args) == 2 {
return s.SendFile(v.Elem().Interface(), args[0], args[1])
}
if len(args) >= 3 {
return s.SendFile(v.Elem().Interface(), args[0], args[1], args[2])
}
return s.SendFile(v.Elem().Interface())
default:
if v.Type() == reflect.TypeOf(os.File{}) {
Expand All @@ -855,6 +878,7 @@ func (s *SuperAgent) SendFile(file interface{}, args ...string) *SuperAgent {
s.FileData = append(s.FileData, File{
Filename: filename,
Fieldname: fieldname,
MimeType: fileType,
Data: data,
})
return s
Expand Down Expand Up @@ -1239,7 +1263,7 @@ func (s *SuperAgent) MakeRequest() (*http.Request, error) {
// add the files
if len(s.FileData) != 0 {
for _, file := range s.FileData {
fw, _ := mw.CreateFormFile(file.Fieldname, file.Filename)
fw, _ := CreateFormFile(mw, file.Fieldname, file.Filename, file.MimeType)
fw.Write(file.Data)
}
contentReader = buf
Expand Down Expand Up @@ -1299,6 +1323,23 @@ func (s *SuperAgent) MakeRequest() (*http.Request, error) {
return req, nil
}

var quoteEscaper = strings.NewReplacer("\\", "\\\\", `"`, "\\\"")

func escapeQuotes(s string) string {
return quoteEscaper.Replace(s)
}

// CreateFormFile is a convenience wrapper around CreatePart. It creates
// a new form-data header with the provided field name and file name.
func CreateFormFile(w *multipart.Writer, fieldname, filename string, contenttype string) (io.Writer, error) {
h := make(textproto.MIMEHeader)
h.Set("Content-Disposition",
fmt.Sprintf(`form-data; name="%s"; filename="%s"`,
escapeQuotes(fieldname), escapeQuotes(filename)))
h.Set("Content-Type", contenttype)
return w.CreatePart(h)
}

// AsCurlCommand returns a string representing the runnable `curl' command
// version of the request.
func (s *SuperAgent) AsCurlCommand() (string, error) {
Expand Down
27 changes: 27 additions & 0 deletions gorequest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -761,13 +761,15 @@ func TestMultipartRequest(t *testing.T) {
const case10b_send_file_by_path_pointer = "/send_file_by_path_pointer"
const case11_send_file_by_path_without_name = "/send_file_by_path_without_name"
const case12_send_file_by_path_without_name_but_with_fieldname = "/send_file_by_path_without_name_but_with_fieldname"
const case121_send_file_by_path_with_name_and_fieldname_and_mimetype = "/send_file_by_path_with_name_and_fieldname_and_mimetype"

const case13_send_file_by_content_without_name = "/send_file_by_content_without_name"
const case13a_send_file_by_content_without_name_pointer = "/send_file_by_content_without_name_pointer"
const case14_send_file_by_content_with_name = "/send_file_by_content_with_name"

const case15_send_file_by_content_without_name_but_with_fieldname = "/send_file_by_content_without_name_but_with_fieldname"
const case16_send_file_by_content_with_name_and_with_fieldname = "/send_file_by_content_with_name_and_with_fieldname"
const case161_send_file_by_content_with_name_and_fieldname_and_mimetype = "/send_file_by_content_with_name_and_fieldname_and_mimetype"

const case17_send_file_multiple_by_path_and_content_without_name = "/send_file_multiple_by_path_and_content_without_name"
const case18_send_file_multiple_by_path_and_content_with_name = "/send_file_multiple_by_path_and_content_with_name"
Expand Down Expand Up @@ -998,6 +1000,21 @@ func TestMultipartRequest(t *testing.T) {
t.Error("Expected Header:Content-Type:application/octet-stream", "| but got", r.MultipartForm.File["my_fieldname"][0].Header["Content-Type"])
}
checkFile(t, r.MultipartForm.File["my_fieldname"][0])
case case161_send_file_by_content_with_name_and_fieldname_and_mimetype, case121_send_file_by_path_with_name_and_fieldname_and_mimetype:
if len(r.MultipartForm.File) != 1 {
t.Error("Expected length of files:[] == 1", "| but got", len(r.MultipartForm.File))
}
if _, ok := r.MultipartForm.File["my_fieldname"]; !ok {
keys := reflect.ValueOf(r.MultipartForm.File).MapKeys()
t.Error("Expected Fieldname:my_fieldname", "| but got", keys)
}
if r.MultipartForm.File["my_fieldname"][0].Filename != "MY_LICENSE" {
t.Error("Expected Filename:MY_LICENSE", "| but got", r.MultipartForm.File["my_fieldname"][0].Filename)
}
if r.MultipartForm.File["my_fieldname"][0].Header["Content-Type"][0] != "application/octet-stream" {
t.Error("Expected Header:Content-Type:application/json", "| but got", r.MultipartForm.File["my_fieldname"][0].Header["Content-Type"])
}
checkFile(t, r.MultipartForm.File["my_fieldname"][0])
case case17_send_file_multiple_by_path_and_content_without_name:
if len(r.MultipartForm.File) != 2 {
t.Error("Expected length of files:[] == 2", "| but got", len(r.MultipartForm.File))
Expand Down Expand Up @@ -1208,6 +1225,11 @@ func TestMultipartRequest(t *testing.T) {
SendFile(fileByPath, "", "my_fieldname").
End()

New().Post(ts.URL+ case121_send_file_by_path_with_name_and_fieldname_and_mimetype).
Type("multipart").
SendFile(fileByPath, "MY_LICENSE", "my_fieldname", "application/json").
End()

b, _ := ioutil.ReadFile("./LICENSE")
New().Post(ts.URL + case13_send_file_by_content_without_name).
Type("multipart").
Expand All @@ -1234,6 +1256,11 @@ func TestMultipartRequest(t *testing.T) {
SendFile(b, "MY_LICENSE", "my_fieldname").
End()

New().Post(ts.URL+case12_send_file_by_content_with_name_and_fieldname_and_mimetype).
Type("multipart").
SendFile(b, "MY_LICENSE", "my_fieldname", "application/json").
End()

New().Post(ts.URL + case17_send_file_multiple_by_path_and_content_without_name).
Type("multipart").
SendFile("./LICENSE").
Expand Down

0 comments on commit 55c40c4

Please sign in to comment.