Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#208 enable custom Content-Type for SendFile #213

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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/json" {
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+case121_send_file_by_path_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