Skip to content

Commit

Permalink
Use HTTP code 429 "Too Many Requests" when throttling.
Browse files Browse the repository at this point in the history
  • Loading branch information
spladug committed Jan 10, 2012
1 parent ef45362 commit 34b4e47
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 8 deletions.
13 changes: 12 additions & 1 deletion r2/r2/config/middleware.py
Expand Up @@ -42,6 +42,17 @@
import sys, tempfile, urllib, re, os, sha, subprocess
from httplib import HTTPConnection

# hack in Paste support for HTTP 429 "Too Many Requests"
from paste import httpexceptions, wsgiwrappers

class HTTPTooManyRequests(httpexceptions.HTTPClientError):
code = 429
title = 'Too Many Requests'
explanation = ('The server has received too many requests from the client.')

httpexceptions._exceptions[429] = HTTPTooManyRequests
wsgiwrappers.STATUS_CODE_TEXT[429] = HTTPTooManyRequests.title

#from pylons.middleware import error_mapper
def error_mapper(code, message, environ, global_conf=None, **kw):
from pylons import c
Expand All @@ -52,7 +63,7 @@ def error_mapper(code, message, environ, global_conf=None, **kw):

if global_conf is None:
global_conf = {}
codes = [304, 401, 403, 404, 503]
codes = [304, 401, 403, 404, 429, 503]
if not asbool(global_conf.get('debug')):
codes.append(500)
if code in codes:
Expand Down
33 changes: 29 additions & 4 deletions r2/r2/controllers/error.py
Expand Up @@ -72,13 +72,32 @@
'''

toofast = \
'''<html>
<head><title>service temporarily unavailable</title></head>
'''<!doctype html>
<html>
<head>
<title>Too Many Requests</title>
<style>
body { font: small verdana, arial, helvetica, sans-serif; }
</style>
</head>
<body>
the service you request is temporarily unavailable. please try again later.
<h1>whoa there, pardner!</h1>
<p>reddit's awesome and all, but you may have a bit of a
problem. we've seen far too many requests come from your ip address
recently.</p>
<p>if you think that we've incorrectly blocked you or you would like
to discuss easier ways to get the data you want, please contact us
any of the following ways.</p>
<ul>
<li><a href="http://webchat.freenode.net/?channels=reddit-dev">#reddit-dev on freenode</a></li>
<li><a href="http://groups.google.com/group/reddit-dev">the reddit-dev google group</a></li>
<li><a href="mailto:ratelimit@reddit.com">ratelimit@reddit.com</a></li>
</ul>
<p>as a reminder, we recommend that clients make no more than one
request every two seconds to avoid being blocked like this.</p>
</body>
</html>
'''
'''

class ErrorController(RedditController):
"""Generates error documents as and when they are required.
Expand Down Expand Up @@ -146,6 +165,10 @@ def send404(self):
else:
return pages.Reddit404().render()

def send429(self):
c.response.status_code = 429
return toofast

def send503(self):
c.response.status_code = 503
if 'retry_after' in request.environ:
Expand Down Expand Up @@ -186,6 +209,8 @@ def GET_document(self):
return pages.TakedownPage(link).render()
elif code == 403:
return self.send403()
elif code == 429:
return self.send429()
elif code == 500:
randmin = {'admin': rand.choice(self.admins)}
failien_name = 'youbrokeit%d.png' % rand.randint(1, NUM_FAILIENS)
Expand Down
6 changes: 3 additions & 3 deletions r2/r2/controllers/reddit_base.py
Expand Up @@ -419,7 +419,7 @@ def ratelimit_agents():
if s and user_agent and s in user_agent.lower():
key = 'rate_agent_' + s
if g.cache.get(s):
abort(503, 'service temporarily unavailable')
abort(429)
else:
g.cache.set(s, 't', time = 1)

Expand All @@ -430,7 +430,7 @@ def ratelimit_throttled():
ip, slash16 = ip_and_slash16(request)

if throttled(ip) or throttled(slash16):
abort(503, 'service temporarily unavailable')
abort(429)


def paginated_listing(default_page_size=25, max_page_size=100, backend='sql'):
Expand Down Expand Up @@ -616,7 +616,7 @@ def post(self):
and request.method.upper() == 'GET'
and (not c.user_is_loggedin or c.allow_loggedin_cache)
and not c.used_cache
and response.status_code != 503
and response.status_code not in (429, 503)
and response.content and response.content[0]):
try:
g.rendercache.set(self.request_key(),
Expand Down

0 comments on commit 34b4e47

Please sign in to comment.