aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/Twisted/py3/twisted/web/pages.py
blob: f94f8655b95fbcaca40159f7e4503506c31a1b7b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# -*- test-case-name: twisted.web.test.test_pages -*-
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.

"""
Utility implementations of L{IResource}.
"""

__all__ = (
    "errorPage",
    "notFound",
    "forbidden",
)

from typing import cast

from twisted.web import http
from twisted.web.iweb import IRenderable, IRequest
from twisted.web.resource import IResource, Resource
from twisted.web.template import renderElement, tags


class _ErrorPage(Resource):
    """
    L{_ErrorPage} is a resource that responds to all requests with a particular
    (parameterized) HTTP status code and an HTML body containing some
    descriptive text. This is useful for rendering simple error pages.

    @see: L{twisted.web.pages.errorPage}

    @ivar _code: An integer HTTP status code which will be used for the
        response.

    @ivar _brief: A short string which will be included in the response body as
        the page title.

    @ivar _detail: A longer string which will be included in the response body.
    """

    def __init__(self, code: int, brief: str, detail: str) -> None:
        super().__init__()
        self._code: int = code
        self._brief: str = brief
        self._detail: str = detail

    def render(self, request: IRequest) -> object:
        """
        Respond to all requests with the given HTTP status code and an HTML
        document containing the explanatory strings.
        """
        request.setResponseCode(self._code)
        request.setHeader(b"content-type", b"text/html; charset=utf-8")
        return renderElement(
            request,
            # cast because the type annotations here seem off; Tag isn't an
            # IRenderable but also probably should be? See
            # https://github.com/twisted/twisted/issues/4982
            cast(
                IRenderable,
                tags.html(
                    tags.head(tags.title(f"{self._code} - {self._brief}")),
                    tags.body(tags.h1(self._brief), tags.p(self._detail)),
                ),
            ),
        )

    def getChild(self, path: bytes, request: IRequest) -> Resource:
        """
        Handle all requests for which L{_ErrorPage} lacks a child by returning
        this error page.

        @param path: A path segment.

        @param request: HTTP request
        """
        return self


def errorPage(code: int, brief: str, detail: str) -> _ErrorPage:
    """
    Build a resource that responds to all requests with a particular HTTP
    status code and an HTML body containing some descriptive text. This is
    useful for rendering simple error pages.

    The resource dynamically handles all paths below it. Use
    L{IResource.putChild()} to override a specific path.

    @param code: An integer HTTP status code which will be used for the
        response.

    @param brief: A short string which will be included in the response
        body as the page title.

    @param detail: A longer string which will be included in the
        response body.

    @returns: An L{IResource}
    """
    return _ErrorPage(code, brief, detail)


def notFound(
    brief: str = "No Such Resource",
    message: str = "Sorry. No luck finding that resource.",
) -> IResource:
    """
    Generate an L{IResource} with a 404 Not Found status code.

    @see: L{twisted.web.pages.errorPage}

    @param brief: A short string displayed as the page title.

    @param brief: A longer string displayed in the page body.

    @returns: An L{IResource}
    """
    return _ErrorPage(http.NOT_FOUND, brief, message)


def forbidden(
    brief: str = "Forbidden Resource", message: str = "Sorry, resource is forbidden."
) -> IResource:
    """
    Generate an L{IResource} with a 403 Forbidden status code.

    @see: L{twisted.web.pages.errorPage}

    @param brief: A short string displayed as the page title.

    @param brief: A longer string displayed in the page body.

    @returns: An L{IResource}
    """
    return _ErrorPage(http.FORBIDDEN, brief, message)