|
|
@@ -8,10 +8,14 @@ import (
|
|
|
"mime"
|
|
|
"net/http"
|
|
|
"net/netip"
|
|
|
+ "regexp"
|
|
|
"strings"
|
|
|
)
|
|
|
|
|
|
-var mimeDecoder mime.WordDecoder
|
|
|
+var (
|
|
|
+ mimeDecoder mime.WordDecoder
|
|
|
+ priorityHeaderIgnoreRegex = regexp.MustCompile(`^u=\d,\s*(i|\d)$|^u=\d$`)
|
|
|
+)
|
|
|
|
|
|
func readBoolParam(r *http.Request, defaultValue bool, names ...string) bool {
|
|
|
value := strings.ToLower(readParam(r, names...))
|
|
|
@@ -50,9 +54,9 @@ func readParam(r *http.Request, names ...string) string {
|
|
|
|
|
|
func readHeaderParam(r *http.Request, names ...string) string {
|
|
|
for _, name := range names {
|
|
|
- value := maybeDecodeHeader(r.Header.Get(name))
|
|
|
+ value := strings.TrimSpace(maybeDecodeHeader(name, r.Header.Get(name)))
|
|
|
if value != "" {
|
|
|
- return strings.TrimSpace(value)
|
|
|
+ return value
|
|
|
}
|
|
|
}
|
|
|
return ""
|
|
|
@@ -126,10 +130,26 @@ func fromContext[T any](r *http.Request, key contextKey) (T, error) {
|
|
|
return t, nil
|
|
|
}
|
|
|
|
|
|
-func maybeDecodeHeader(header string) string {
|
|
|
- decoded, err := mimeDecoder.DecodeHeader(header)
|
|
|
+// maybeDecodeHeader decodes the given header value if it is MIME encoded, e.g. "=?utf-8?q?Hello_World?=",
|
|
|
+// or returns the original header value if it is not MIME encoded. It also calls maybeIgnoreSpecialHeader
|
|
|
+// to ignore new HTTP "Priority" header.
|
|
|
+func maybeDecodeHeader(name, value string) string {
|
|
|
+ decoded, err := mimeDecoder.DecodeHeader(value)
|
|
|
if err != nil {
|
|
|
- return header
|
|
|
+ return maybeIgnoreSpecialHeader(name, value)
|
|
|
+ }
|
|
|
+ return maybeIgnoreSpecialHeader(name, decoded)
|
|
|
+}
|
|
|
+
|
|
|
+// maybeIgnoreSpecialHeader ignores new HTTP "Priority" header (see https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-priority)
|
|
|
+//
|
|
|
+// Cloudflare (and potentially other providers) add this to requests when forwarding to the backend (ntfy),
|
|
|
+// so we just ignore it. If the "Priority" header is set to "u=*, i" or "u=*" (by Cloudflare), the header will be ignored.
|
|
|
+// Returning an empty string will allow the rest of the logic to continue searching for another header (x-priority, prio, p),
|
|
|
+// or in the Query parameters.
|
|
|
+func maybeIgnoreSpecialHeader(name, value string) string {
|
|
|
+ if strings.ToLower(name) == "priority" && priorityHeaderIgnoreRegex.MatchString(strings.TrimSpace(value)) {
|
|
|
+ return ""
|
|
|
}
|
|
|
- return decoded
|
|
|
+ return value
|
|
|
}
|