This commit is contained in:
Philipp Heckel 2022-04-03 20:19:43 -04:00
parent b3667a916b
commit 73349cd423
4 changed files with 43 additions and 35 deletions

View file

@ -42,7 +42,7 @@ var (
errHTTPNotFound = &errHTTP{40401, http.StatusNotFound, "page not found", ""} errHTTPNotFound = &errHTTP{40401, http.StatusNotFound, "page not found", ""}
errHTTPUnauthorized = &errHTTP{40101, http.StatusUnauthorized, "unauthorized", "https://ntfy.sh/docs/publish/#authentication"} errHTTPUnauthorized = &errHTTP{40101, http.StatusUnauthorized, "unauthorized", "https://ntfy.sh/docs/publish/#authentication"}
errHTTPForbidden = &errHTTP{40301, http.StatusForbidden, "forbidden", "https://ntfy.sh/docs/publish/#authentication"} errHTTPForbidden = &errHTTP{40301, http.StatusForbidden, "forbidden", "https://ntfy.sh/docs/publish/#authentication"}
errHTTPEntityTooLargeAttachmentTooLarge = &errHTTP{41301, http.StatusRequestEntityTooLarge, "attachment too large, or bandwidth limit reached", ""} errHTTPEntityTooLargeAttachmentTooLarge = &errHTTP{41301, http.StatusRequestEntityTooLarge, "attachment too large, or bandwidth limit reached", "https://ntfy.sh/docs/publish/#limitations"}
errHTTPTooManyRequestsLimitRequests = &errHTTP{42901, http.StatusTooManyRequests, "limit reached: too many requests, please be nice", "https://ntfy.sh/docs/publish/#limitations"} errHTTPTooManyRequestsLimitRequests = &errHTTP{42901, http.StatusTooManyRequests, "limit reached: too many requests, please be nice", "https://ntfy.sh/docs/publish/#limitations"}
errHTTPTooManyRequestsLimitEmails = &errHTTP{42902, http.StatusTooManyRequests, "limit reached: too many emails, please be nice", "https://ntfy.sh/docs/publish/#limitations"} errHTTPTooManyRequestsLimitEmails = &errHTTP{42902, http.StatusTooManyRequests, "limit reached: too many emails, please be nice", "https://ntfy.sh/docs/publish/#limitations"}
errHTTPTooManyRequestsLimitSubscriptions = &errHTTP{42903, http.StatusTooManyRequests, "limit reached: too many active subscriptions, please be nice", "https://ntfy.sh/docs/publish/#limitations"} errHTTPTooManyRequestsLimitSubscriptions = &errHTTP{42903, http.StatusTooManyRequests, "limit reached: too many active subscriptions, please be nice", "https://ntfy.sh/docs/publish/#limitations"}

View file

@ -1024,9 +1024,9 @@ func TestServer_PublishAttachmentTooLargeContentLength(t *testing.T) {
"Content-Length": "20000000", "Content-Length": "20000000",
}) })
err := toHTTPError(t, response.Body.String()) err := toHTTPError(t, response.Body.String())
require.Equal(t, 400, response.Code) require.Equal(t, 413, response.Code)
require.Equal(t, 400, err.HTTPCode) require.Equal(t, 413, err.HTTPCode)
require.Equal(t, 40012, err.Code) require.Equal(t, 41301, err.Code)
} }
func TestServer_PublishAttachmentTooLargeBodyAttachmentFileSizeLimit(t *testing.T) { func TestServer_PublishAttachmentTooLargeBodyAttachmentFileSizeLimit(t *testing.T) {
@ -1036,9 +1036,9 @@ func TestServer_PublishAttachmentTooLargeBodyAttachmentFileSizeLimit(t *testing.
s := newTestServer(t, c) s := newTestServer(t, c)
response := request(t, s, "PUT", "/mytopic", content, nil) response := request(t, s, "PUT", "/mytopic", content, nil)
err := toHTTPError(t, response.Body.String()) err := toHTTPError(t, response.Body.String())
require.Equal(t, 400, response.Code) require.Equal(t, 413, response.Code)
require.Equal(t, 400, err.HTTPCode) require.Equal(t, 413, err.HTTPCode)
require.Equal(t, 40012, err.Code) require.Equal(t, 41301, err.Code)
} }
func TestServer_PublishAttachmentExpiryBeforeDelivery(t *testing.T) { func TestServer_PublishAttachmentExpiryBeforeDelivery(t *testing.T) {
@ -1068,9 +1068,9 @@ func TestServer_PublishAttachmentTooLargeBodyVisitorAttachmentTotalSizeLimit(t *
content := util.RandomString(5001) // 5000+5001 > , see below content := util.RandomString(5001) // 5000+5001 > , see below
response = request(t, s, "PUT", "/mytopic", content, nil) response = request(t, s, "PUT", "/mytopic", content, nil)
err := toHTTPError(t, response.Body.String()) err := toHTTPError(t, response.Body.String())
require.Equal(t, 400, response.Code) require.Equal(t, 413, response.Code)
require.Equal(t, 400, err.HTTPCode) require.Equal(t, 413, err.HTTPCode)
require.Equal(t, 40012, err.Code) require.Equal(t, 41301, err.Code)
} }
func TestServer_PublishAttachmentAndPrune(t *testing.T) { func TestServer_PublishAttachmentAndPrune(t *testing.T) {
@ -1144,8 +1144,32 @@ func TestServer_PublishAttachmentBandwidthLimitUploadOnly(t *testing.T) {
// And a failed one // And a failed one
response := request(t, s, "PUT", "/mytopic", content, nil) response := request(t, s, "PUT", "/mytopic", content, nil)
err := toHTTPError(t, response.Body.String()) err := toHTTPError(t, response.Body.String())
require.Equal(t, 400, response.Code) require.Equal(t, 413, response.Code)
require.Equal(t, 40012, err.Code) require.Equal(t, 41301, err.Code)
}
func TestServer_PublishAttachmentUserStats(t *testing.T) {
content := util.RandomString(4999) // > 4096
c := newTestConfig(t)
c.AttachmentFileSizeLimit = 5000
c.VisitorAttachmentTotalSizeLimit = 6000
s := newTestServer(t, c)
// Upload one attachment
response := request(t, s, "PUT", "/mytopic", content, nil)
msg := toMessage(t, response.Body.String())
require.Contains(t, msg.Attachment.URL, "http://127.0.0.1:12345/file/")
// User stats
response = request(t, s, "GET", "/user/stats", "", nil)
require.Equal(t, 200, response.Code)
var stats visitorStats
require.Nil(t, json.NewDecoder(strings.NewReader(response.Body.String())).Decode(&stats))
require.Equal(t, int64(5000), stats.AttachmentFileSizeLimit)
require.Equal(t, int64(6000), stats.VisitorAttachmentBytesTotal)
require.Equal(t, int64(4999), stats.VisitorAttachmentBytesUsed)
require.Equal(t, int64(1001), stats.VisitorAttachmentBytesRemaining)
} }
func newTestConfig(t *testing.T) *Config { func newTestConfig(t *testing.T) *Config {

View file

@ -15,10 +15,6 @@ var ErrLimitReached = errors.New("limit reached")
type Limiter interface { type Limiter interface {
// Allow adds n to the limiters internal value, or returns ErrLimitReached if the limit has been reached // Allow adds n to the limiters internal value, or returns ErrLimitReached if the limit has been reached
Allow(n int64) error Allow(n int64) error
// Remaining returns the remaining count until the limit is reached; may return -1 if the implementation
// does not support this operation.
Remaining() int64
} }
// FixedLimiter is a helper that allows adding values up to a well-defined limit. Once the limit is reached // FixedLimiter is a helper that allows adding values up to a well-defined limit. Once the limit is reached
@ -48,13 +44,6 @@ func (l *FixedLimiter) Allow(n int64) error {
return nil return nil
} }
// Remaining returns the remaining count until the limit is reached
func (l *FixedLimiter) Remaining() int64 {
l.mu.Lock()
defer l.mu.Unlock()
return l.limit - l.value
}
// RateLimiter is a Limiter that wraps a rate.Limiter, allowing a floating time-based limit. // RateLimiter is a Limiter that wraps a rate.Limiter, allowing a floating time-based limit.
type RateLimiter struct { type RateLimiter struct {
limiter *rate.Limiter limiter *rate.Limiter
@ -85,11 +74,6 @@ func (l *RateLimiter) Allow(n int64) error {
return nil return nil
} }
// Remaining is not implemented for RateLimiter. It always returns -1.
func (l *RateLimiter) Remaining() int64 {
return -1
}
// LimitWriter implements an io.Writer that will pass through all Write calls to the underlying // LimitWriter implements an io.Writer that will pass through all Write calls to the underlying
// writer w until any of the limiter's limit is reached, at which point a Write will return ErrLimitReached. // writer w until any of the limiter's limit is reached, at which point a Write will return ErrLimitReached.
// Each limiter's value is increased with every write. // Each limiter's value is increased with every write.

View file

@ -51,6 +51,13 @@ class Api {
console.log(`[Api] Publishing message to ${url}`); console.log(`[Api] Publishing message to ${url}`);
const send = new Promise(function (resolve, reject) { const send = new Promise(function (resolve, reject) {
xhr.open("PUT", url); xhr.open("PUT", url);
if (body.type) {
xhr.overrideMimeType(body.type);
}
for (const [key, value] of Object.entries(headers)) {
xhr.setRequestHeader(key, value);
}
xhr.upload.addEventListener("progress", onProgress);
xhr.addEventListener('readystatechange', (ev) => { xhr.addEventListener('readystatechange', (ev) => {
if (xhr.readyState === 4 && xhr.status >= 200 && xhr.status <= 299) { if (xhr.readyState === 4 && xhr.status >= 200 && xhr.status <= 299) {
console.log(`[Api] Publish successful (HTTP ${xhr.status})`, xhr.response); console.log(`[Api] Publish successful (HTTP ${xhr.status})`, xhr.response);
@ -70,13 +77,6 @@ class Api {
reject(errorText ?? "An error occurred"); reject(errorText ?? "An error occurred");
} }
}) })
xhr.upload.addEventListener("progress", onProgress);
if (body.type) {
xhr.overrideMimeType(body.type);
}
for (const [key, value] of Object.entries(headers)) {
xhr.setRequestHeader(key, value);
}
xhr.send(body); xhr.send(body);
}); });
send.abort = () => { send.abort = () => {