1
2
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 """
9
10 import re
11
12 __all__ = ['HTTP', 'redirect']
13
14 defined_status = {
15 200: 'OK',
16 201: 'CREATED',
17 202: 'ACCEPTED',
18 203: 'NON-AUTHORITATIVE INFORMATION',
19 204: 'NO CONTENT',
20 205: 'RESET CONTENT',
21 206: 'PARTIAL CONTENT',
22 301: 'MOVED PERMANENTLY',
23 302: 'FOUND',
24 303: 'SEE OTHER',
25 304: 'NOT MODIFIED',
26 305: 'USE PROXY',
27 307: 'TEMPORARY REDIRECT',
28 400: 'BAD REQUEST',
29 401: 'UNAUTHORIZED',
30 402: 'PAYMENT REQUIRED',
31 403: 'FORBIDDEN',
32 404: 'NOT FOUND',
33 405: 'METHOD NOT ALLOWED',
34 406: 'NOT ACCEPTABLE',
35 407: 'PROXY AUTHENTICATION REQUIRED',
36 408: 'REQUEST TIMEOUT',
37 409: 'CONFLICT',
38 410: 'GONE',
39 411: 'LENGTH REQUIRED',
40 412: 'PRECONDITION FAILED',
41 413: 'REQUEST ENTITY TOO LARGE',
42 414: 'REQUEST-URI TOO LONG',
43 415: 'UNSUPPORTED MEDIA TYPE',
44 416: 'REQUESTED RANGE NOT SATISFIABLE',
45 417: 'EXPECTATION FAILED',
46 422: 'UNPROCESSABLE ENTITY',
47 429: 'TOO MANY REQUESTS',
48 451: 'UNAVAILABLE FOR LEGAL REASONS',
49 500: 'INTERNAL SERVER ERROR',
50 501: 'NOT IMPLEMENTED',
51 502: 'BAD GATEWAY',
52 503: 'SERVICE UNAVAILABLE',
53 504: 'GATEWAY TIMEOUT',
54 505: 'HTTP VERSION NOT SUPPORTED',
55 }
56
57 regex_status = re.compile('^\d{3} [0-9A-Z ]+$')
58
59 -class HTTP(Exception):
60
61 - def __init__(
62 self,
63 status,
64 body='',
65 cookies=None,
66 **headers
67 ):
72
74 if cookies and len(cookies) > 0:
75 self.headers['Set-Cookie'] = [
76 str(cookie)[11:] for cookie in cookies.values()]
77
78 - def to(self, responder, env=None):
79 env = env or {}
80 status = self.status
81 headers = self.headers
82 if status in defined_status:
83 status = '%d %s' % (status, defined_status[status])
84 elif isinstance(status, int):
85 status = '%d UNKNOWN ERROR' % status
86 else:
87 status = str(status)
88 if not regex_status.match(status):
89 status = '500 %s' % (defined_status[500])
90 headers.setdefault('Content-Type', 'text/html; charset=UTF-8')
91 body = self.body
92 if status[:1] == '4':
93 if not body:
94 body = status
95 if isinstance(body, str):
96 headers['Content-Length'] = len(body)
97 rheaders = []
98 for k, v in headers.iteritems():
99 if isinstance(v, list):
100 rheaders += [(k, str(item)) for item in v]
101 elif not v is None:
102 rheaders.append((k, str(v)))
103 responder(status, rheaders)
104 if env.get('request_method', '') == 'HEAD':
105 return ['']
106 elif isinstance(body, str):
107 return [body]
108 elif hasattr(body, '__iter__'):
109 return body
110 else:
111 return [str(body)]
112
113 @property
115 """
116 compose a message describing this exception
117
118 "status defined_status [web2py_error]"
119
120 message elements that are not defined are omitted
121 """
122 msg = '%(status)s'
123 if self.status in defined_status:
124 msg = '%(status)s %(defined_status)s'
125 if 'web2py_error' in self.headers:
126 msg += ' [%(web2py_error)s]'
127 return msg % dict(
128 status=self.status,
129 defined_status=defined_status.get(self.status),
130 web2py_error=self.headers.get('web2py_error'))
131
133 "stringify me"
134 return self.message
135
136
137 -def redirect(location='', how=303, client_side=False):
138 if location:
139 from gluon import current
140 loc = location.replace('\r', '%0D').replace('\n', '%0A')
141 if client_side and current.request.ajax:
142 raise HTTP(200, **{'web2py-redirect-location': loc})
143 else:
144 raise HTTP(how,
145 'You are being redirected <a href="%s">here</a>' % loc,
146 Location=loc)
147 else:
148 from gluon import current
149 if client_side and current.request.ajax:
150 raise HTTP(200, **{'web2py-component-command': 'window.location.reload(true)'})
151