-
Notifications
You must be signed in to change notification settings - Fork 21
Expand file tree
/
Copy pathmain.go
More file actions
132 lines (108 loc) · 3.01 KB
/
main.go
File metadata and controls
132 lines (108 loc) · 3.01 KB
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package main
import (
"fmt"
"io"
"log"
"net/http"
"os"
"path/filepath"
"time"
)
const MAX_UPLOAD_SIZE = 1024 * 1024 // 1MB
// Progress is used to track the progress of a file upload.
// It implements the io.Writer interface so it can be passed
// to an io.TeeReader()
type Progress struct {
TotalSize int64
BytesRead int64
}
// Write is used to satisfy the io.Writer interface.
// Instead of writing somewhere, it simply aggregates
// the total bytes on each read
func (pr *Progress) Write(p []byte) (n int, err error) {
n, err = len(p), nil
pr.BytesRead += int64(n)
pr.Print()
return
}
// Print displays the current progress of the file upload
func (pr *Progress) Print() {
if pr.BytesRead == pr.TotalSize {
fmt.Println("DONE!")
return
}
fmt.Printf("File upload in progress: %d\n", pr.BytesRead)
}
func IndexHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Content-Type", "text/html")
http.ServeFile(w, r, "index.html")
}
func uploadHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
// 32 MB is the default used by FormFile
if err := r.ParseMultipartForm(32 << 20); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// get a reference to the fileHeaders
files := r.MultipartForm.File["file"]
for _, fileHeader := range files {
if fileHeader.Size > MAX_UPLOAD_SIZE {
http.Error(w, fmt.Sprintf("The uploaded image is too big: %s. Please use an image less than 1MB in size", fileHeader.Filename), http.StatusBadRequest)
return
}
file, err := fileHeader.Open()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer file.Close()
buff := make([]byte, 512)
_, err = file.Read(buff)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
filetype := http.DetectContentType(buff)
if filetype != "image/jpeg" && filetype != "image/png" {
http.Error(w, "The provided file format is not allowed. Please upload a JPEG or PNG image", http.StatusBadRequest)
return
}
_, err = file.Seek(0, io.SeekStart)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
err = os.MkdirAll("./uploads", os.ModePerm)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
f, err := os.Create(fmt.Sprintf("./uploads/%d%s", time.Now().UnixNano(), filepath.Ext(fileHeader.Filename)))
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
defer f.Close()
pr := &Progress{
TotalSize: fileHeader.Size,
}
_, err = io.Copy(f, io.TeeReader(file, pr))
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
}
fmt.Fprintf(w, "Upload successful")
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", IndexHandler)
mux.HandleFunc("/upload", uploadHandler)
if err := http.ListenAndServe(":4500", mux); err != nil {
log.Fatal(err)
}
}