source: OpenRLabs-Git/deploy/rlabs-docker/web2py-rlabs/gluon/http.py

main
Last change on this file was 42bd667, checked in by David Fuertes <dfuertes@…>, 4 years ago

Historial Limpio

  • Property mode set to 100755
File size: 5.9 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4"""
5| This file is part of the web2py Web Framework
6| Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
7| License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
8
9HTTP statuses helpers
10--------------------------------------------
11"""
12
13import re
14from gluon._compat import iteritems, unicodeT, to_bytes
15
16__all__ = ['HTTP', 'redirect']
17
18defined_status = {
19    200: 'OK',
20    201: 'CREATED',
21    202: 'ACCEPTED',
22    203: 'NON-AUTHORITATIVE INFORMATION',
23    204: 'NO CONTENT',
24    205: 'RESET CONTENT',
25    206: 'PARTIAL CONTENT',
26    301: 'MOVED PERMANENTLY',
27    302: 'FOUND',
28    303: 'SEE OTHER',
29    304: 'NOT MODIFIED',
30    305: 'USE PROXY',
31    307: 'TEMPORARY REDIRECT',
32    400: 'BAD REQUEST',
33    401: 'UNAUTHORIZED',
34    402: 'PAYMENT REQUIRED',
35    403: 'FORBIDDEN',
36    404: 'NOT FOUND',
37    405: 'METHOD NOT ALLOWED',
38    406: 'NOT ACCEPTABLE',
39    407: 'PROXY AUTHENTICATION REQUIRED',
40    408: 'REQUEST TIMEOUT',
41    409: 'CONFLICT',
42    410: 'GONE',
43    411: 'LENGTH REQUIRED',
44    412: 'PRECONDITION FAILED',
45    413: 'REQUEST ENTITY TOO LARGE',
46    414: 'REQUEST-URI TOO LONG',
47    415: 'UNSUPPORTED MEDIA TYPE',
48    416: 'REQUESTED RANGE NOT SATISFIABLE',
49    417: 'EXPECTATION FAILED',
50    422: 'UNPROCESSABLE ENTITY',
51    429: 'TOO MANY REQUESTS',
52    451: 'UNAVAILABLE FOR LEGAL REASONS',  # http://www.451unavailable.org/
53    500: 'INTERNAL SERVER ERROR',
54    501: 'NOT IMPLEMENTED',
55    502: 'BAD GATEWAY',
56    503: 'SERVICE UNAVAILABLE',
57    504: 'GATEWAY TIMEOUT',
58    505: 'HTTP VERSION NOT SUPPORTED',
59    509: 'BANDWIDTH LIMIT EXCEEDED',
60}
61
62regex_status = re.compile('^\d{3} [0-9A-Z ]+$')
63
64
65class HTTP(Exception):
66    """Raises an HTTP response
67
68    Args:
69        status: usually an integer. If it's a well known status code, the ERROR
70          message will be automatically added. A string can also be passed
71          as `510 Foo Bar` and in that case the status code and the error
72          message will be parsed accordingly
73        body: what to return as body. If left as is, will return the error code
74          and the status message in the body itself
75        cookies: pass cookies along (usually not needed)
76        headers: pass headers as usual dict mapping
77    """
78
79    def __init__(
80        self,
81        status,
82        body='',
83        cookies=None,
84        **headers
85    ):
86        self.status = status
87        self.body = body
88        self.headers = headers
89        self.cookies2headers(cookies)
90
91    def cookies2headers(self, cookies):
92        if cookies and len(cookies) > 0:
93            self.headers['Set-Cookie'] = [
94                str(cookie)[11:] for cookie in cookies.values()]
95
96    def to(self, responder, env=None):
97        env = env or {}
98        status = self.status
99        headers = self.headers
100        if status in defined_status:
101            status = '%d %s' % (status, defined_status[status])
102        elif isinstance(status, int):
103            status = '%d UNKNOWN ERROR' % status
104        else:
105            status = str(status)
106            if not regex_status.match(status):
107                status = '500 %s' % (defined_status[500])
108        headers.setdefault('Content-Type', 'text/html; charset=UTF-8')
109        body = self.body
110        if status[:1] == '4':
111            if not body:
112                body = status
113            if isinstance(body, (str, bytes, bytearray)):
114                if isinstance(body, unicodeT):
115                    body = to_bytes(body) # This must be done before len
116                headers['Content-Length'] = len(body)
117        rheaders = []
118        for k, v in iteritems(headers):
119            if isinstance(v, list):
120                rheaders += [(k, str(item)) for item in v]
121            elif v is not None:
122                rheaders.append((k, str(v)))
123        responder(status, rheaders)
124        if env.get('request_method', '') == 'HEAD':
125            return ['']
126        elif isinstance(body, (str, bytes, bytearray)):
127            if isinstance(body, unicodeT):
128                body = to_bytes(body)
129            return [body]
130        elif hasattr(body, '__iter__'):
131            return body
132        else:
133            body = str(body)
134            if isinstance(body, unicodeT):
135                body = to_bytes(body)
136            return [body]
137
138    @property
139    def message(self):
140        """
141        compose a message describing this exception
142
143            "status defined_status [web2py_error]"
144
145        message elements that are not defined are omitted
146        """
147        msg = '%(status)s'
148        if self.status in defined_status:
149            msg = '%(status)s %(defined_status)s'
150        if 'web2py_error' in self.headers:
151            msg += ' [%(web2py_error)s]'
152        return msg % dict(
153            status=self.status,
154            defined_status=defined_status.get(self.status),
155            web2py_error=self.headers.get('web2py_error'))
156
157    def __str__(self):
158        """stringify me"""
159        return self.message
160
161
162def redirect(location='', how=303, client_side=False, headers=None):
163    """Raises a redirect (303)
164
165    Args:
166        location: the url where to redirect
167        how: what HTTP status code to use when redirecting
168        client_side: if set to True, it triggers a reload of the entire page
169          when the fragment has been loaded as a component
170    """
171    headers = headers or {}
172    if location:
173        from gluon.globals import current
174        loc = location.replace('\r', '%0D').replace('\n', '%0A')
175        if client_side and current.request.ajax:
176            headers['web2py-redirect-location'] = loc
177            raise HTTP(200, **headers)
178        else:
179            headers['Location'] = loc
180            raise HTTP(how,
181                       'You are being redirected <a href="%s">here</a>' % loc,
182                       **headers)
183    else:
184        from gluon.globals import current
185        if client_side and current.request.ajax:
186            headers['web2py-component-command'] = 'window.location.reload(true)'
187            raise HTTP(200, **headers)
Note: See TracBrowser for help on using the repository browser.