Example #1
0
 def test_http_error(self):
     res = self._make_request_with_side_effect(exc.HTTPGatewayTimeout())
     # verify that the exception structure is the one expected
     # by the python-tackerclient
     self.assertEqual(exc.HTTPGatewayTimeout().explanation,
                      res.json['TackerError']['message'])
     self.assertEqual('HTTPGatewayTimeout', res.json['TackerError']['type'])
     self.assertEqual('', res.json['TackerError']['detail'])
     self.assertEqual(exc.HTTPGatewayTimeout.code, res.status_int)
Example #2
0
    def make_imaged_request(self, method, imaged_url, headers, body, stream):
        timeout = (self.config.imaged_connection_timeout_sec,
                   self.config.imaged_read_timeout_sec)

        logging.debug("Connecting to host at %s", imaged_url)
        logging.debug("Outgoing headers to host:\n" +
                      '\n'.join(('  {}: {}'.format(k, headers[k])
                                 for k in sorted(headers))))

        try:
            # TODO Pool requests, keep the session somewhere?
            # TODO Otherwise, we can use request.prepare()
            imaged_session = requests.Session()
            imaged_req = requests.Request(method,
                                          imaged_url,
                                          headers=headers,
                                          data=body)
            imaged_req.body_file = body
            # TODO log the request to vdsm
            imaged_prepped = imaged_session.prepare_request(imaged_req)
            imaged_resp = imaged_session.send(
                imaged_prepped,
                verify=config.engine_ca_cert_file,
                timeout=timeout,
                stream=stream)
        except requests.Timeout:
            s = "Timed out connecting to host"
            raise exc.HTTPGatewayTimeout(s)
        except requests.URLRequired:
            s = "Invalid host URI for host"
            raise exc.HTTPBadRequest(s)
        except requests.ConnectionError as e:
            s = "Failed communicating with host: " + e.__doc__
            logging.error(s, exc_info=True)
            raise exc.HTTPServiceUnavailable(s)
        except requests.RequestException as e:
            s = "Failed communicating with host: " + e.__doc__
            logging.error(s, exc_info=True)
            raise exc.HTTPInternalServerError(s)

        print imaged_resp.headers
        # logging.debug("Incoming headers from host:\n" +
        #               '\n'.join(('  {}: {}'
        #                          .format(k, imaged_resp.headers.get(k))
        #                          for k in sorted(imaged_resp.headers))))

        if imaged_resp.status_code not in http_success_codes:
            # Don't read the whole body, in case something went really wrong...
            s = next(imaged_resp.iter_content(256, False), "(empty)")
            logging.error("Failed: %s", s)
            # TODO why isn't the exception logged somewhere?
            raise exc.status_map[imaged_resp.status_code](
                "Failed response from host: {}".format(s))

        logging.debug("Successful request to host: HTTP %d %s",
                      imaged_resp.status_code,
                      httplib.responses[imaged_resp.status_code])
        return imaged_resp
    def test_http_error(self):
        controller = mock.MagicMock()
        controller.test.side_effect = exc.HTTPGatewayTimeout()

        resource = webtest.TestApp(wsgi_resource.Resource(controller))

        environ = {'wsgiorg.routing_args': (None, {'action': 'test'})}
        res = resource.get('', extra_environ=environ, expect_errors=True)
        self.assertEqual(res.status_int, exc.HTTPGatewayTimeout.code)
Example #4
0
    def make_imaged_request(self,
                            method,
                            imaged_url,
                            headers,
                            body,
                            stream,
                            connection_timeout=None,
                            read_timeout=None):
        logging.debug("Connecting to host at %s", imaged_url)
        logging.debug("Outgoing headers to host:\n" +
                      '\n'.join(('  {}: {}'.format(k, headers[k])
                                 for k in sorted(headers))))

        try:
            # TODO Pool requests, keep the session somewhere?
            # TODO Otherwise, we can use request.prepare()
            imaged_session = requests.Session()
            imaged_req = requests.Request(method,
                                          imaged_url,
                                          headers=headers,
                                          data=body)
            imaged_req.body_file = body
            # TODO log the request to vdsm
            imaged_prepped = imaged_session.prepare_request(imaged_req)
            imaged_resp = imaged_session.send(
                imaged_prepped,
                verify=config.engine_ca_cert_file,
                timeout=(connection_timeout, read_timeout),
                stream=stream)
        except requests.Timeout:
            s = "Timed out connecting to host"
            raise exc.HTTPGatewayTimeout(s)
        except requests.URLRequired:
            s = "Invalid host URI for host"
            raise exc.HTTPBadRequest(s)
        except requests.ConnectionError as e:
            s = "Failed communicating with host: " + e.__doc__
            logging.error(s, exc_info=True)
            raise exc.HTTPServiceUnavailable(s)
        except requests.RequestException as e:
            s = "Failed communicating with host: " + e.__doc__
            logging.error(s, exc_info=True)
            raise exc.HTTPInternalServerError(s)

        logging.debug("Incoming headers from host:\n" + '\n'.join(
            ('  {}: {}'.format(k, imaged_resp.headers.get(k))
             for k in sorted(imaged_resp.headers))))

        if imaged_resp.status_code not in http_success_codes:
            s = "Failed response from host: %d %s" % \
                (imaged_resp.status_code, imaged_resp.content)
            raise exc.status_map[imaged_resp.status_code](s)

        logging.debug("Successful request to host: HTTP %d %s",
                      imaged_resp.status_code,
                      httplib.responses[imaged_resp.status_code])
        return imaged_resp
Example #5
0
def code2exception(code, detail):
    """Transforms a code + detail into a WebOb exception"""
    if code == 400:
        return exc.HTTPBadRequest(detail)
    if code == 401:
        return exc.HTTPUnauthorized(detail)
    if code == 402:
        return exc.HTTPPaymentRequired(detail)
    if code == 403:
        return exc.HTTPForbidden(detail)
    if code == 404:
        return exc.HTTPNotFound(detail)
    if code == 405:
        return exc.HTTPMethodNotAllowed(detail)
    if code == 406:
        return exc.HTTPNotAcceptable(detail)
    if code == 407:
        return exc.HTTPProxyAuthenticationRequired(detail)
    if code == 408:
        return exc.HTTPRequestTimeout(detail)
    if code == 409:
        return exc.HTTPConflict(detail)
    if code == 410:
        return exc.HTTPGone(detail)
    if code == 411:
        return exc.HTTPLengthRequired(detail)
    if code == 412:
        return exc.HTTPPreconditionFailed(detail)
    if code == 413:
        return exc.HTTPRequestEntityTooLarge(detail)
    if code == 414:
        return exc.HTTPRequestURITooLong(detail)
    if code == 415:
        return exc.HTTPUnsupportedMediaType(detail)
    if code == 416:
        return exc.HTTPRequestRangeNotSatisfiable(detail)
    if code == 417:
        return exc.HTTPExpectationFailed(detail)
    if code == 500:
        return exc.HTTPInternalServerError(detail)
    if code == 501:
        return exc.HTTPNotImplemented(detail)
    if code == 502:
        return exc.HTTPBadGateway(detail)
    if code == 503:
        return exc.HTTPServiceUnavailable(detail)
    if code == 504:
        return exc.HTTPGatewayTimeout(detail)
    if code == 505:
        return exc.HTTPVersionNotSupported(detail)

    raise NotImplementedError(code)
Example #6
0
 def __call__(self, environ, start_response):
     scheme = environ['wsgi.url_scheme']
     if scheme == 'http':
         ConnClass = self.HTTPConnection
     elif scheme == 'https':
         ConnClass = self.HTTPSConnection
     else:
         raise ValueError("Unknown scheme: %r" % scheme)
     if 'SERVER_NAME' not in environ:
         host = environ.get('HTTP_HOST')
         if not host:
             raise ValueError(
                 "environ contains neither SERVER_NAME nor HTTP_HOST")
         if ':' in host:
             host, port = host.split(':', 1)
         else:
             if scheme == 'http':
                 port = '80'
             else:
                 port = '443'
         environ['SERVER_NAME'] = host
         environ['SERVER_PORT'] = port
     kw = {}
     if ('webob.client.timeout' in environ
             and self._timeout_supported(ConnClass)):
         kw['timeout'] = environ['webob.client.timeout']
     conn = ConnClass('%(SERVER_NAME)s:%(SERVER_PORT)s' % environ, **kw)
     headers = {}
     for key, value in environ.items():
         if key.startswith('HTTP_'):
             key = key[5:].replace('_', '-').title()
             headers[key] = value
     path = (url_quote(environ.get('SCRIPT_NAME', '')) +
             url_quote(environ.get('PATH_INFO', '')))
     if environ.get('QUERY_STRING'):
         path += '?' + environ['QUERY_STRING']
     try:
         content_length = int(environ.get('CONTENT_LENGTH', '0'))
     except ValueError:
         content_length = 0
     ## FIXME: there is no streaming of the body, and that might be useful
     ## in some cases
     if content_length:
         body = environ['wsgi.input'].read(content_length)
     else:
         body = ''
     headers['Content-Length'] = content_length
     if environ.get('CONTENT_TYPE'):
         headers['Content-Type'] = environ['CONTENT_TYPE']
     if not path.startswith("/"):
         path = "/" + path
     try:
         conn.request(environ['REQUEST_METHOD'], path, body, headers)
         res = conn.getresponse()
     except socket.timeout:
         resp = exc.HTTPGatewayTimeout()
         return resp(environ, start_response)
     except (socket.error, socket.gaierror) as e:
         if ((isinstance(e, socket.error) and e.args[0] == -2)
                 or (isinstance(e, socket.gaierror) and e.args[0] == 8)):
             # Name or service not known
             resp = exc.HTTPBadGateway(
                 "Name or service not known (bad domain name: %s)" %
                 environ['SERVER_NAME'])
             return resp(environ, start_response)
         elif e.args[0] in _e_refused:  # pragma: no cover
             # Connection refused
             resp = exc.HTTPBadGateway("Connection refused")
             return resp(environ, start_response)
         raise
     headers_out = self.parse_headers(res.msg)
     status = '%s %s' % (res.status, res.reason)
     start_response(status, headers_out)
     length = res.getheader('content-length')
     # FIXME: This shouldn't really read in all the content at once
     if length is not None:
         body = res.read(int(length))
     else:
         body = res.read()
     conn.close()
     return [body]
Example #7
0
    def __call__(self, environ, start_response):
        method = environ['REQUEST_METHOD']
        if (self.allowed_methods is not None
                and method not in self.allowed_methods):
            return exc.HTTPMethodNotAllowed()(environ, start_response)

        if 'RAW_URI' in environ:
            path_info = environ['RAW_URI']
        elif 'REQUEST_URI' in environ:
            path_info = environ['REQUEST_URI']
        else:
            if self.strip_script_name:
                path_info = ''
            else:
                path_info = environ['SCRIPT_NAME']
            path_info += environ['PATH_INFO']

            if PY3:
                path_info = url_quote(path_info.encode('latin-1'),
                                      LOW_CHAR_SAFE)

            query_string = environ['QUERY_STRING']
            if query_string:
                path_info += '?' + query_string

        for key, dest in self.header_map.items():
            value = environ.get(key)
            if value:
                environ['HTTP_%s' % dest] = value

        host_uri = self.extract_uri(environ)
        uri = host_uri + path_info

        new_headers = {}
        for k, v in environ.items():
            if k.startswith('HTTP_'):
                k = k[5:].replace('_', '-').title()
                new_headers[k] = v

        content_type = environ.get("CONTENT_TYPE")
        if content_type and content_type is not None:
            new_headers['Content-Type'] = content_type

        content_length = environ.get('CONTENT_LENGTH')
        transfer_encoding = environ.get('Transfer-Encoding', '').lower()
        if not content_length and transfer_encoding != 'chunked':
            new_headers['Transfer-Encoding'] = 'chunked'
        elif content_length:
            new_headers['Content-Length'] = content_length

        if new_headers.get('Content-Length', '0') == '-1':
            resp = exc.HTTPInternalServerError(detail=WEBOB_ERROR)
            return resp(environ, start_response)

        try:
            response = self.process_request(uri, method, new_headers, environ)
        except socket.timeout:
            return exc.HTTPGatewayTimeout()(environ, start_response)
        except (socket.error, socket.gaierror):
            return exc.HTTPBadGateway()(environ, start_response)
        except Exception as e:
            self.logger.exception(e)
            return exc.HTTPInternalServerError()(environ, start_response)

        status, location, headerslist, app_iter = response

        if location:
            if self.strip_script_name:
                prefix_path = environ['SCRIPT_NAME']
            else:
                prefix_path = None

            new_location = rewrite_location(host_uri,
                                            location,
                                            prefix_path=prefix_path)

            headers = []
            for k, v in headerslist:
                if k.lower() == 'location':
                    v = new_location
                headers.append((k, v))
        else:
            headers = headerslist

        start_response(status, headers)

        if method == "HEAD":
            return [six.b('')]

        return app_iter
Example #8
0
    def __call__(self, environ, start_response):
        scheme = environ["wsgi.url_scheme"]

        if scheme == "http":
            ConnClass = self.HTTPConnection
        elif scheme == "https":
            ConnClass = self.HTTPSConnection
        else:
            raise ValueError("Unknown scheme: %r" % scheme)

        if "SERVER_NAME" not in environ:
            host = environ.get("HTTP_HOST")

            if not host:
                raise ValueError(
                    "environ contains neither SERVER_NAME nor HTTP_HOST")

            if ":" in host:
                host, port = host.split(":", 1)
            else:
                if scheme == "http":
                    port = "80"
                else:
                    port = "443"
            environ["SERVER_NAME"] = host
            environ["SERVER_PORT"] = port
        kw = {}

        if "webob.client.timeout" in environ and self._timeout_supported(
                ConnClass):
            kw["timeout"] = environ["webob.client.timeout"]
        conn = ConnClass("%(SERVER_NAME)s:%(SERVER_PORT)s" % environ, **kw)
        headers = {}

        for key, value in environ.items():
            if key.startswith("HTTP_"):
                key = key[5:].replace("_", "-").title()
                headers[key] = value
        path = url_quote(environ.get("SCRIPT_NAME", "")) + url_quote(
            environ.get("PATH_INFO", ""))

        if environ.get("QUERY_STRING"):
            path += "?" + environ["QUERY_STRING"]
        try:
            content_length = int(environ.get("CONTENT_LENGTH", "0"))
        except ValueError:
            content_length = 0
        # FIXME: there is no streaming of the body, and that might be useful
        # in some cases

        if content_length:
            body = environ["wsgi.input"].read(content_length)
        else:
            body = ""
        headers["Content-Length"] = content_length

        if environ.get("CONTENT_TYPE"):
            headers["Content-Type"] = environ["CONTENT_TYPE"]

        if not path.startswith("/"):
            path = "/" + path
        try:
            conn.request(environ["REQUEST_METHOD"], path, body, headers)
            res = conn.getresponse()
        except socket.timeout:
            resp = exc.HTTPGatewayTimeout()

            return resp(environ, start_response)
        except (OSError, socket.gaierror) as e:
            if (isinstance(e, socket.error)
                    and e.args[0] == -2) or (isinstance(e, socket.gaierror)
                                             and e.args[0] == 8):
                # Name or service not known
                resp = exc.HTTPBadGateway(
                    "Name or service not known (bad domain name: %s)" %
                    environ["SERVER_NAME"])

                return resp(environ, start_response)
            elif e.args[0] in _e_refused:  # pragma: no cover
                # Connection refused
                resp = exc.HTTPBadGateway("Connection refused")

                return resp(environ, start_response)
            raise
        headers_out = self.parse_headers(res.msg)
        status = "%s %s" % (res.status, res.reason)
        start_response(status, headers_out)
        length = res.getheader("content-length")
        # FIXME: This shouldn't really read in all the content at once

        if length is not None:
            body = res.read(int(length))
        else:
            body = res.read()
        conn.close()

        return [body]