Use HTTP code 429 "Too Many Requests" when throttling.

This commit is contained in:
Neil Williams
2011-12-22 22:22:23 -08:00
parent ef45362d59
commit 34b4e479b6
3 changed files with 44 additions and 8 deletions

View File

@@ -42,6 +42,17 @@ from cStringIO import StringIO
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
@@ -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:

View File

@@ -72,13 +72,32 @@ redditbroke = \
'''
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.
@@ -146,6 +165,10 @@ class ErrorController(RedditController):
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:
@@ -186,6 +209,8 @@ class ErrorController(RedditController):
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)

View File

@@ -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)
@@ -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'):
@@ -616,7 +616,7 @@ class MinimalController(BaseController):
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(),