Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Introduce Apps:APIUnthrottled permission to prevent select API users …

…from being throttled (bug 848869)
  • Loading branch information...
commit f74f1a8b5e65c2eed47385151ebfd9ff2ecd0e42 1 parent 5be330a
Chuck Harmston chuckharmston authored
Showing with 66 additions and 8 deletions.
  1. +10 −7 mkt/api/base.py
  2. +56 −1 mkt/api/tests/test_base.py
17 mkt/api/base.py
View
@@ -9,6 +9,7 @@
from tastypie.exceptions import ImmediateHttpResponse, UnsupportedFormat
from tastypie.resources import Resource, ModelResource
+from access import acl
import commonware.log
from translations.fields import PurifiedField, TranslatedField
@@ -142,13 +143,15 @@ def throttle_check(self, request):
Mostly a hook, this uses class assigned to ``throttle`` from
``Resource._meta``.
"""
- identifiers = [a.get_identifier(request) for a in self._auths()]
-
- # Check to see if they should be throttled.
- if any(self._meta.throttle.should_be_throttled(identifier)
- for identifier in identifiers):
- # Throttle limit exceeded.
- raise ImmediateHttpResponse(response=HttpTooManyRequests())
+ # Never throttle users with Apps:APIUnthrottled.
+ if not acl.action_allowed(request, 'Apps', 'APIUnthrottled'):
+ identifiers = [a.get_identifier(request) for a in self._auths()]
+
+ # Check to see if they should be throttled.
+ if any(self._meta.throttle.should_be_throttled(identifier)
+ for identifier in identifiers):
+ # Throttle limit exceeded.
+ raise ImmediateHttpResponse(response=HttpTooManyRequests())
def log_throttled_access(self, request):
"""
57 mkt/api/tests/test_base.py
View
@@ -1,17 +1,23 @@
import json
import urllib
+from django.contrib.auth.models import User
+
from mock import patch
from nose.tools import eq_
from tastypie import http
from tastypie.authorization import Authorization
from tastypie.exceptions import ImmediateHttpResponse
+from tastypie.throttle import BaseThrottle
from test_utils import RequestFactory
+from access.middleware import ACLMiddleware
from amo.tests import TestCase
from mkt.api.base import MarketplaceResource
+from mkt.api.http import HttpTooManyRequests
from mkt.api.serializers import Serializer
+from mkt.site.fixtures import fixture
class SampleResource(MarketplaceResource):
@@ -31,7 +37,7 @@ def _encode_data(self, data, content_type):
return urllib.urlencode(data)
-class TestMarketplace(TestCase):
+class TestEncoding(TestCase):
def setUp(self):
self.resource = SampleResource()
@@ -70,3 +76,52 @@ def test_form_encoded(self, obj_create):
content_type='application/x-www-form-urlencoded')
self.resource.dispatch('list', request)
eq_(obj_create.call_args[0][0].data, {'foo': 'bar'})
+
+
+class ThrottleResource(MarketplaceResource):
+
+ class Meta(object):
+ authorization = Authorization()
+ throttle = BaseThrottle()
+
+
+class TestThrottling(TestCase):
+ fixtures = fixture('user_2519')
+
+ def setUp(self):
+ self.resource = ThrottleResource()
+ self.request = RequestFactory().post('/')
+ self.user = User.objects.get(pk=2519)
+ self.request.user = self.user
+ self.throttle = self.resource._meta.throttle
+ self.request.META['CONTENT_TYPE'] = 'application/x-www-form-urlencoded'
+ self.mocked_sbt = patch.object(self.throttle, 'should_be_throttled')
+
+ def no_throttle_expected(self):
+ try:
+ self.resource.throttle_check(self.request)
+ except ImmediateHttpResponse, e:
+ if isinstance(e.response, HttpTooManyRequests):
+ self.fail('Unexpected 429')
+ raise e
+
+ def throttle_expected(self):
+ with self.assertImmediate(HttpTooManyRequests):
+ self.resource.throttle_check(self.request)
+
+ def test_should_throttle(self):
+ with self.mocked_sbt as sbt:
+ sbt.return_value = True
+ self.throttle_expected()
+
+ def test_shouldnt_throttle(self):
+ with self.mocked_sbt as sbt:
+ sbt.return_value = False
+ self.no_throttle_expected()
+
+ def test_unthrottled_user(self):
+ self.grant_permission(self.user.get_profile(), 'Apps:APIUnthrottled')
+ ACLMiddleware().process_request(self.request)
+ with self.mocked_sbt as sbt:
+ sbt.return_value = True
+ self.no_throttle_expected()
Please sign in to comment.
Something went wrong with that request. Please try again.