package main import ( "net/http" "net/url" "path" "strings" ) const ( errSrcInvalid = "source is not a parsable URL" errTgtNotAccepted = "can not process webmentions for this target" errInvalidScheme = "URL scheme is not HTTP(S)" ) // endpoint is a webmention receiver. type endpoint struct { allowPrefix string // host (or host:port) and path prefix for the targets served by this endpoint } // ServeHTTP is http.Handler implementation. func (ep endpoint) ServeHTTP(w http.ResponseWriter, r *http.Request) { source, err := url.Parse(r.PostFormValue("source")) if err != nil || source.Host == "" { w.WriteHeader(http.StatusBadRequest) w.Write([]byte(errSrcInvalid)) return } if source.Scheme != "http" && source.Scheme != "https" { w.WriteHeader(http.StatusBadRequest) w.Write([]byte(errInvalidScheme)) return } target, err := url.Parse(r.PostFormValue("target")) if err != nil || !ep.targetAllowed(target) { w.WriteHeader(http.StatusBadRequest) w.Write([]byte(errTgtNotAccepted)) return } if target.Scheme != "http" && target.Scheme != "https" { w.WriteHeader(http.StatusBadRequest) w.Write([]byte(errInvalidScheme)) return } } // targetAllowed shows whether ep can accept a webmention for the target. func (ep endpoint) targetAllowed(target *url.URL) bool { if !strings.HasSuffix(ep.allowPrefix, "/") { ep.allowPrefix = ep.allowPrefix + "/" } tgt := path.Join(target.Host, target.Path) if !strings.HasSuffix(tgt, "/") { tgt = tgt + "/" } return strings.HasPrefix(tgt, ep.allowPrefix) }