Пример #1
0
    def get_headers(
        self, version="1.1", keep_alive=False, keep_alive_timeout=None
    ):
        # This is all returned in a kind-of funky way
        # We tried to make this as fast as possible in pure python
        timeout_header = b""
        if keep_alive and keep_alive_timeout is not None:
            timeout_header = b"Keep-Alive: %d\r\n" % keep_alive_timeout

        self.headers["Transfer-Encoding"] = "chunked"
        self.headers.pop("Content-Length", None)
        self.headers["Content-Type"] = self.headers.get(
            "Content-Type", self.content_type
        )

        headers = self._parse_headers()

        if self.status is 200:
            status = b"OK"
        else:
            status = STATUS_CODES.get(self.status)

        return (b"HTTP/%b %d %b\r\n" b"%b" b"%b\r\n") % (
            version.encode(),
            self.status,
            status,
            timeout_header,
            headers,
        )
Пример #2
0
    def output(self, version="1.1", keep_alive=False, keep_alive_timeout=None):
        # This is all returned in a kind-of funky way
        # We tried to make this as fast as possible in pure python
        timeout_header = b''
        if keep_alive and keep_alive_timeout is not None:
            timeout_header = b'Keep-Alive: %d\r\n' % keep_alive_timeout

        body = b''
        if has_message_body(self.status):
            body = self.body
            self.headers['Content-Length'] = self.headers.get(
                'Content-Length', len(self.body))

        self.headers['Content-Type'] = self.headers.get(
            'Content-Type', self.content_type)

        if self.status in (304, 412):
            self.headers = remove_entity_headers(self.headers)

        headers = self._parse_headers()

        if self.status is 200:
            status = b'OK'
        else:
            status = STATUS_CODES.get(self.status, b'UNKNOWN RESPONSE')

        return (b'HTTP/%b %d %b\r\n'
                b'Connection: %b\r\n'
                b'%b'
                b'%b\r\n'
                b'%b') % (version.encode(), self.status, status,
                          b'keep-alive' if keep_alive else b'close',
                          timeout_header, headers, body)
Пример #3
0
    def get_headers(self,
                    version="1.1",
                    keep_alive=False,
                    keep_alive_timeout=None):
        # This is all returned in a kind-of funky way
        # We tried to make this as fast as possible in pure python
        timeout_header = b''
        if keep_alive and keep_alive_timeout is not None:
            timeout_header = b'Keep-Alive: %d\r\n' % keep_alive_timeout

        self.headers['Transfer-Encoding'] = 'chunked'
        self.headers.pop('Content-Length', None)
        self.headers['Content-Type'] = self.headers.get(
            'Content-Type', self.content_type)

        headers = self._parse_headers()

        if self.status is 200:
            status = b'OK'
        else:
            status = STATUS_CODES.get(self.status)

        return (b'HTTP/%b %d %b\r\n'
                b'%b'
                b'%b\r\n') % (version.encode(), self.status, status,
                              timeout_header, headers)
Пример #4
0
    def __init__(
        self,
        message: Optional[Union[str, bytes]] = None,
        status_code: Optional[int] = None,
        quiet: Optional[bool] = None,
        context: Optional[Dict[str, Any]] = None,
        extra: Optional[Dict[str, Any]] = None,
    ) -> None:
        self.context = context
        self.extra = extra
        if message is None:
            if self.message:
                message = self.message
            elif status_code is not None:
                msg: bytes = STATUS_CODES.get(status_code, b"")
                message = msg.decode("utf8")

        super().__init__(message)

        if status_code is not None:
            self.status_code = status_code

        # quiet=None/False/True with None meaning choose by status
        if quiet or quiet is None and status_code not in (None, 500):
            self.quiet = True
Пример #5
0
    def output(self, version="1.1", keep_alive=False, keep_alive_timeout=None):
        # This is all returned in a kind-of funky way
        # We tried to make this as fast as possible in pure python
        timeout_header = b""
        if keep_alive and keep_alive_timeout is not None:
            timeout_header = b"Keep-Alive: %d\r\n" % keep_alive_timeout

        body = b""
        if has_message_body(self.status):
            body = self.body
            self.headers["Content-Length"] = self.headers.get(
                "Content-Length", len(self.body))

        # self.headers get priority over content_type
        if self.content_type and "Content-Type" not in self.headers:
            self.headers["Content-Type"] = self.content_type

        if self.status in (304, 412):
            self.headers = remove_entity_headers(self.headers)

        headers = self._parse_headers()
        status = STATUS_CODES.get(self.status, b"UNKNOWN RESPONSE")
        return (b"HTTP/%b %d %b\r\n"
                b"Connection: %b\r\n"
                b"%b"
                b"%b\r\n"
                b"%b") % (
                    version.encode(),
                    self.status,
                    status,
                    b"keep-alive" if keep_alive else b"close",
                    timeout_header,
                    headers,
                    body,
                )
Пример #6
0
def exception_response(request, exception, debug):
    status = 500
    text = ("The server encountered an internal error "
            "and cannot complete your request.")

    headers = {}
    if isinstance(exception, SanicException):
        text = f"{exception}"
        status = getattr(exception, "status_code", status)
        headers = getattr(exception, "headers", headers)
    elif debug:
        text = f"{exception}"

    status_text = STATUS_CODES.get(status, b"Error Occurred").decode()
    title = escape(f"{status} — {status_text}")
    text = escape(text)

    if debug and not getattr(exception, "quiet", False):
        return html(
            f"<!DOCTYPE html><meta charset=UTF-8><title>{title}</title>"
            f"<style>{TRACEBACK_STYLE}</style>\n"
            f"<h1>⚠️ {title}</h1><p>{text}\n"
            f"{_render_traceback_html(request, exception)}",
            status=status,
        )

    # Keeping it minimal with trailing newline for pretty curl/console output
    return html(
        f"<!DOCTYPE html><meta charset=UTF-8><title>{title}</title>"
        "<style>html { font-family: sans-serif }</style>\n"
        f"<h1>⚠️ {title}</h1><p>{text}\n",
        status=status,
        headers=headers,
    )
Пример #7
0
def format_http1_response(status: int,
                          headers: HeaderIterable,
                          body=b"") -> bytes:
    """Format a full HTTP/1.1 response.

    - If `body` is included, content-length must be specified in headers.
    """
    headerbytes = format_http1(headers)
    return b"HTTP/1.1 %d %b\r\n%b\r\n%b" % (
        status,
        STATUS_CODES.get(status, b"UNKNOWN"),
        headerbytes,
        body,
    )
Пример #8
0
def abort(status_code, message=None):
    """
    Raise an exception based on SanicException. Returns the HTTP response
    message appropriate for the given status code, unless provided.

    :param status_code: The HTTP status code to return.
    :param message: The HTTP response body. Defaults to the messages
                    in response.py for the given status code.
    """
    if message is None:
        message = STATUS_CODES.get(status_code)
        # These are stored as bytes in the STATUS_CODES dict
        message = message.decode("utf8")
    sanic_exception = _sanic_exceptions.get(status_code, SanicException)
    raise sanic_exception(message=message, status_code=status_code)
Пример #9
0
def abort(status_code, message=None):
    """
    Raise an exception based on SanicException. Returns the HTTP response
    message appropriate for the given status code, unless provided.

    :param status_code: The HTTP status code to return.
    :param message: The HTTP response body. Defaults to the messages
                    in response.py for the given status code.
    """
    if message is None:
        message = STATUS_CODES.get(status_code)
        # These are stored as bytes in the STATUS_CODES dict
        message = message.decode("utf8")
    sanic_exception = _sanic_exceptions.get(status_code, SanicException)
    raise sanic_exception(message=message, status_code=status_code)
Пример #10
0
def exception_response(request, exception, debug):
    status = 500
    text = (
        "The server encountered an internal error "
        "and cannot complete your request."
    )

    headers = {}
    if isinstance(exception, SanicException):
        text = f"{exception}"
        status = getattr(exception, "status_code", status)
        headers = getattr(exception, "headers", headers)
    elif debug:
        text = f"{exception}"

    status_text = STATUS_CODES.get(status, b"Error Occurred").decode()
    title = escape(f"{status} — {status_text}")
    text = escape(text)

    if debug and not getattr(exception, "quiet", False):
        return html(f"{text}", status=status)

    return html(f"{text}", status=status, headers=headers)
Пример #11
0
    def handle_error(self, request, e):
        """
        Error handler for the API transforms a raised exception into a Sanic response,
        with the appropriate HTTP status code and body.
        :param request: The Sanic Request object
        :type request: sanic.request.Request
        :param e: the raised Exception object
        :type e: Exception
        """
        context = restplus.get_context_from_spf(self.spf_reg)
        app = context.app
        #got_request_exception.send(app._get_current_object(), exception=e)
        if not isinstance(e, SanicException) and app.config.get(
                'PROPAGATE_EXCEPTIONS', False):
            exc_type, exc_value, tb = sys.exc_info()
            if exc_value is e:
                raise
            else:
                raise e

        include_message_in_response = app.config.get("ERROR_INCLUDE_MESSAGE",
                                                     True)
        include_code_in_response = app.config.get("ERROR_INCLUDE_CODE", True)
        default_data = {}
        headers = Header()
        for typecheck, handler in self._own_and_child_error_handlers.items():
            if isinstance(e, typecheck):
                result = handler(e)
                default_data, code, headers = unpack(
                    result, HTTPStatus.INTERNAL_SERVER_ERROR)
                break
        else:
            if isinstance(e, SanicException):
                sanic_code = code = e.status_code
                try:
                    status = e.args[0]
                    assert isinstance(status, (str, bytes))
                except (AttributeError, LookupError, AssertionError):
                    if sanic_code is 200:
                        status = b'OK'
                    # x is y comparison only works between -5 and 256
                    elif sanic_code == 404:
                        status = b'Not Found'
                    elif sanic_code == 500:
                        status = b'Internal Server Error'
                    else:
                        status = ALL_STATUS_CODES.get(int(sanic_code))
                code = HTTPStatus(sanic_code, None)
                if status and isinstance(status, bytes):
                    status = status.decode('ascii')
                if include_message_in_response:
                    default_data = {'message': getattr(e, 'message', status)}

            elif self._default_error_handler:
                result = self._default_error_handler(e)
                default_data, code, headers = unpack(
                    result, HTTPStatus.INTERNAL_SERVER_ERROR)
            else:
                code = HTTPStatus.INTERNAL_SERVER_ERROR
                status = ALL_STATUS_CODES.get(code.value, str(e))
                if status and isinstance(status, bytes):
                    status = status.decode('ascii')
                if include_message_in_response:
                    default_data = {
                        'message': status,
                    }

        if include_message_in_response:
            default_data['message'] = default_data.get('message', str(e))
        if include_code_in_response:
            default_data['code'] = int(code)

        data = getattr(e, 'data', default_data)
        fallback_mediatype = None

        if code >= HTTPStatus.INTERNAL_SERVER_ERROR:
            exc_info = sys.exc_info()
            if exc_info[1] is None or exc_info[0] is None:
                e_type = e.__class__
                e_value = e
                e_traceback = e.__traceback__
            else:
                e_type, e_value, e_traceback = exc_info

            context.log(logging.ERROR,
                        "Caught Exception: {}".format(str(e_type)))
            context.log(logging.ERROR, "Detail: {}".format(str(e_value)))
            tb = traceback.format_tb(e_traceback)
            tb = "".join(tb)
            context.log(logging.ERROR, "Traceback:\n{}".format(tb))

        elif code == HTTPStatus.NOT_FOUND and app.config.get("ERROR_404_HELP", False) \
                and include_message_in_response:
            data['message'] = self._help_on_404(request,
                                                data.get('message', None))

        elif code == HTTPStatus.NOT_ACCEPTABLE and self.default_mediatype is None:
            # if we are handling NotAcceptable (406), make sure that
            # make_response uses a representation we support as the
            # default mediatype (so that make_response doesn't throw
            # another NotAcceptable error).
            supported_mediatypes = list(self.representations.keys())
            fallback_mediatype = supported_mediatypes[
                0] if supported_mediatypes else "text/plain"

        # Remove blacklisted headers
        for header in HEADERS_BLACKLIST:
            headers.pop(header, None)
        resp = self.make_response(request,
                                  data,
                                  code,
                                  headers,
                                  fallback_mediatype=fallback_mediatype)

        if code == HTTPStatus.UNAUTHORIZED:
            resp = self.unauthorized(resp)
        return resp
Пример #12
0
        addr = f"[{addr}]"  # bracket IPv6
    return addr.lower()


def parse_host(host: str) -> Tuple[Optional[str], Optional[int]]:
    """Split host:port into hostname and port.
    :return: None in place of missing elements
    """
    m = _host_re.fullmatch(host)
    if not m:
        return None, None
    host, port = m.groups()
    return host.lower(), int(port) if port is not None else None


_HTTP1_STATUSLINES = [
    b"HTTP/1.1 %d %b\r\n" % (status, STATUS_CODES.get(status, b"UNKNOWN"))
    for status in range(1000)
]


def format_http1_response(status: int, headers: HeaderBytesIterable) -> bytes:
    """Format a HTTP/1.1 response header."""
    # Note: benchmarks show that here bytes concat is faster than bytearray,
    # b"".join() or %-formatting. %timeit any changes you make.
    ret = _HTTP1_STATUSLINES[status]
    for h in headers:
        ret += b"%b: %b\r\n" % h
    ret += b"\r\n"
    return ret
Пример #13
0
 def title(self):
     status_text = STATUS_CODES.get(self.status, b"Error Occurred").decode()
     return f"{self.status} — {status_text}"
Пример #14
0
 def title(self):
     return STATUS_CODES.get(self.status, b"Error Occurred").decode()