github.com/alibabacloud-go/tea@v1.3.10/dara/form.go (about) 1 package dara 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "math/rand" 8 "net/url" 9 "strings" 10 ) 11 12 type FileField struct { 13 Filename *string `json:"filename" xml:"filename" require:"true"` 14 ContentType *string `json:"content-type" xml:"content-type" require:"true"` 15 Content io.Reader `json:"content" xml:"content" require:"true"` 16 } 17 18 func (s *FileField) SetFilename(v string) *FileField { 19 s.Filename = &v 20 return s 21 } 22 23 func (s *FileField) SetContentType(v string) *FileField { 24 s.ContentType = &v 25 return s 26 } 27 28 func (s *FileField) SetContent(v io.Reader) *FileField { 29 s.Content = v 30 return s 31 } 32 33 type FileFormReader struct { 34 formFiles []*formFile 35 formField io.Reader 36 index int 37 streaming bool 38 ifField bool 39 } 40 41 type formFile struct { 42 StartField io.Reader 43 EndField io.Reader 44 File io.Reader 45 start bool 46 end bool 47 } 48 49 const numBytes = "1234567890" 50 51 func GetBoundary() string { 52 b := make([]byte, 14) 53 for i := range b { 54 b[i] = numBytes[rand.Intn(len(numBytes))] 55 } 56 return string(b) 57 } 58 59 func ToFileForm(body map[string]interface{}, boundary string) io.Reader { 60 out := bytes.NewBuffer(nil) 61 line := "--" + boundary + "\r\n" 62 forms := make(map[string]string) 63 files := make(map[string]map[string]interface{}) 64 for key, value := range body { 65 switch value.(type) { 66 case *FileField: 67 if val, ok := value.(*FileField); ok { 68 out := make(map[string]interface{}) 69 out["filename"] = StringValue(val.Filename) 70 out["content-type"] = StringValue(val.ContentType) 71 out["content"] = val.Content 72 files[key] = out 73 } 74 case map[string]interface{}: 75 if val, ok := value.(map[string]interface{}); ok { 76 files[key] = val 77 } 78 default: 79 forms[key] = fmt.Sprintf("%v", value) 80 } 81 } 82 for key, value := range forms { 83 if value != "" { 84 out.Write([]byte(line)) 85 out.Write([]byte("Content-Disposition: form-data; name=\"" + key + "\"" + "\r\n\r\n")) 86 out.Write([]byte(value + "\r\n")) 87 } 88 } 89 formFiles := make([]*formFile, 0) 90 for key, value := range files { 91 var file io.Reader 92 start := line 93 start += "Content-Disposition: form-data; name=\"" + key + "\"; filename=\"" + value["filename"].(string) + "\"\r\n" 94 start += "Content-Type: " + value["content-type"].(string) + "\r\n\r\n" 95 if content, ok := value["content"].(io.Reader); ok { 96 file = content 97 } else { 98 file = strings.NewReader("") 99 } 100 formFile := &formFile{ 101 File: file, 102 start: true, 103 StartField: strings.NewReader(start), 104 } 105 if len(files) == len(formFiles)+1 { 106 end := "\r\n\r\n--" + boundary + "--\r\n" 107 formFile.EndField = strings.NewReader(end) 108 } else { 109 formFile.EndField = strings.NewReader("\r\n\r\n") 110 } 111 formFiles = append(formFiles, formFile) 112 } 113 return &FileFormReader{ 114 formFiles: formFiles, 115 formField: out, 116 ifField: true, 117 } 118 } 119 120 func (f *FileFormReader) Read(p []byte) (n int, err error) { 121 if f.ifField { 122 n, err = f.formField.Read(p) 123 if err != nil && err != io.EOF { 124 return n, err 125 } else if err == io.EOF { 126 err = nil 127 f.ifField = false 128 f.streaming = true 129 } 130 } else if f.streaming { 131 form := f.formFiles[f.index] 132 if form.start { 133 n, err = form.StartField.Read(p) 134 if err != nil && err != io.EOF { 135 return n, err 136 } else if err == io.EOF { 137 err = nil 138 form.start = false 139 } 140 } else if form.end { 141 n, err = form.EndField.Read(p) 142 if err != nil && err != io.EOF { 143 return n, err 144 } else if err == io.EOF { 145 f.index++ 146 form.end = false 147 if f.index < len(f.formFiles) { 148 err = nil 149 } 150 } 151 } else { 152 n, err = form.File.Read(p) 153 if err != nil && err != io.EOF { 154 return n, err 155 } else if err == io.EOF { 156 err = nil 157 form.end = true 158 } 159 } 160 } 161 162 return n, err 163 } 164 165 func ToFormString(a map[string]interface{}) string { 166 if a == nil { 167 return "" 168 } 169 res := "" 170 urlEncoder := url.Values{} 171 for key, value := range a { 172 v := fmt.Sprintf("%v", value) 173 urlEncoder.Add(key, v) 174 } 175 res = urlEncoder.Encode() 176 return res 177 }