mirror of
https://github.com/binwiederhier/ntfy.git
synced 2024-05-17 19:03:29 +12:00
allow large HTTP body so long as resulting message is small
This commit is contained in:
parent
03737dbf5c
commit
7fd5f0b29d
|
@ -117,6 +117,7 @@ var (
|
||||||
errHTTPBadRequestWebPushSubscriptionInvalid = &errHTTP{40038, http.StatusBadRequest, "invalid request: web push payload malformed", "", nil}
|
errHTTPBadRequestWebPushSubscriptionInvalid = &errHTTP{40038, http.StatusBadRequest, "invalid request: web push payload malformed", "", nil}
|
||||||
errHTTPBadRequestWebPushEndpointUnknown = &errHTTP{40039, http.StatusBadRequest, "invalid request: web push endpoint unknown", "", nil}
|
errHTTPBadRequestWebPushEndpointUnknown = &errHTTP{40039, http.StatusBadRequest, "invalid request: web push endpoint unknown", "", nil}
|
||||||
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 is too large after replacing template", "", 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}
|
||||||
|
|
|
@ -1044,8 +1044,11 @@ func (s *Server) parsePublishParams(r *http.Request, m *message) (cache bool, fi
|
||||||
// Body must be attachment, because we passed a filename
|
// Body must be attachment, because we passed a filename
|
||||||
// 5. curl -T file.txt ntfy.sh/mytopic
|
// 5. curl -T file.txt ntfy.sh/mytopic
|
||||||
// If file.txt is <= 4096 (message limit) and valid UTF-8, treat it as a message
|
// If file.txt is <= 4096 (message limit) and valid UTF-8, treat it as a message
|
||||||
// 6. curl -T file.txt ntfy.sh/mytopic
|
// 6. curl -H "Template: yes" -T file.txt ntfy.sh/mytopic
|
||||||
// If file.txt is > message limit, treat it as an attachment
|
// If file.txt is < 4096*2 (message limit*2) and a template is used, try parsing under the assumption
|
||||||
|
// that the message generated by the template will be less than 4096
|
||||||
|
// 7. curl -T file.txt ntfy.sh/mytopic
|
||||||
|
// If file.txt is > message limit or template && file.txt > message limit*2, treat it as an attachment
|
||||||
func (s *Server) handlePublishBody(r *http.Request, v *visitor, m *message, body *util.PeekedReadCloser, template bool, unifiedpush bool) error {
|
func (s *Server) handlePublishBody(r *http.Request, v *visitor, m *message, body *util.PeekedReadCloser, template bool, unifiedpush bool) error {
|
||||||
if m.Event == pollRequestEvent { // Case 1
|
if m.Event == pollRequestEvent { // Case 1
|
||||||
return s.handleBodyDiscard(body)
|
return s.handleBodyDiscard(body)
|
||||||
|
@ -1057,8 +1060,16 @@ func (s *Server) handlePublishBody(r *http.Request, v *visitor, m *message, body
|
||||||
return s.handleBodyAsAttachment(r, v, m, body) // Case 4
|
return s.handleBodyAsAttachment(r, v, m, body) // Case 4
|
||||||
} else if !body.LimitReached && utf8.Valid(body.PeekedBytes) {
|
} else if !body.LimitReached && utf8.Valid(body.PeekedBytes) {
|
||||||
return s.handleBodyAsTextMessage(m, body, template) // Case 5
|
return s.handleBodyAsTextMessage(m, body, template) // Case 5
|
||||||
|
} else if template {
|
||||||
|
templateBody, err := util.Peek(body, s.config.MessageSizeLimit*2)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !templateBody.LimitReached {
|
||||||
|
return s.handleBodyAsTextMessage(m, templateBody, template) // Case 6
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return s.handleBodyAsAttachment(r, v, m, body) // Case 6
|
return s.handleBodyAsAttachment(r, v, m, body) // Case 7
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) handleBodyDiscard(body *util.PeekedReadCloser) error {
|
func (s *Server) handleBodyDiscard(body *util.PeekedReadCloser) error {
|
||||||
|
@ -1104,6 +1115,10 @@ func (s *Server) handleBodyAsTextMessage(m *message, body *util.PeekedReadCloser
|
||||||
if m.Attachment != nil && m.Attachment.Name != "" && m.Message == "" {
|
if m.Attachment != nil && m.Attachment.Name != "" && m.Message == "" {
|
||||||
m.Message = fmt.Sprintf(defaultAttachmentMessage, m.Attachment.Name)
|
m.Message = fmt.Sprintf(defaultAttachmentMessage, m.Attachment.Name)
|
||||||
}
|
}
|
||||||
|
// Ensure message is less than message limit after templating
|
||||||
|
if len(m.Message) > s.config.MessageSizeLimit {
|
||||||
|
return errHTTPBadRequestTemplatedMessageTooLarge
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2754,6 +2754,35 @@ func TestServer_MessageTemplate_FancyGJSON(t *testing.T) {
|
||||||
require.Equal(t, `2 Severe Errors`, m.Title)
|
require.Equal(t, `2 Severe Errors`, m.Title)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestServer_MessageTemplate_ExceedMessageSize_TemplatedMessageOK(t *testing.T) {
|
||||||
|
c := newTestConfig(t)
|
||||||
|
c.MessageSizeLimit = 25 // 25 < len(HTTP body) < 25*2 && len(m.Message) < 25
|
||||||
|
s := newTestServer(t, c)
|
||||||
|
response := request(t, s, "PUT", "/mytopic", `{"foo":"bar", "nested":{"title":"here"}}`, map[string]string{
|
||||||
|
"X-Message": "${foo}",
|
||||||
|
"X-Title": "${nested.title}",
|
||||||
|
"X-Template": "1",
|
||||||
|
})
|
||||||
|
|
||||||
|
require.Equal(t, 200, response.Code)
|
||||||
|
m := toMessage(t, response.Body.String())
|
||||||
|
require.Equal(t, "bar", m.Message)
|
||||||
|
require.Equal(t, "here", m.Title)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestServer_MessageTemplate_ExceedMessageSize_TemplatedMessageTooLong(t *testing.T) {
|
||||||
|
c := newTestConfig(t)
|
||||||
|
c.MessageSizeLimit = 21 // 21 < len(HTTP body) < 21*2 && !len(m.Message) < 21
|
||||||
|
s := newTestServer(t, c)
|
||||||
|
response := request(t, s, "PUT", "/mytopic", `{"foo":"This is a long message"}`, map[string]string{
|
||||||
|
"X-Message": "${foo}",
|
||||||
|
"X-Template": "1",
|
||||||
|
})
|
||||||
|
|
||||||
|
require.Equal(t, 400, response.Code)
|
||||||
|
require.Equal(t, 40041, toHTTPError(t, response.Body.String()).Code)
|
||||||
|
}
|
||||||
|
|
||||||
func newTestConfig(t *testing.T) *Config {
|
func newTestConfig(t *testing.T) *Config {
|
||||||
conf := NewConfig()
|
conf := NewConfig()
|
||||||
conf.BaseURL = "http://127.0.0.1:12345"
|
conf.BaseURL = "http://127.0.0.1:12345"
|
||||||
|
|
Loading…
Reference in a new issue