mirror of
https://github.com/binwiederhier/ntfy.git
synced 2024-12-14 11:47:33 +00:00
Tests
This commit is contained in:
parent
a04f2f9c9a
commit
b9c176ddba
4 changed files with 81 additions and 70 deletions
|
@ -119,6 +119,8 @@ var (
|
||||||
errHTTPBadRequestWebPushTopicCountTooHigh = &errHTTP{40040, http.StatusBadRequest, "invalid request: too many web push topic subscriptions", "", nil}
|
errHTTPBadRequestWebPushTopicCountTooHigh = &errHTTP{40040, http.StatusBadRequest, "invalid request: too many web push topic subscriptions", "", nil}
|
||||||
errHTTPBadRequestTemplatedMessageTooLarge = &errHTTP{40041, http.StatusBadRequest, "invalid request: message or title is too large after replacing template", "", nil}
|
errHTTPBadRequestTemplatedMessageTooLarge = &errHTTP{40041, http.StatusBadRequest, "invalid request: message or title is too large after replacing template", "", nil}
|
||||||
errHTTPBadRequestTemplatedMessageNotJSON = &errHTTP{40042, http.StatusBadRequest, "invalid request: message body must be JSON if templating is enabled", "", nil}
|
errHTTPBadRequestTemplatedMessageNotJSON = &errHTTP{40042, http.StatusBadRequest, "invalid request: message body must be JSON if templating is enabled", "", nil}
|
||||||
|
errHTTPBadRequestTemplateInvalid = &errHTTP{40043, http.StatusBadRequest, "invalid request: could not parse template", "", nil}
|
||||||
|
errHTTPBadRequestTemplateExecutionFailed = &errHTTP{40044, http.StatusBadRequest, "invalid request: template execution failed", "", nil}
|
||||||
errHTTPNotFound = &errHTTP{40401, http.StatusNotFound, "page not found", "", nil}
|
errHTTPNotFound = &errHTTP{40401, http.StatusNotFound, "page not found", "", nil}
|
||||||
errHTTPUnauthorized = &errHTTP{40101, http.StatusUnauthorized, "unauthorized", "https://ntfy.sh/docs/publish/#authentication", nil}
|
errHTTPUnauthorized = &errHTTP{40101, http.StatusUnauthorized, "unauthorized", "https://ntfy.sh/docs/publish/#authentication", nil}
|
||||||
errHTTPForbidden = &errHTTP{40301, http.StatusForbidden, "forbidden", "https://ntfy.sh/docs/publish/#authentication", nil}
|
errHTTPForbidden = &errHTTP{40301, http.StatusForbidden, "forbidden", "https://ntfy.sh/docs/publish/#authentication", nil}
|
||||||
|
|
|
@ -135,6 +135,7 @@ const (
|
||||||
unifiedPushTopicPrefix = "up" // Temporarily, we rate limit all "up*" topics based on the subscriber
|
unifiedPushTopicPrefix = "up" // Temporarily, we rate limit all "up*" topics based on the subscriber
|
||||||
unifiedPushTopicLength = 14 // Length of UnifiedPush topics, including the "up" part
|
unifiedPushTopicLength = 14 // Length of UnifiedPush topics, including the "up" part
|
||||||
messagesHistoryMax = 10 // Number of message count values to keep in memory
|
messagesHistoryMax = 10 // Number of message count values to keep in memory
|
||||||
|
templateMaxExecutionTime = 100 * time.Millisecond
|
||||||
)
|
)
|
||||||
|
|
||||||
// WebSocket constants
|
// WebSocket constants
|
||||||
|
@ -1102,34 +1103,30 @@ func (s *Server) handleBodyAsTemplatedTextMessage(m *message, body *util.PeekedR
|
||||||
return errHTTPEntityTooLargeJSONBody
|
return errHTTPEntityTooLargeJSONBody
|
||||||
}
|
}
|
||||||
peekedBody := strings.TrimSpace(string(body.PeekedBytes))
|
peekedBody := strings.TrimSpace(string(body.PeekedBytes))
|
||||||
m.Message = replaceTemplate(m.Message, peekedBody)
|
if m.Message, err = replaceTemplate(m.Message, peekedBody); err != nil {
|
||||||
m.Title = replaceTemplate(m.Title, peekedBody)
|
return err
|
||||||
|
}
|
||||||
|
if m.Title, err = replaceTemplate(m.Title, peekedBody); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if len(m.Message) > s.config.MessageSizeLimit {
|
if len(m.Message) > s.config.MessageSizeLimit {
|
||||||
return errHTTPBadRequestTemplatedMessageTooLarge
|
return errHTTPBadRequestTemplatedMessageTooLarge
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func replaceTemplate(tpl string, source string) string {
|
func replaceTemplate(tpl string, source string) (string, error) {
|
||||||
rendered, err := replaceTemplateInternal(tpl, source)
|
|
||||||
if err != nil {
|
|
||||||
return "<invalid template>"
|
|
||||||
}
|
|
||||||
return rendered
|
|
||||||
}
|
|
||||||
|
|
||||||
func replaceTemplateInternal(tpl string, source string) (string, error) {
|
|
||||||
var data any
|
var data any
|
||||||
if err := json.Unmarshal([]byte(source), &data); err != nil {
|
if err := json.Unmarshal([]byte(source), &data); err != nil {
|
||||||
return "", err
|
return "", errHTTPBadRequestTemplatedMessageNotJSON
|
||||||
}
|
}
|
||||||
t, err := template.New("").Parse(tpl)
|
t, err := template.New("").Parse(tpl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", errHTTPBadRequestTemplateInvalid
|
||||||
}
|
}
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
if err := t.Execute(&buf, data); err != nil {
|
if err := t.Execute(util.NewTimeoutWriter(&buf, templateMaxExecutionTime), data); err != nil {
|
||||||
return "", err
|
return "", errHTTPBadRequestTemplateExecutionFailed
|
||||||
}
|
}
|
||||||
return buf.String(), nil
|
return buf.String(), nil
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
34
util/timeout_writer.go
Normal file
34
util/timeout_writer.go
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ErrWriteTimeout is returned when a write timed out
|
||||||
|
var ErrWriteTimeout = errors.New("write operation failed due to timeout since creation")
|
||||||
|
|
||||||
|
// TimeoutWriter wraps an io.Writer that will time out after the given timeout
|
||||||
|
type TimeoutWriter struct {
|
||||||
|
writer io.Writer
|
||||||
|
timeout time.Duration
|
||||||
|
start time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTimeoutWriter creates a new TimeoutWriter
|
||||||
|
func NewTimeoutWriter(w io.Writer, timeout time.Duration) *TimeoutWriter {
|
||||||
|
return &TimeoutWriter{
|
||||||
|
writer: w,
|
||||||
|
timeout: timeout,
|
||||||
|
start: time.Now(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write implements the io.Writer interface, failing if called after the timeout period from creation.
|
||||||
|
func (tw *TimeoutWriter) Write(p []byte) (n int, err error) {
|
||||||
|
if time.Since(tw.start) > tw.timeout {
|
||||||
|
return 0, errors.New("write operation failed due to timeout since creation")
|
||||||
|
}
|
||||||
|
return tw.writer.Write(p)
|
||||||
|
}
|
Loading…
Reference in a new issue