@@ -2092,6 +2092,24 @@ def dispatch(self, method, uri, input):
2092
2092
msg = _ ("Api rate limits exceeded. Please wait: %s seconds." ) % retry_after
2093
2093
output = self .error_obj (429 , msg , source = "ApiRateLimiter" )
2094
2094
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
+
2095
2113
return self .format_dispatch_output (
2096
2114
self .__default_accept_type ,
2097
2115
output ,
@@ -2126,6 +2144,75 @@ def dispatch(self, method, uri, input):
2126
2144
'Ignoring X-HTTP-Method-Override using %s request on %s' ,
2127
2145
method .upper (), uri )
2128
2146
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"
2129
2216
if method .upper () == 'OPTIONS' :
2130
2217
# add access-control-allow-* access-control-max-age to support
2131
2218
# CORS preflight
0 commit comments