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  }