--- /dev/null
+/*
+uploader -- simplest form file uploader
+Copyright (C) 2018 Sergey Matveev <stargrave@stargrave.org>
+*/
+
+package main
+
+import (
+ "bufio"
+ "encoding/hex"
+ "flag"
+ "fmt"
+ "io"
+ "net"
+ "net/http"
+ "os"
+ "time"
+
+ "golang.org/x/crypto/blake2s"
+ "golang.org/x/net/netutil"
+)
+
+const (
+ WriteBufSize = 1 << 20
+)
+
+func upload(w http.ResponseWriter, r *http.Request) {
+ if r.Method == http.MethodGet {
+ w.Write([]byte(`<html>
+<head><title>Upload</title></head><body>
+<form enctype="multipart/form-data" action="/upload/" method="post">
+<input type="file" name="fileupload" /><input type="submit" />
+</form></body></html>`))
+ return
+ }
+ mr, err := r.MultipartReader()
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+ p, err := mr.NextPart()
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+ if p.FormName() != "fileupload" {
+ fmt.Println("non file form field")
+ return
+ }
+ now := time.Now()
+ fd, err := os.OpenFile(now.Format(time.RFC3339Nano), os.O_WRONLY|os.O_CREATE, 0600)
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+ defer fd.Close()
+ h, err := blake2s.New256(nil)
+ if err != nil {
+ panic(err)
+ }
+ fdBuf := bufio.NewWriterSize(fd, WriteBufSize)
+ mw := io.MultiWriter(fdBuf, h)
+ n, err := io.Copy(mw, p)
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+ if err = fdBuf.Flush(); err != nil {
+ fmt.Println(err)
+ return
+ }
+ fmt.Fprintf(w, "bytes: %d\nBLAKE2s: %s\n", n, hex.EncodeToString(h.Sum(nil)))
+}
+
+func main() {
+ bind := flag.String("bind", "[::]:8086", "Address to bind to")
+ conns := flag.Int("conns", 2, "Maximal number of connections")
+ flag.Parse()
+ ln, err := net.Listen("tcp", *bind)
+ if err != nil {
+ panic(err)
+ }
+ fmt.Println("listening on", *bind)
+ ln = netutil.LimitListener(ln, *conns)
+ s := &http.Server{
+ ReadHeaderTimeout: 10 * time.Second,
+ MaxHeaderBytes: 10 * (1 << 10),
+ }
+ http.HandleFunc("/upload/", upload)
+ s.Serve(ln)
+}