form.go raw

   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  }
 178