author | Sylvain Thénault <sylvain.thenault@logilab.fr> |
Tue, 01 Jun 2010 12:21:03 +0200 | |
branch | stable |
changeset 5617 | f0bc8f5ddee2 |
parent 5426 | 0d4853a6e5ee |
child 5442 | 3ed8afbbdf70 |
permissions | -rw-r--r-- |
5421
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4721
diff
changeset
|
1 |
# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4721
diff
changeset
|
2 |
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4721
diff
changeset
|
3 |
# |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4721
diff
changeset
|
4 |
# This file is part of CubicWeb. |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4721
diff
changeset
|
5 |
# |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4721
diff
changeset
|
6 |
# CubicWeb is free software: you can redistribute it and/or modify it under the |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4721
diff
changeset
|
7 |
# terms of the GNU Lesser General Public License as published by the Free |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4721
diff
changeset
|
8 |
# Software Foundation, either version 2.1 of the License, or (at your option) |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4721
diff
changeset
|
9 |
# any later version. |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4721
diff
changeset
|
10 |
# |
5424
8ecbcbff9777
replace logilab-common by CubicWeb in disclaimer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5421
diff
changeset
|
11 |
# CubicWeb is distributed in the hope that it will be useful, but WITHOUT |
5421
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4721
diff
changeset
|
12 |
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4721
diff
changeset
|
13 |
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4721
diff
changeset
|
14 |
# details. |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4721
diff
changeset
|
15 |
# |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4721
diff
changeset
|
16 |
# You should have received a copy of the GNU Lesser General Public License along |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4721
diff
changeset
|
17 |
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>. |
0 | 18 |
"""WSGI request handler for cubicweb |
19 |
||
20 |
""" |
|
21 |
||
22 |
__docformat__ = "restructuredtext en" |
|
23 |
||
4719
aaed3f813ef8
kill dead/useless code as suggested by pylint
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4252
diff
changeset
|
24 |
from cubicweb import AuthenticationError |
5223
6abd6e3599f4
#773448: refactor session and 'no connection' handling, by introducing proper web session. We should now be able to see page even when no anon is configured, and be redirected to the login form as soon as one tries to do a query.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4721
diff
changeset
|
25 |
from cubicweb.web import Redirect, DirectResponse, StatusResponse, LogOut |
0 | 26 |
from cubicweb.web.application import CubicWebPublisher |
27 |
from cubicweb.wsgi.request import CubicWebWsgiRequest |
|
28 |
||
29 |
# See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html |
|
30 |
STATUS_CODE_TEXT = { |
|
31 |
100: 'CONTINUE', |
|
32 |
101: 'SWITCHING PROTOCOLS', |
|
33 |
200: 'OK', |
|
34 |
201: 'CREATED', |
|
35 |
202: 'ACCEPTED', |
|
36 |
203: 'NON-AUTHORITATIVE INFORMATION', |
|
37 |
204: 'NO CONTENT', |
|
38 |
205: 'RESET CONTENT', |
|
39 |
206: 'PARTIAL CONTENT', |
|
40 |
300: 'MULTIPLE CHOICES', |
|
41 |
301: 'MOVED PERMANENTLY', |
|
42 |
302: 'FOUND', |
|
43 |
303: 'SEE OTHER', |
|
44 |
304: 'NOT MODIFIED', |
|
45 |
305: 'USE PROXY', |
|
46 |
306: 'RESERVED', |
|
47 |
307: 'TEMPORARY REDIRECT', |
|
48 |
400: 'BAD REQUEST', |
|
49 |
401: 'UNAUTHORIZED', |
|
50 |
402: 'PAYMENT REQUIRED', |
|
51 |
403: 'FORBIDDEN', |
|
52 |
404: 'NOT FOUND', |
|
53 |
405: 'METHOD NOT ALLOWED', |
|
54 |
406: 'NOT ACCEPTABLE', |
|
55 |
407: 'PROXY AUTHENTICATION REQUIRED', |
|
56 |
408: 'REQUEST TIMEOUT', |
|
57 |
409: 'CONFLICT', |
|
58 |
410: 'GONE', |
|
59 |
411: 'LENGTH REQUIRED', |
|
60 |
412: 'PRECONDITION FAILED', |
|
61 |
413: 'REQUEST ENTITY TOO LARGE', |
|
62 |
414: 'REQUEST-URI TOO LONG', |
|
63 |
415: 'UNSUPPORTED MEDIA TYPE', |
|
64 |
416: 'REQUESTED RANGE NOT SATISFIABLE', |
|
65 |
417: 'EXPECTATION FAILED', |
|
66 |
500: 'INTERNAL SERVER ERROR', |
|
67 |
501: 'NOT IMPLEMENTED', |
|
68 |
502: 'BAD GATEWAY', |
|
69 |
503: 'SERVICE UNAVAILABLE', |
|
70 |
504: 'GATEWAY TIMEOUT', |
|
71 |
505: 'HTTP VERSION NOT SUPPORTED', |
|
72 |
} |
|
73 |
||
74 |
||
75 |
class WSGIResponse(object): |
|
76 |
"""encapsulates the wsgi response parameters |
|
77 |
(code, headers and body if there is one) |
|
78 |
""" |
|
79 |
def __init__(self, code, req, body=None): |
|
80 |
text = STATUS_CODE_TEXT.get(code, 'UNKNOWN STATUS CODE') |
|
81 |
self.status = '%s %s' % (code, text) |
|
82 |
self.headers = [(str(k), str(v)) for k, v in req.headers_out.items()] |
|
83 |
if body: |
|
84 |
self.body = [body] |
|
85 |
else: |
|
86 |
self.body = [] |
|
87 |
||
88 |
def __iter__(self): |
|
89 |
return iter(self.body) |
|
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
0
diff
changeset
|
90 |
|
0 | 91 |
|
92 |
||
93 |
class CubicWebWSGIApplication(object): |
|
94 |
"""This is the wsgi application which will be called by the |
|
95 |
wsgi server with the WSGI ``environ`` and ``start_response`` |
|
96 |
parameters. |
|
97 |
||
98 |
XXX: missing looping tasks and proper repository shutdown when |
|
99 |
the application is stopped. |
|
100 |
NOTE: no pyro |
|
101 |
""" |
|
102 |
||
103 |
def __init__(self, config, debug=None, vreg=None): |
|
104 |
self.appli = CubicWebPublisher(config, debug=debug, vreg=vreg) |
|
105 |
self.debugmode = debug |
|
106 |
self.config = config |
|
107 |
self.base_url = None |
|
108 |
# self.base_url = config['base-url'] or config.default_base_url() |
|
109 |
# assert self.base_url[-1] == '/' |
|
110 |
# self.https_url = config['https-url'] |
|
111 |
# assert not self.https_url or self.https_url[-1] == '/' |
|
2770
356e9d7c356d
R propagate registry API changes
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents:
2058
diff
changeset
|
112 |
self.url_rewriter = self.appli.vreg['components'].select_or_none('urlrewriter') |
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
0
diff
changeset
|
113 |
|
0 | 114 |
def _render(self, req): |
115 |
"""this function performs the actual rendering |
|
116 |
XXX missing: https handling, url rewriting, cache management, |
|
117 |
authentication |
|
118 |
""" |
|
119 |
if self.base_url is None: |
|
120 |
self.base_url = self.config._base_url = req.base_url() |
|
121 |
# XXX https handling needs to be implemented |
|
122 |
if req.authmode == 'http': |
|
123 |
# activate realm-based auth |
|
124 |
realm = self.config['realm'] |
|
125 |
req.set_header('WWW-Authenticate', [('Basic', {'realm' : realm })], raw=False) |
|
126 |
try: |
|
127 |
self.appli.connect(req) |
|
128 |
except Redirect, ex: |
|
129 |
return self.redirect(req, ex.location) |
|
130 |
path = req.path |
|
131 |
if not path or path == "/": |
|
132 |
path = 'view' |
|
133 |
try: |
|
134 |
result = self.appli.publish(path, req) |
|
135 |
except DirectResponse, ex: |
|
136 |
return WSGIResponse(200, req, ex.response) |
|
137 |
except StatusResponse, ex: |
|
138 |
return WSGIResponse(ex.status, req, ex.content) |
|
5223
6abd6e3599f4
#773448: refactor session and 'no connection' handling, by introducing proper web session. We should now be able to see page even when no anon is configured, and be redirected to the login form as soon as one tries to do a query.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4721
diff
changeset
|
139 |
except AuthenticationError: # must be before AuthenticationError |
0 | 140 |
return self.request_auth(req) |
5223
6abd6e3599f4
#773448: refactor session and 'no connection' handling, by introducing proper web session. We should now be able to see page even when no anon is configured, and be redirected to the login form as soon as one tries to do a query.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4721
diff
changeset
|
141 |
except LogOut: |
0 | 142 |
if self.config['auth-mode'] == 'cookie': |
143 |
# in cookie mode redirecting to the index view is enough : |
|
144 |
# either anonymous connection is allowed and the page will |
|
145 |
# be displayed or we'll be redirected to the login form |
|
146 |
msg = req._('you have been logged out') |
|
147 |
# if req.https: |
|
148 |
# req._base_url = self.base_url |
|
149 |
# req.https = False |
|
150 |
url = req.build_url('view', vid='index', __message=msg) |
|
151 |
return self.redirect(req, url) |
|
152 |
else: |
|
153 |
# in http we have to request auth to flush current http auth |
|
154 |
# information |
|
155 |
return self.request_auth(req, loggedout=True) |
|
156 |
except Redirect, ex: |
|
157 |
return self.redirect(req, ex.location) |
|
158 |
if not result: |
|
159 |
# no result, something went wrong... |
|
160 |
self.error('no data (%s)', req) |
|
161 |
# 500 Internal server error |
|
162 |
return self.redirect(req, req.build_url('error')) |
|
163 |
return WSGIResponse(200, req, result) |
|
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
0
diff
changeset
|
164 |
|
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
0
diff
changeset
|
165 |
|
0 | 166 |
def __call__(self, environ, start_response): |
167 |
"""WSGI protocol entry point""" |
|
168 |
req = CubicWebWsgiRequest(environ, self.appli.vreg, self.base_url) |
|
169 |
response = self._render(req) |
|
170 |
start_response(response.status, response.headers) |
|
171 |
return response.body |
|
172 |
||
173 |
def redirect(self, req, location): |
|
174 |
"""convenience function which builds a redirect WSGIResponse""" |
|
175 |
self.debug('redirecting to %s', location) |
|
176 |
req.set_header('location', str(location)) |
|
177 |
return WSGIResponse(303, req) |
|
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
0
diff
changeset
|
178 |
|
0 | 179 |
def request_auth(self, req, loggedout=False): |
180 |
"""returns the appropriate WSGIResponse to require the user to log in |
|
181 |
""" |
|
182 |
# if self.https_url and req.base_url() != self.https_url: |
|
183 |
# return self.redirect(self.https_url + 'login') |
|
184 |
if self.config['auth-mode'] == 'http': |
|
185 |
code = 401 # UNAUTHORIZED |
|
186 |
else: |
|
187 |
code = 403 # FORBIDDEN |
|
188 |
if loggedout: |
|
189 |
# if req.https: |
|
190 |
# req._base_url = self.base_url |
|
191 |
# req.https = False |
|
192 |
content = self.appli.loggedout_content(req) |
|
193 |
else: |
|
194 |
content = self.appli.need_login_content(req) |
|
195 |
return WSGIResponse(code, req, content) |
|
196 |
||
197 |
||
198 |
from logging import getLogger |
|
199 |
from cubicweb import set_log_methods |
|
200 |
set_log_methods(CubicWebWSGIApplication, getLogger('cubicweb.wsgi')) |