Skip to content

Instantly share code, notes, and snippets.

@jordanorelli
Created August 28, 2013 20:38
Show Gist options
  • Save jordanorelli/6370955 to your computer and use it in GitHub Desktop.
Save jordanorelli/6370955 to your computer and use it in GitHub Desktop.
package main
import (
"flag"
"fmt"
"io"
"log"
"net/http"
"os"
"path/filepath"
)
var default_index = `
<!DOCTYPE html>
<title>upload</title>
<meta charset='utf-8'>
<form action='.' method='post' enctype='multipart/form-data'>
<input type='file' name='lorem'>
<input type='file' name='ipsum'>
<input type='file' name='file'>
<input type='submit'>
</form>
`
var (
index_page = flag.String("index", default_index,
"HTML file containing the upload form; if not specified, a simple default page will be used")
dest_dir = flag.String("dest", ".",
"destination directory for storing uploaded files")
)
type makeHandler func(http.ResponseWriter, *http.Request) error
type handlerError struct {
code int
message string
}
func (h handlerError) Error() string {
return h.message
}
func index(w http.ResponseWriter, r *http.Request) error {
switch r.Method {
case "POST":
src_file_reader, err := r.MultipartReader()
if err != nil {
return fmt.Errorf("unable to open multipartreader: %v", err)
}
for part, err := src_file_reader.NextPart(); err == nil; {
form_name := part.FormName()
if form_name != "file" {
log.Printf("Skipping '%s'\n", form_name)
return handlerError{302, "bad form name"}
}
log.Printf("Handling '%s'\n", form_name)
dest_file, err := os.Create(filepath.Join(*dest_dir, part.FileName()))
if err != nil {
return fmt.Errorf("unable to create destination file: %v", err)
}
defer dest_file.Close()
if _, err := io.Copy(dest_file, part); err != nil {
return handlerError{500, "unable to copy file"}
}
}
case "GET":
fmt.Fprintf(w, "%s", *index_page)
default:
return handlerError{405, "unsupported http method"}
}
return nil
}
func (fn makeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
err := fn(w, r)
if err == nil {
return
}
switch e := err.(type) {
case handlerError:
if e.code >= 300 && e.code < 400 {
http.Redirect(w, r, "/", e.code)
break
}
w.WriteHeader(e.code)
io.WriteString(w, e.message)
default:
http.Redirect(w, r, "/", 302)
}
}
func main() {
flag.Parse()
http.Handle("/", makeHandler(index))
log.Fatal(http.ListenAndServe("0.0.0.0:4000", nil))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment