Fail early for too-large attachments
parent
289a6fdd0f
commit
68a324c206
|
@ -139,7 +139,7 @@ var (
|
|||
errHTTPBadRequestTopicInvalid = &errHTTP{40009, http.StatusBadRequest, "invalid topic: path invalid", ""}
|
||||
errHTTPBadRequestTopicDisallowed = &errHTTP{40010, http.StatusBadRequest, "invalid topic: topic name is disallowed", ""}
|
||||
errHTTPBadRequestMessageNotUTF8 = &errHTTP{40011, http.StatusBadRequest, "invalid message: message must be UTF-8 encoded", ""}
|
||||
errHTTPBadRequestMessageTooLarge = &errHTTP{40012, http.StatusBadRequest, "invalid message: too large", ""}
|
||||
errHTTPBadRequestAttachmentTooLarge = &errHTTP{40012, http.StatusBadRequest, "invalid request: attachment too large", ""}
|
||||
errHTTPBadRequestAttachmentURLInvalid = &errHTTP{40013, http.StatusBadRequest, "invalid request: attachment URL is invalid", ""}
|
||||
errHTTPBadRequestAttachmentURLPeakGeneral = &errHTTP{40014, http.StatusBadRequest, "invalid request: attachment URL peak failed", ""}
|
||||
errHTTPBadRequestAttachmentURLPeakNon2xx = &errHTTP{40015, http.StatusBadRequest, "invalid request: attachment URL peak failed with non-2xx status code", ""}
|
||||
|
@ -458,7 +458,7 @@ func (s *Server) handlePublish(w http.ResponseWriter, r *http.Request, v *visito
|
|||
if err := maybePeakAttachmentURL(m); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.handlePublishBody(v, m, body); err != nil {
|
||||
if err := s.handlePublishBody(r, v, m, body); err != nil {
|
||||
return err
|
||||
}
|
||||
if m.Message == "" {
|
||||
|
@ -592,15 +592,15 @@ func readParam(r *http.Request, names ...string) string {
|
|||
// If file.txt is <= 4096 (message limit) and valid UTF-8, treat it as a message
|
||||
// 4. curl -T file.txt ntfy.sh/mytopic
|
||||
// If file.txt is > message limit, treat it as an attachment
|
||||
func (s *Server) handlePublishBody(v *visitor, m *message, body *util.PeakedReadCloser) error {
|
||||
func (s *Server) handlePublishBody(r *http.Request, v *visitor, m *message, body *util.PeakedReadCloser) error {
|
||||
if m.Attachment != nil && m.Attachment.URL != "" {
|
||||
return s.handleBodyAsMessage(m, body) // Case 1
|
||||
} else if m.Attachment != nil && m.Attachment.Name != "" {
|
||||
return s.handleBodyAsAttachment(v, m, body) // Case 2
|
||||
return s.handleBodyAsAttachment(r, v, m, body) // Case 2
|
||||
} else if !body.LimitReached && utf8.Valid(body.PeakedBytes) {
|
||||
return s.handleBodyAsMessage(m, body) // Case 3
|
||||
}
|
||||
return s.handleBodyAsAttachment(v, m, body) // Case 4
|
||||
return s.handleBodyAsAttachment(r, v, m, body) // Case 4
|
||||
}
|
||||
|
||||
func (s *Server) handleBodyAsMessage(m *message, body *util.PeakedReadCloser) error {
|
||||
|
@ -616,16 +616,27 @@ func (s *Server) handleBodyAsMessage(m *message, body *util.PeakedReadCloser) er
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) handleBodyAsAttachment(v *visitor, m *message, body *util.PeakedReadCloser) error {
|
||||
func (s *Server) handleBodyAsAttachment(r *http.Request, v *visitor, m *message, body *util.PeakedReadCloser) error {
|
||||
if s.fileCache == nil {
|
||||
return errHTTPBadRequestAttachmentsDisallowed
|
||||
} else if m.Time > time.Now().Add(s.config.AttachmentExpiryDuration).Unix() {
|
||||
return errHTTPBadRequestAttachmentsExpiryBeforeDelivery
|
||||
}
|
||||
visitorAttachmentsSize, err := s.cache.AttachmentsSize(v.ip)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
remainingVisitorAttachmentSize := s.config.VisitorAttachmentTotalSizeLimit - visitorAttachmentsSize
|
||||
contentLengthStr := r.Header.Get("Content-Length")
|
||||
if contentLengthStr != "" { // Early "do-not-trust" check, hard limit see below
|
||||
contentLength, err := strconv.ParseInt(contentLengthStr, 10, 64)
|
||||
if err == nil && (contentLength > remainingVisitorAttachmentSize || contentLength > s.config.AttachmentFileSizeLimit) {
|
||||
return errHTTPBadRequestAttachmentTooLarge
|
||||
}
|
||||
}
|
||||
if m.Attachment == nil {
|
||||
m.Attachment = &attachment{}
|
||||
}
|
||||
var err error
|
||||
var ext string
|
||||
m.Attachment.Owner = v.ip // Important for attachment rate limiting
|
||||
m.Attachment.Expires = time.Now().Add(s.config.AttachmentExpiryDuration).Unix()
|
||||
|
@ -637,18 +648,12 @@ func (s *Server) handleBodyAsAttachment(v *visitor, m *message, body *util.Peake
|
|||
if m.Message == "" {
|
||||
m.Message = fmt.Sprintf(defaultAttachmentMessage, m.Attachment.Name)
|
||||
}
|
||||
visitorAttachmentsSize, err := s.cache.AttachmentsSize(v.ip)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
remainingVisitorAttachmentSize := s.config.VisitorAttachmentTotalSizeLimit - visitorAttachmentsSize
|
||||
m.Attachment.Size, err = s.fileCache.Write(m.ID, body, util.NewLimiter(remainingVisitorAttachmentSize))
|
||||
if err == util.ErrLimitReached {
|
||||
return errHTTPBadRequestMessageTooLarge
|
||||
return errHTTPBadRequestAttachmentTooLarge
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue