diff options
| -rw-r--r-- | hpcu/main.go | 6 | ||||
| -rw-r--r-- | hswc/main.go | 101 |
2 files changed, 105 insertions, 2 deletions
diff --git a/hpcu/main.go b/hpcu/main.go index 3508f63..68d65b2 100644 --- a/hpcu/main.go +++ b/hpcu/main.go @@ -3,10 +3,11 @@ package main import ( "errors" + "log" + "janouch.name/haven/nexgb" "janouch.name/haven/nexgb/xfixes" "janouch.name/haven/nexgb/xproto" - "log" ) type selectionState struct { @@ -288,7 +289,8 @@ func handleSelectionRequest(e xproto.SelectionRequestEvent) { } if typ == 0 || len(data) > int(setup.MaximumRequestLength)*4-64 || - state.owning == 0 || e.Time < state.owning { + state.owning == 0 || + (e.Time != xproto.TimeCurrentTime && e.Time < state.owning) { // TODO: Use the INCR mechanism for large data transfers instead // of refusing the request, or at least use PropModeAppend. // 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)) +} |
