def _check_status_code(self, resp, method, **kwargs): if self._unauthorized(resp): message = "Unauthorized error" raise exc.HTTPUnauthorized(message=message) 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. location = resp.headers.get('location') if location is None: message = "Location not returned with 302" raise exc.InvalidEndpoint(message=message) elif location.startswith(self.endpoint): # shave off the endpoint, it will be prepended when we recurse location = location[len(self.endpoint):] else: message = "Prohibited endpoint redirect %s" % location raise exc.InvalidEndpoint(message=message) return self._http_request(location, method, **kwargs) elif resp.status_code == 300: raise exc.from_response(resp)
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()) 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 # 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 timeout = None if method in ['POST', 'DELETE', 'PUT', 'PATCH']: timeout = self.write_timeout elif method is 'GET': timeout = self.read_timeout try: resp = requests.request( method, self.endpoint_url + url, allow_redirects=allow_redirects, timeout=timeout, **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) except requests.Timeout as e: endpoint = self.endpoint message = ("Error %(method)s timeout request to %(endpoint)s %(e)s" % {'method': method, 'endpoint': endpoint, 'e': e}) raise exc.RequestTimeoutError(message=message) self.log_http_response(resp) if (resp.status_code == 401 or (resp.status_code == 500 and "(HTTP 401)" in resp.content)): # re-authenticate and attempt one more request try: self.re_authenticate() kwargs['headers']['X-Auth-Token'] = self.auth_token resp = requests.request( method, self.endpoint_url + url, allow_redirects=allow_redirects, timeout=timeout, **kwargs) except Exception as e: raise exc.HTTPUnauthorized(e) 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. location = resp.headers.get('location') if location is None: message = "Location not returned with 302" raise exc.InvalidEndpoint(message=message) elif location.startswith(self.endpoint): # shave off the endpoint, it will be prepended when we recurse location = location[len(self.endpoint):] else: message = "Prohibited endpoint redirect %s" % location raise exc.InvalidEndpoint(message=message) return self._http_request(location, method, **kwargs) elif resp.status_code == 300: raise exc.from_response(resp) return resp
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()) 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 # 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 timeout = None if method in ['POST', 'DELETE', 'PUT', 'PATCH']: timeout = self.write_timeout elif method is 'GET': timeout = self.read_timeout try: resp = requests.request(method, self.endpoint_url + url, allow_redirects=allow_redirects, timeout=timeout, **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) except requests.Timeout as e: endpoint = self.endpoint message = ( "Error %(method)s timeout request to %(endpoint)s %(e)s" % { 'method': method, 'endpoint': endpoint, 'e': e }) raise exc.RequestTimeoutError(message=message) self.log_http_response(resp) if (resp.status_code == 401 or (resp.status_code == 500 and "(HTTP 401)" in resp.content)): # re-authenticate and attempt one more request try: self.re_authenticate() kwargs['headers']['X-Auth-Token'] = self.auth_token resp = requests.request(method, self.endpoint_url + url, allow_redirects=allow_redirects, timeout=timeout, **kwargs) except Exception as e: raise exc.HTTPUnauthorized(e) 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. location = resp.headers.get('location') if location is None: message = "Location not returned with 302" raise exc.InvalidEndpoint(message=message) elif location.startswith(self.endpoint): # shave off the endpoint, it will be prepended when we recurse location = location[len(self.endpoint):] else: message = "Prohibited endpoint redirect %s" % location raise exc.InvalidEndpoint(message=message) return self._http_request(location, method, **kwargs) elif resp.status_code == 300: raise exc.from_response(resp) return resp