package main import ( "encoding/json" "fmt" "log" "net/http" "net/url" "os" "regexp" "strings" "sync" "time" ) var ( long = regexp.MustCompile(`(.{72}\S*)\s+`) file, requests *os.File m sync.Mutex ) func wrap(s string) string { return strings.ReplaceAll(long.ReplaceAllString( strings.ReplaceAll(s, "\r", ""), "$1\n"), "\n", "\n ") } func handler(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() if err := r.ParseForm(); err != nil { w.WriteHeader(http.StatusBadRequest) return } text := r.FormValue("text") if len(text) > 64<<10 { w.WriteHeader(http.StatusBadRequest) return } m.Lock() defer m.Unlock() j, _ := json.Marshal(struct { URI string Headers http.Header Form url.Values }{ URI: r.RequestURI, Headers: r.Header, Form: r.Form, }) if s, err := file.Stat(); err != nil { log.Fatalln(err) } else if s.Size()+int64(len(text)) > 64<<20 { w.WriteHeader(http.StatusInternalServerError) } else if r.Form.Has("submit") { // should not be named, and thus received. // // If this is not enough to filter out most spammers, consider also: // - Header: "Origin" should not be missing for POST. // - Header: "Accept" should not be "*/*". // - Header: "Accept-Language" and "Accept-Encoding" should be present. // - Form: _charset_ should not be kept verbatim, // seeing as Safari/Chromium/Firefox all pass UTF-8, // in accordance with HTML5. w.WriteHeader(http.StatusTeapot) } else { fmt.Fprintf(file, "%s %s\n %s\n", time.Now().Local().Format(time.RFC1123), r.RequestURI, wrap(text)) if err := file.Sync(); err != nil { log.Fatalln(err) } // To help filter out spammers. fmt.Fprintf(requests, "%s\n", j) if err := requests.Sync(); err != nil { log.Fatalln(err) } fmt.Fprintln(w, "Saved.") } } func main() { if len(os.Args) != 3 { log.Fatalf("Usage: %s BIND DB\n", os.Args[0]) } var err error if file, err = os.OpenFile(os.Args[2], os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644); err != nil { log.Fatalln(err) } if requests, err = os.OpenFile(os.Args[2]+".requests", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644); err != nil { log.Fatalln(err) } http.HandleFunc("/", handler) log.Fatalln(http.ListenAndServe(os.Args[1], nil)) }