-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathmultipart.go
109 lines (92 loc) · 2.41 KB
/
multipart.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package snippets
import (
"bufio"
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"os"
)
func sendMultipart(url string, field string, name string) (*http.Response, error) {
r, w := io.Pipe()
mWriter := multipart.NewWriter(w)
go func() {
defer w.Close()
defer mWriter.Close()
fWriter, err := mWriter.CreateFormFile(field, name)
if err != nil {
return
}
file, err := os.Open(name)
if err != nil {
return
}
defer file.Close()
if _, err = io.Copy(fWriter, file); err != nil {
return
}
}()
return http.Post(url, mWriter.FormDataContentType(), r)
}
func receiveMultipart(w http.ResponseWriter, r *http.Request) {
r.Body = http.MaxBytesReader(w, r.Body, 32<<20+1024)
reader, err := r.MultipartReader()
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// demonstration purpose - we have 2 fields named: text_field and file_file
// they will be parsed in order
var _ = []string{"text_field", "file_field"}
// parse text field
var text = make([]byte, 512)
p, err := reader.NextPart()
// one more field to parse, EOF is considered as failure here
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if p.FormName() != "text_field" {
http.Error(w, "text_field is expected", http.StatusBadRequest)
}
_, err = p.Read(text)
if err != nil && err != io.EOF {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// parse file field
p, err = reader.NextPart()
if err != nil && err != io.EOF {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if p.FormName() != "file_field" {
http.Error(w, "file_field is expected", http.StatusBadRequest)
}
buf := bufio.NewReader(p)
sniff, _ := buf.Peek(512)
contentType := http.DetectContentType(sniff)
if contentType != "application/zip" {
http.Error(w, "file type not allowed", http.StatusBadRequest)
return
}
f, err := ioutil.TempFile("", "")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer f.Close()
var maxSize int64 = 32 << 20
lmt := io.LimitReader(p, maxSize+1)
written, err := io.Copy(f, lmt)
if err != nil && err != io.EOF {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if written > maxSize {
os.Remove(f.Name())
http.Error(w, "file size over limit", http.StatusBadRequest)
return
}
// here we should have text and f to be processed accordingly
}