Beispiel #1
0
 def _init_limiter(self):
     try:
         redis_pool = get_redis_pool(db=settings["RATE_LIMITER_REDIS_DB"])
     except RedisNotConfigured:
         logger.warning(
             "Redis URL not configured: rate limiter not started")
         self._limiter = None
     else:
         # If a redis is configured, then we use the corresponding redis service in the rate
         # limiter.
         self._limiter = RateLimiter(
             resource=self.resource,
             max_requests=self.max_requests,
             expire=self.expire,
             redis_pool=redis_pool,
         )
 def setUp(self):
     """
     Initialises Rate Limit class and delete all keys from Redis.
     """
     self.rate_limit = RateLimit(resource='test', client='localhost',
                                 max_requests=10)
     self.rate_limit._reset()
Beispiel #3
0
class IdunnRateLimiter:
    def __init__(self, resource, max_requests, expire):
        self.resource = resource
        self.max_requests = max_requests
        self.expire = expire
        self._init_limiter()

    def _init_limiter(self):
        try:
            redis_pool = get_redis_pool(db=settings["RATE_LIMITER_REDIS_DB"])
        except RedisNotConfigured:
            logger.warning(
                "Redis URL not configured: rate limiter not started")
            self._limiter = None
        else:
            """
            If a redis is configured,
            then we use the corresponding redis
            service in the rate limiter.
            """
            self._limiter = RateLimiter(
                resource=self.resource,
                max_requests=self.max_requests,
                expire=self.expire,
                redis_pool=redis_pool,
            )

    def limit(self, client, ignore_redis_error=False):
        if self._limiter is None:
            return dummy_limit()

        @contextmanager
        def limit():
            try:
                with self._limiter.limit(client):
                    yield
            except RedisError as e:
                if ignore_redis_error:
                    logger.warning(
                        "Ignoring RedisError in rate limiter for %s",
                        self._limiter.resource,
                        exc_info=True,
                    )
                    yield
                else:
                    raise

        return limit()

    def check_limit_per_client(self, request):
        client_id = request.headers.get("x-client-hash") or "default"
        try:
            with self.limit(client=client_id, ignore_redis_error=True):
                pass
        except TooManyRequestsException:
            raise HTTPException(status_code=429, detail="Too Many Requests")
    def test_limit_10_using_rate_limiter(self):
        """
        Should raise TooManyRequests Exception when trying to increment for the
        eleventh time.
        """
        self.rate_limit = RateLimiter(resource='test', max_requests=10,
                                      expire=2).limit(client='localhost')
        self.assertEqual(self.rate_limit.get_usage(), 0)
        self.assertEqual(self.rate_limit.has_been_reached(), False)

        self._make_10_requests()
        self.assertEqual(self.rate_limit.get_usage(), 10)
        self.assertEqual(self.rate_limit.has_been_reached(), True)

        with self.assertRaises(TooManyRequests):
            with self.rate_limit:
                pass

        self.assertEqual(self.rate_limit.get_usage(), 11)
        self.assertEqual(self.rate_limit.has_been_reached(), True)
 def test_not_expired(self):
     """
     Should raise TooManyRequests Exception when the expire time has not
     been reached yet.
     """
     self.rate_limit = RateLimit(resource='test', client='localhost',
                                 max_requests=10, expire=2)
     self._make_10_requests()
     time.sleep(1)
     with self.assertRaises(TooManyRequests):
         with self.rate_limit:
             pass
Beispiel #6
0
 def get_limiter(cls):
     if cls._limiter is None:
         from app import settings
         try:
             redis_pool = get_redis_pool(settings,
                                         db=settings['WIKI_API_REDIS_DB'])
         except RedisNotConfigured:
             logger.warning(
                 "Redis URL not configured: rate limiter not started")
             cls._limiter = DISABLED_STATE
         else:
             """
             If a redis is configured,
             then we use the corresponding redis
             service in the rate limiter.
             """
             max_calls = int(settings['WIKI_API_RL_MAX_CALLS'])
             redis_period = int(settings['WIKI_API_RL_PERIOD'])
             cls._limiter = RateLimiter(resource='WikipediaAPI',
                                        max_requests=max_calls,
                                        expire=redis_period,
                                        redis_pool=redis_pool)
     return cls._limiter
class TestRedisRateLimit(unittest.TestCase):
    def setUp(self):
        """
        Initialises Rate Limit class and delete all keys from Redis.
        """
        self.rate_limit = RateLimit(resource='test', client='localhost',
                                    max_requests=10)
        self.rate_limit._reset()

    def _make_10_requests(self):
        """
        Increments usage ten times.
        """
        for x in range(0, 10):
            with self.rate_limit:
                pass

    def test_limit_10_max_request(self):
        """
        Should raise TooManyRequests Exception when trying to increment for the
        eleventh time.
        """
        self.assertEqual(self.rate_limit.get_usage(), 0)
        self.assertEqual(self.rate_limit.has_been_reached(), False)

        self._make_10_requests()
        self.assertEqual(self.rate_limit.get_usage(), 10)
        self.assertEqual(self.rate_limit.has_been_reached(), True)

        with self.assertRaises(TooManyRequests):
            with self.rate_limit:
                pass

        self.assertEqual(self.rate_limit.get_usage(), 11)
        self.assertEqual(self.rate_limit.has_been_reached(), True)

    def test_expire(self):
        """
        Should not raise TooManyRequests Exception when trying to increment for
        the eleventh time after the expire time.
        """
        self._make_10_requests()
        time.sleep(1)
        with self.rate_limit:
            pass

    def test_not_expired(self):
        """
        Should raise TooManyRequests Exception when the expire time has not
        been reached yet.
        """
        self.rate_limit = RateLimit(resource='test', client='localhost',
                                    max_requests=10, expire=2)
        self._make_10_requests()
        time.sleep(1)
        with self.assertRaises(TooManyRequests):
            with self.rate_limit:
                pass

    def test_limit_10_using_rate_limiter(self):
        """
        Should raise TooManyRequests Exception when trying to increment for the
        eleventh time.
        """
        self.rate_limit = RateLimiter(resource='test', max_requests=10,
                                      expire=2).limit(client='localhost')
        self.assertEqual(self.rate_limit.get_usage(), 0)
        self.assertEqual(self.rate_limit.has_been_reached(), False)

        self._make_10_requests()
        self.assertEqual(self.rate_limit.get_usage(), 10)
        self.assertEqual(self.rate_limit.has_been_reached(), True)

        with self.assertRaises(TooManyRequests):
            with self.rate_limit:
                pass

        self.assertEqual(self.rate_limit.get_usage(), 11)
        self.assertEqual(self.rate_limit.has_been_reached(), True)