Skip to content

Commit 073c370

Browse files
committed
fix: replace bad reverted code change; allow js rate headers
Last commit included an incorrect undo. I was going to move the Allow header/output format parsing earlier in the dispatch method. But I reverted it incorrectly and removed it instead. It has been added back in the former location. Header that allows javascript access to the rest rate limit header has been moved. The rate limit headers can be accessed by client side javascript regardless of the rate limit being exceeded.
1 parent 285abbd commit 073c370

File tree

1 file changed

+87
-0
lines changed

1 file changed

+87
-0
lines changed

roundup/rest.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2092,6 +2092,24 @@ def dispatch(self, method, uri, input):
20922092
msg = _("Api rate limits exceeded. Please wait: %s seconds.") % retry_after
20932093
output = self.error_obj(429, msg, source="ApiRateLimiter")
20942094

2095+
# expose these headers to rest clients. Otherwise they can't
2096+
# respond to:
2097+
# rate limiting (*RateLimit*, Retry-After)
2098+
# obsolete API endpoint (Sunset)
2099+
# options request to discover supported methods (Allow)
2100+
self.client.setHeader(
2101+
"Access-Control-Expose-Headers",
2102+
", ".join([
2103+
"X-RateLimit-Limit",
2104+
"X-RateLimit-Remaining",
2105+
"X-RateLimit-Reset",
2106+
"X-RateLimit-Limit-Period",
2107+
"Retry-After",
2108+
"Sunset",
2109+
"Allow",
2110+
])
2111+
)
2112+
20952113
return self.format_dispatch_output(
20962114
self.__default_accept_type,
20972115
output,
@@ -2126,6 +2144,75 @@ def dispatch(self, method, uri, input):
21262144
'Ignoring X-HTTP-Method-Override using %s request on %s',
21272145
method.upper(), uri)
21282146

2147+
# parse Accept header and get the content type
2148+
# Acceptable types ordered with preferred one first
2149+
# in list.
2150+
try:
2151+
accept_header = parse_accept_header(headers.get('Accept'))
2152+
except UsageError as e:
2153+
output = self.error_obj(406, _("Unable to parse Accept Header. %(error)s. "
2154+
"Acceptable types: %(acceptable_types)s") % {
2155+
'error': e.args[0],
2156+
'acceptable_types': " ".join(sorted(self.__accepted_content_type.keys()))})
2157+
accept_header = []
2158+
2159+
if not accept_header:
2160+
accept_type = self.__default_accept_type
2161+
else:
2162+
accept_type = None
2163+
for part in accept_header:
2164+
if accept_type:
2165+
# we accepted the best match, stop searching for
2166+
# lower quality matches.
2167+
break
2168+
if part[0] in self.__accepted_content_type:
2169+
accept_type = self.__accepted_content_type[part[0]]
2170+
# Version order:
2171+
# 1) accept header version=X specifier
2172+
# application/vnd.x.y; version=1
2173+
# 2) from type in accept-header type/subtype-vX
2174+
# application/vnd.x.y-v1
2175+
# 3) from @apiver in query string to make browser
2176+
# use easy
2177+
# This code handles 1 and 2. Set api_version to none
2178+
# to trigger @apiver parsing below
2179+
# Places that need the api_version info should
2180+
# use default if version = None
2181+
try:
2182+
self.api_version = int(part[1]['version'])
2183+
except KeyError:
2184+
self.api_version = None
2185+
except (ValueError, TypeError):
2186+
# TypeError if int(None)
2187+
msg = ("Unrecognized api version: %s. "
2188+
"See /rest without specifying api version "
2189+
"for supported versions." % (
2190+
part[1]['version']))
2191+
output = self.error_obj(400, msg)
2192+
2193+
# get the request format for response
2194+
# priority : extension from uri (/rest/data/issue.json),
2195+
# header (Accept: application/json, application/xml)
2196+
# default (application/json)
2197+
ext_type = os.path.splitext(urlparse(uri).path)[1][1:]
2198+
2199+
# Check to see if the length of the extension is less than 6.
2200+
# this allows use of .vcard for a future use in downloading
2201+
# user info. It also allows passing through larger items like
2202+
# JWT that has a final component > 6 items. This method also
2203+
# allow detection of mistyped types like jon for json.
2204+
if ext_type and (len(ext_type) < 6):
2205+
# strip extension so uri make sense
2206+
# .../issue.json -> .../issue
2207+
uri = uri[:-(len(ext_type) + 1)]
2208+
else:
2209+
ext_type = None
2210+
2211+
# headers.get('Accept') is never empty if called here.
2212+
# accept_type will be set to json if there is no Accept header
2213+
# accept_type wil be empty only if there is an Accept header
2214+
# with invalid values.
2215+
data_type = ext_type or accept_type or headers.get('Accept') or "invalid"
21292216
if method.upper() == 'OPTIONS':
21302217
# add access-control-allow-* access-control-max-age to support
21312218
# CORS preflight

0 commit comments

Comments
 (0)