diff options
| -rw-r--r-- | hswc/main.go | 101 | 
1 files changed, 101 insertions, 0 deletions
| diff --git a/hswc/main.go b/hswc/main.go new file mode 100644 index 0000000..275aac6 --- /dev/null +++ b/hswc/main.go @@ -0,0 +1,101 @@ +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") { +		// <input type="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)) +} | 
