Wsgi_15Watt.Response

  1from .Request import Request
  2from .Exceptions import NotAllowedHttpResponseCode
  3from .Cookie import Cookie
  4
  5
  6class ResponseCodeToText(object):
  7    """
  8    Translates the web servers numeric response code to its
  9    string representation:
 10
 11    200 -> 200 OK
 12
 13    401 -> Unauthorized
 14
 15    ...
 16    """
 17    __numToTxt = {
 18        100: 'Continue',
 19        101: 'Switching Protocols',
 20        102: 'Processing',
 21        103: 'Early Hints',
 22
 23        200: 'OK',
 24        201: 'Created',
 25        202: 'Accepted',
 26        203: 'Non - Authoritative Information',
 27        204: 'No Content',
 28        205: 'Reset Content',
 29        206: 'Partial Content',
 30        207: 'Multi - Status',
 31        208: 'Already Reported',
 32        226: 'IM Used',
 33
 34        300: 'Multiple Choices',
 35        301: 'Moved Permanently',
 36        302: 'Found',
 37        303: 'See Other',
 38        304: 'Not Modified',
 39        307: 'Temporary Redirect',
 40        308: 'Permanent Redirect',
 41
 42        400: 'Bad Request',
 43        401: 'Unauthorized',
 44        402: 'Payment Required',
 45        403: 'Forbidden',
 46        404: 'Not Found',
 47        405: 'Method Not Allowed',
 48        406: 'Not Acceptable',
 49        407: 'Proxy Authentication Required',
 50        408: 'Request Timeout',
 51        409: 'Conflict',
 52        410: 'Gone',
 53        411: 'Length Required',
 54        412: 'Precondition Failed',
 55        413: 'Payload Too Large',
 56        414: 'URI Too Long',
 57        415: 'Unsupported Media Type',
 58        416: 'Range Not Satisfiable',
 59        417: 'Expectation Failed',
 60        418: 'I\'m a teapot',
 61        421: 'Misdirected Request',
 62        422: 'Unprocessable Entity',
 63        423: 'Locked',
 64        424: 'Failed Dependency',
 65        425: 'Too Early',
 66        426: 'Upgrade Required',
 67        428: 'Precondition Required',
 68        429: 'Too Many Requests',
 69        431: 'Request Header Fields Too Large',
 70        451: 'Unavailable For Legal Reasons',
 71
 72        500: 'Internal Server Error',
 73        501: 'Not Implemented',
 74        502: 'Bad Gateway',
 75        503: 'Service Unavailable',
 76        504: 'Gateway Timeout',
 77        505: 'HTTP Version Not Supported',
 78        506: 'Variant Also Negotiates',
 79        507: 'Insufficient Storage',
 80        508: 'Loop Detected',
 81        510: 'Not Extended',
 82        511: 'Network Authentication Required',
 83        513: 'The Server Is In A Bad Mood'
 84    }
 85
 86
 87    def __init__(self, respCode: int):
 88        if respCode not in self.__numToTxt:
 89            raise NotAllowedHttpResponseCode(respCode)
 90
 91        self.__responseCode = respCode
 92
 93
 94    def asText(self) -> str:
 95        """
 96            Returns the string representation of the response code
 97        :return:
 98        """
 99        return '{responseCode} {responseText}'.format(
100                responseCode=self.__responseCode,
101                responseText=self.__numToTxt[self.__responseCode]
102            )
103
104
105    def __str__(self) -> str:
106        return self.asText()
107
108
109
110
111class Response(object):
112    """
113        Representation of the response, that is sent back to the web server
114    """
115    def __init__(self, request: Request, startResponse):
116        self.__request       = request
117        self.__startResponse = startResponse
118        self.contentType     = 'text/plain'
119        self.charset         = 'utf-8'
120        self.returnCode      = 200
121        self.__arrHeaders    = {}
122        self.__arrCookies    = {}
123
124        # The content to send as a byte array
125        self.__byteContent = None
126
127        # The content to send as a string
128        self.__stringContent = ''
129
130
131    # Getters for the private properties
132    @property
133    def request(self) -> Request:
134        return self.__request
135
136
137    @property
138    def stringContent(self) -> str:
139        return self.__stringContent
140
141
142    @stringContent.setter
143    def stringContent(self, strCont: str) -> None:
144        self.__byteContent   = None
145        self.__stringContent = strCont
146
147
148    @property
149    def byteContent(self) -> bytes:
150        return self.__byteContent
151
152
153    @byteContent.setter
154    def byteContent(self, byteCont: bytes) -> None:
155        self.__stringContent = ''
156        self.__byteContent   = byteCont
157
158
159    def addHeader(self, key: str, value: str):
160        """
161            Adds a header line to the response.
162            An already added header is overwritten
163        """
164        self.__arrHeaders[key] = value
165        return self
166
167
168    def addCookie(self, cookie: Cookie):
169        """
170            Adds a cookie to the response.
171            A already added cookie is overwritten
172        """
173        self.__arrCookies[cookie.key] = cookie
174        return self
175
176
177    def getContent(self) -> list[bytes]:
178        """
179            Returns the rendered content.
180            startResponse has been called before.
181        :return:
182        """
183        # Run startResponse to the web server
184        self.__startResponse(
185            ResponseCodeToText(respCode=self.returnCode).asText(),
186            self.__buildHeader()
187        )
188
189        if self.__byteContent is None:
190            # Byte content has not been created yet
191            self.__byteContent = bytes(self.__stringContent, self.charset)
192
193        # Return the byte content
194        return [self.__byteContent]
195
196
197    def redirect(self, url: str, code: int = 303) -> None:
198        """
199            Redirects the user to the given url
200        """
201        self.returnCode = code
202        self.addHeader('Location', url)
203
204
205    def __buildHeader(self) -> list[tuple]:
206        arrHeader = [
207            ('Content-type', '{contType}; charset={charSet}'.format(contType=self.contentType, charSet=self.charset)),
208            ('Access-Control-Allow-Origin', '*')
209        ]
210
211        for key in self.__arrHeaders:
212            arrHeader.append((key, self.__arrHeaders[key]))
213
214        for key in self.__arrCookies:
215            arrHeader.append(('Set-Cookie', str(self.__arrCookies[key])))
216
217        return arrHeader
class ResponseCodeToText:
  7class ResponseCodeToText(object):
  8    """
  9    Translates the web servers numeric response code to its
 10    string representation:
 11
 12    200 -> 200 OK
 13
 14    401 -> Unauthorized
 15
 16    ...
 17    """
 18    __numToTxt = {
 19        100: 'Continue',
 20        101: 'Switching Protocols',
 21        102: 'Processing',
 22        103: 'Early Hints',
 23
 24        200: 'OK',
 25        201: 'Created',
 26        202: 'Accepted',
 27        203: 'Non - Authoritative Information',
 28        204: 'No Content',
 29        205: 'Reset Content',
 30        206: 'Partial Content',
 31        207: 'Multi - Status',
 32        208: 'Already Reported',
 33        226: 'IM Used',
 34
 35        300: 'Multiple Choices',
 36        301: 'Moved Permanently',
 37        302: 'Found',
 38        303: 'See Other',
 39        304: 'Not Modified',
 40        307: 'Temporary Redirect',
 41        308: 'Permanent Redirect',
 42
 43        400: 'Bad Request',
 44        401: 'Unauthorized',
 45        402: 'Payment Required',
 46        403: 'Forbidden',
 47        404: 'Not Found',
 48        405: 'Method Not Allowed',
 49        406: 'Not Acceptable',
 50        407: 'Proxy Authentication Required',
 51        408: 'Request Timeout',
 52        409: 'Conflict',
 53        410: 'Gone',
 54        411: 'Length Required',
 55        412: 'Precondition Failed',
 56        413: 'Payload Too Large',
 57        414: 'URI Too Long',
 58        415: 'Unsupported Media Type',
 59        416: 'Range Not Satisfiable',
 60        417: 'Expectation Failed',
 61        418: 'I\'m a teapot',
 62        421: 'Misdirected Request',
 63        422: 'Unprocessable Entity',
 64        423: 'Locked',
 65        424: 'Failed Dependency',
 66        425: 'Too Early',
 67        426: 'Upgrade Required',
 68        428: 'Precondition Required',
 69        429: 'Too Many Requests',
 70        431: 'Request Header Fields Too Large',
 71        451: 'Unavailable For Legal Reasons',
 72
 73        500: 'Internal Server Error',
 74        501: 'Not Implemented',
 75        502: 'Bad Gateway',
 76        503: 'Service Unavailable',
 77        504: 'Gateway Timeout',
 78        505: 'HTTP Version Not Supported',
 79        506: 'Variant Also Negotiates',
 80        507: 'Insufficient Storage',
 81        508: 'Loop Detected',
 82        510: 'Not Extended',
 83        511: 'Network Authentication Required',
 84        513: 'The Server Is In A Bad Mood'
 85    }
 86
 87
 88    def __init__(self, respCode: int):
 89        if respCode not in self.__numToTxt:
 90            raise NotAllowedHttpResponseCode(respCode)
 91
 92        self.__responseCode = respCode
 93
 94
 95    def asText(self) -> str:
 96        """
 97            Returns the string representation of the response code
 98        :return:
 99        """
100        return '{responseCode} {responseText}'.format(
101                responseCode=self.__responseCode,
102                responseText=self.__numToTxt[self.__responseCode]
103            )
104
105
106    def __str__(self) -> str:
107        return self.asText()

Translates the web servers numeric response code to its string representation:

200 -> 200 OK

401 -> Unauthorized

...

ResponseCodeToText(respCode: int)
88    def __init__(self, respCode: int):
89        if respCode not in self.__numToTxt:
90            raise NotAllowedHttpResponseCode(respCode)
91
92        self.__responseCode = respCode
def asText(self) -> str:
 95    def asText(self) -> str:
 96        """
 97            Returns the string representation of the response code
 98        :return:
 99        """
100        return '{responseCode} {responseText}'.format(
101                responseCode=self.__responseCode,
102                responseText=self.__numToTxt[self.__responseCode]
103            )

Returns the string representation of the response code

Returns
class Response:
112class Response(object):
113    """
114        Representation of the response, that is sent back to the web server
115    """
116    def __init__(self, request: Request, startResponse):
117        self.__request       = request
118        self.__startResponse = startResponse
119        self.contentType     = 'text/plain'
120        self.charset         = 'utf-8'
121        self.returnCode      = 200
122        self.__arrHeaders    = {}
123        self.__arrCookies    = {}
124
125        # The content to send as a byte array
126        self.__byteContent = None
127
128        # The content to send as a string
129        self.__stringContent = ''
130
131
132    # Getters for the private properties
133    @property
134    def request(self) -> Request:
135        return self.__request
136
137
138    @property
139    def stringContent(self) -> str:
140        return self.__stringContent
141
142
143    @stringContent.setter
144    def stringContent(self, strCont: str) -> None:
145        self.__byteContent   = None
146        self.__stringContent = strCont
147
148
149    @property
150    def byteContent(self) -> bytes:
151        return self.__byteContent
152
153
154    @byteContent.setter
155    def byteContent(self, byteCont: bytes) -> None:
156        self.__stringContent = ''
157        self.__byteContent   = byteCont
158
159
160    def addHeader(self, key: str, value: str):
161        """
162            Adds a header line to the response.
163            An already added header is overwritten
164        """
165        self.__arrHeaders[key] = value
166        return self
167
168
169    def addCookie(self, cookie: Cookie):
170        """
171            Adds a cookie to the response.
172            A already added cookie is overwritten
173        """
174        self.__arrCookies[cookie.key] = cookie
175        return self
176
177
178    def getContent(self) -> list[bytes]:
179        """
180            Returns the rendered content.
181            startResponse has been called before.
182        :return:
183        """
184        # Run startResponse to the web server
185        self.__startResponse(
186            ResponseCodeToText(respCode=self.returnCode).asText(),
187            self.__buildHeader()
188        )
189
190        if self.__byteContent is None:
191            # Byte content has not been created yet
192            self.__byteContent = bytes(self.__stringContent, self.charset)
193
194        # Return the byte content
195        return [self.__byteContent]
196
197
198    def redirect(self, url: str, code: int = 303) -> None:
199        """
200            Redirects the user to the given url
201        """
202        self.returnCode = code
203        self.addHeader('Location', url)
204
205
206    def __buildHeader(self) -> list[tuple]:
207        arrHeader = [
208            ('Content-type', '{contType}; charset={charSet}'.format(contType=self.contentType, charSet=self.charset)),
209            ('Access-Control-Allow-Origin', '*')
210        ]
211
212        for key in self.__arrHeaders:
213            arrHeader.append((key, self.__arrHeaders[key]))
214
215        for key in self.__arrCookies:
216            arrHeader.append(('Set-Cookie', str(self.__arrCookies[key])))
217
218        return arrHeader

Representation of the response, that is sent back to the web server

Response(request: Wsgi_15Watt.Request.Request, startResponse)
116    def __init__(self, request: Request, startResponse):
117        self.__request       = request
118        self.__startResponse = startResponse
119        self.contentType     = 'text/plain'
120        self.charset         = 'utf-8'
121        self.returnCode      = 200
122        self.__arrHeaders    = {}
123        self.__arrCookies    = {}
124
125        # The content to send as a byte array
126        self.__byteContent = None
127
128        # The content to send as a string
129        self.__stringContent = ''
contentType
charset
returnCode
request: Wsgi_15Watt.Request.Request
133    @property
134    def request(self) -> Request:
135        return self.__request
stringContent: str
138    @property
139    def stringContent(self) -> str:
140        return self.__stringContent
byteContent: bytes
149    @property
150    def byteContent(self) -> bytes:
151        return self.__byteContent
def addHeader(self, key: str, value: str):
160    def addHeader(self, key: str, value: str):
161        """
162            Adds a header line to the response.
163            An already added header is overwritten
164        """
165        self.__arrHeaders[key] = value
166        return self

Adds a header line to the response. An already added header is overwritten

def addCookie(self, cookie: Wsgi_15Watt.Cookie.Cookie):
169    def addCookie(self, cookie: Cookie):
170        """
171            Adds a cookie to the response.
172            A already added cookie is overwritten
173        """
174        self.__arrCookies[cookie.key] = cookie
175        return self

Adds a cookie to the response. A already added cookie is overwritten

def getContent(self) -> list[bytes]:
178    def getContent(self) -> list[bytes]:
179        """
180            Returns the rendered content.
181            startResponse has been called before.
182        :return:
183        """
184        # Run startResponse to the web server
185        self.__startResponse(
186            ResponseCodeToText(respCode=self.returnCode).asText(),
187            self.__buildHeader()
188        )
189
190        if self.__byteContent is None:
191            # Byte content has not been created yet
192            self.__byteContent = bytes(self.__stringContent, self.charset)
193
194        # Return the byte content
195        return [self.__byteContent]

Returns the rendered content. startResponse has been called before.

Returns
def redirect(self, url: str, code: int = 303) -> None:
198    def redirect(self, url: str, code: int = 303) -> None:
199        """
200            Redirects the user to the given url
201        """
202        self.returnCode = code
203        self.addHeader('Location', url)

Redirects the user to the given url