def strip_endpoint(self, location): if location is None: message = _("Location not returned with 302") raise exc.InvalidEndpoint(message=message) elif location.lower().startswith(self.endpoint.lower()): return location[len(self.endpoint):] else: message = _("Prohibited endpoint redirect %s") % location raise exc.InvalidEndpoint(message=message)
def strip_endpoint(self, location): if location is None: message = _("Location not returned with 302") raise exc.InvalidEndpoint(message=message) if (self.endpoint_override is not None and location.lower().startswith( self.endpoint_override.lower())): return location[len(self.endpoint_override):] else: return location
def _http_request(self, url, method, **kwargs): kwargs.setdefault('user_agent', USER_AGENT) kwargs.setdefault('auth', self.auth) endpoint_filter = kwargs.setdefault('endpoint_filter', {}) endpoint_filter.setdefault('interface', self.interface) endpoint_filter.setdefault('service_type', self.service_type) endpoint_filter.setdefault('region_name', self.region_name) # TODO(gyee): what are these headers for? if self.auth_url: kwargs['headers'].setdefault('X-Auth-Url', self.auth_url) if self.region_name: kwargs['headers'].setdefault('X-Region-Name', self.region_name) if self.include_pass and 'X-Auth-Key' not in kwargs['headers']: kwargs['headers'].update(self.credentials_headers()) # Allow caller to specify not to follow redirects, in which case we # just return the redirect response. Useful for using stacks:lookup. follow_redirects = kwargs.pop('follow_redirects', True) # If the endpoint is passed in, make sure keystone uses it # instead of looking up the endpoint in the auth plugin. if self.endpoint is not None: kwargs['endpoint_override'] = self.endpoint resp = self.session.request(url, method, redirect=follow_redirects, raise_exc=False, **kwargs) if 400 <= resp.status_code < 600: raise exc.from_response(resp) elif resp.status_code in (301, 302, 305): # Redirected. Reissue the request to the new location, # unless caller specified follow_redirects=False if follow_redirects: location = resp.headers.get('location') if location is None: message = _("Location not returned with 302") raise exc.InvalidEndpoint(message=message) elif (self.endpoint is not None and location.lower().startswith(self.endpoint.lower())): location = location[len(self.endpoint):] resp = self._http_request(location, method, **kwargs) elif resp.status_code == 300: raise exc.from_response(resp) return resp
def _resolve_stack_id(self, stack_id): # if the id already has a slash in it, # then it is already {stack_name}/{stack_id} if stack_id.find('/') > 0: return stack_id # We want to capture the redirect, not actually get the stack, # since all we want is the stacks:lookup response to get the # fully qualified ID, and not all users are allowed to do the # redirected stacks:show, so pass redirect=False resp = self.client.get('/stacks/%s' % stack_id, redirect=False) location = resp.headers.get('location') if not location: message = _("Location not returned with redirect") raise exc.InvalidEndpoint(message=message) return location.split('/stacks/', 1)[1]
def _http_request(self, url, method, **kwargs): """Send an http request with the specified characteristics. Wrapper around requests.request to handle tasks such as setting headers and error handling. """ # Copy the kwargs so we can reuse the original in case of redirects kwargs['headers'] = copy.deepcopy(kwargs.get('headers', {})) kwargs['headers'].setdefault('User-Agent', USER_AGENT) if self.auth_token: kwargs['headers'].setdefault('X-Auth-Token', self.auth_token) else: kwargs['headers'].update(self.credentials_headers()) if self.auth_url: kwargs['headers'].setdefault('X-Auth-Url', self.auth_url) if self.region_name: kwargs['headers'].setdefault('X-Region-Name', self.region_name) if self.include_pass and 'X-Auth-Key' not in kwargs['headers']: kwargs['headers'].update(self.credentials_headers()) if osprofiler_web: kwargs['headers'].update(osprofiler_web.get_trace_id_headers()) self.log_curl_request(method, url, kwargs) if self.cert_file and self.key_file: kwargs['cert'] = (self.cert_file, self.key_file) if self.verify_cert is not None: kwargs['verify'] = self.verify_cert if self.timeout is not None: kwargs['timeout'] = float(self.timeout) # Allow caller to specify not to follow redirects, in which case we # just return the redirect response. Useful for using stacks:lookup. redirect = kwargs.pop('redirect', True) # Since requests does not follow the RFC when doing redirection to sent # back the same method on a redirect we are simply bypassing it. For # example if we do a DELETE/POST/PUT on a URL and we get a 302 RFC says # that we should follow that URL with the same method as before, # requests doesn't follow that and send a GET instead for the method. # Hopefully this could be fixed as they say in a comment in a future # point version i.e.: 3.x # See issue: https://github.com/kennethreitz/requests/issues/1704 allow_redirects = False try: resp = requests.request(method, self.endpoint_url + url, allow_redirects=allow_redirects, **kwargs) except socket.gaierror as e: message = (_("Error finding address for %(url)s: %(e)s") % { 'url': self.endpoint_url + url, 'e': e }) raise exc.InvalidEndpoint(message=message) except (socket.error, socket.timeout) as e: endpoint = self.endpoint message = (_("Error communicating with %(endpoint)s %(e)s") % { 'endpoint': endpoint, 'e': e }) raise exc.CommunicationError(message=message) self.log_http_response(resp) if not ('X-Auth-Key' in kwargs['headers']) and ( resp.status_code == 401 or (resp.status_code == 500 and "(HTTP 401)" in resp.content)): raise exc.HTTPUnauthorized( _("Authentication failed: %s") % resp.content) elif 400 <= resp.status_code < 600: raise exc.from_response(resp) elif resp.status_code in (301, 302, 305): # Redirected. Reissue the request to the new location, # unless caller specified redirect=False if redirect: location = resp.headers.get('location') path = self.strip_endpoint(location) resp = self._http_request(path, method, **kwargs) elif resp.status_code == 300: raise exc.from_response(resp) return resp