aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPřemysl Eric Janouch <p@janouch.name>2022-10-06 00:44:09 +0200
committerPřemysl Eric Janouch <p@janouch.name>2024-11-03 06:12:31 +0100
commit486b58525fc5ec7658b7c90f0179ea3d112d0ca4 (patch)
tree4115a0bb66b30485eae82a52ed2ad179c1c390e2
parentc3cc608570aa473d8777496e857e69637507da25 (diff)
downloadhaven-486b58525fc5ec7658b7c90f0179ea3d112d0ca4.tar.gz
haven-486b58525fc5ec7658b7c90f0179ea3d112d0ca4.tar.xz
haven-486b58525fc5ec7658b7c90f0179ea3d112d0ca4.zip
Add a basic tool for collecting web commentsorigin/master
-rw-r--r--hswc/main.go101
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))
+}