Beispiel #1
0
    def test_error(self, metrics):
        limiter = RateLimiter(
            storage.MemoryStorage(),
            "1 per minute",
            identifiers=["foo"],
            metrics=metrics,
        )

        def raiser(*args, **kwargs):
            raise redis.ConnectionError()

        limiter._window = pretend.stub(hit=raiser,
                                       test=raiser,
                                       get_window_stats=raiser)

        assert limiter.test("foo")
        assert limiter.hit("foo")
        assert limiter.resets_in("foo") is None

        assert metrics.increment.calls == [
            pretend.call("warehouse.ratelimiter.error", tags=["call:test"]),
            pretend.call("warehouse.ratelimiter.error", tags=["call:hit"]),
            pretend.call("warehouse.ratelimiter.error",
                         tags=["call:resets_in"]),
        ]
Beispiel #2
0
    def test_results_in(self):
        limiter = RateLimiter(storage.MemoryStorage(), "1 per minute")

        assert limiter.resets_in("foo") is None

        while limiter.hit("foo"):
            pass

        assert limiter.resets_in("foo") > datetime.timedelta(seconds=0)
        assert limiter.resets_in("foo") < datetime.timedelta(seconds=60)
Beispiel #3
0
    def test_namespacing(self):
        storage_ = storage.MemoryStorage()
        limiter1 = RateLimiter(storage_, "1 per minute", identifiers=["foo"])
        limiter2 = RateLimiter(storage_, "1 per minute")

        assert limiter1.test("bar")
        assert limiter2.test("bar")

        while limiter1.hit("bar"):
            pass

        assert limiter2.test("bar")
        assert not limiter1.test("bar")
Beispiel #4
0
    def test_basic(self):
        limiter = RateLimiter(storage.MemoryStorage(),
                              "1 per minute",
                              identifiers=["foo"])

        assert limiter.test("foo")
        assert limiter.test("bar")

        while limiter.hit("bar"):
            pass

        assert limiter.test("foo")
        assert not limiter.test("bar")
Beispiel #5
0
    def test_clear(self, metrics):
        limiter = RateLimiter(storage.MemoryStorage(),
                              "1 per minute",
                              metrics=metrics)

        assert limiter.test("foo")

        while limiter.hit("foo"):
            pass

        assert not limiter.test("foo")

        limiter.clear("foo")

        assert limiter.test("foo")
Beispiel #6
0
    def test_results_in_expired(self):
        limiter = RateLimiter(storage.MemoryStorage(),
                              "1 per minute; 1 per hour; 1 per day")

        current = datetime.datetime.now(tz=datetime.timezone.utc)
        stats = iter([
            (0, 0),
            ((current + datetime.timedelta(seconds=60)).timestamp(), 0),
            ((current + datetime.timedelta(seconds=5)).timestamp(), 0),
        ])

        limiter._window = pretend.stub(
            get_window_stats=lambda l, *a: next(stats))

        resets_in = limiter.resets_in("foo")

        assert resets_in > datetime.timedelta(seconds=0)
        assert resets_in <= datetime.timedelta(seconds=5)
Beispiel #7
0
from limits import storage
from limits import strategies
from limits import parse
from sanic import exceptions


class TooManyRequests(exceptions.InvalidUsage):
    status_code = 429


_MEMORY_STORAGE = storage.MemoryStorage()
_MOVING_WINDOW = strategies.MovingWindowRateLimiter(_MEMORY_STORAGE)

_LIMIT_MESSAGE = "Paste creation limited at 6 per minute."


def limiter(frequency):
    frequency = parse(frequency)

    def decorator(function):
        def wrapper(request, *args, **kwargs):
            namespace = f"{function.__module__}.{function.__name__}"
            ip = request.ip[0] or '127.0.0.1'
            ip = request.headers.get("X-Forwarded-For", ip)
            if not _MOVING_WINDOW.hit(frequency, namespace, ip):
                raise TooManyRequests(_LIMIT_MESSAGE)
            return function(request, *args, **kwargs)

        return wrapper

    return decorator