1 # copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
|
2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr |
|
3 # |
|
4 # This file is part of CubicWeb. |
|
5 # |
|
6 # CubicWeb is free software: you can redistribute it and/or modify it under the |
|
7 # terms of the GNU Lesser General Public License as published by the Free |
|
8 # Software Foundation, either version 2.1 of the License, or (at your option) |
|
9 # any later version. |
|
10 # |
|
11 # CubicWeb is distributed in the hope that it will be useful, but WITHOUT |
|
12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
|
13 # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
|
14 # details. |
|
15 # |
|
16 # You should have received a copy of the GNU Lesser General Public License along |
|
17 # with CubicWeb. If not, see <http://www.gnu.org/licenses/>. |
|
18 """WSGI request handler for cubicweb""" |
|
19 |
|
20 __docformat__ = "restructuredtext en" |
|
21 |
|
22 from itertools import chain, repeat |
|
23 |
|
24 from six.moves import zip |
|
25 |
|
26 from cubicweb import AuthenticationError |
|
27 from cubicweb.web import DirectResponse |
|
28 from cubicweb.web.application import CubicWebPublisher |
|
29 from cubicweb.wsgi.request import CubicWebWsgiRequest |
|
30 |
|
31 # See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html |
|
32 STATUS_CODE_TEXT = { |
|
33 100: 'CONTINUE', |
|
34 101: 'SWITCHING PROTOCOLS', |
|
35 200: 'OK', |
|
36 201: 'CREATED', |
|
37 202: 'ACCEPTED', |
|
38 203: 'NON-AUTHORITATIVE INFORMATION', |
|
39 204: 'NO CONTENT', |
|
40 205: 'RESET CONTENT', |
|
41 206: 'PARTIAL CONTENT', |
|
42 300: 'MULTIPLE CHOICES', |
|
43 301: 'MOVED PERMANENTLY', |
|
44 302: 'FOUND', |
|
45 303: 'SEE OTHER', |
|
46 304: 'NOT MODIFIED', |
|
47 305: 'USE PROXY', |
|
48 306: 'RESERVED', |
|
49 307: 'TEMPORARY REDIRECT', |
|
50 400: 'BAD REQUEST', |
|
51 401: 'UNAUTHORIZED', |
|
52 402: 'PAYMENT REQUIRED', |
|
53 403: 'FORBIDDEN', |
|
54 404: 'NOT FOUND', |
|
55 405: 'METHOD NOT ALLOWED', |
|
56 406: 'NOT ACCEPTABLE', |
|
57 407: 'PROXY AUTHENTICATION REQUIRED', |
|
58 408: 'REQUEST TIMEOUT', |
|
59 409: 'CONFLICT', |
|
60 410: 'GONE', |
|
61 411: 'LENGTH REQUIRED', |
|
62 412: 'PRECONDITION FAILED', |
|
63 413: 'REQUEST ENTITY TOO LARGE', |
|
64 414: 'REQUEST-URI TOO LONG', |
|
65 415: 'UNSUPPORTED MEDIA TYPE', |
|
66 416: 'REQUESTED RANGE NOT SATISFIABLE', |
|
67 417: 'EXPECTATION FAILED', |
|
68 500: 'INTERNAL SERVER ERROR', |
|
69 501: 'NOT IMPLEMENTED', |
|
70 502: 'BAD GATEWAY', |
|
71 503: 'SERVICE UNAVAILABLE', |
|
72 504: 'GATEWAY TIMEOUT', |
|
73 505: 'HTTP VERSION NOT SUPPORTED', |
|
74 } |
|
75 |
|
76 class WSGIResponse(object): |
|
77 """encapsulates the wsgi response parameters |
|
78 (code, headers and body if there is one) |
|
79 """ |
|
80 def __init__(self, code, req, body=None): |
|
81 text = STATUS_CODE_TEXT.get(code, 'UNKNOWN STATUS CODE') |
|
82 self.status = '%s %s' % (code, text) |
|
83 self.headers = list(chain(*[zip(repeat(k), v) |
|
84 for k, v in req.headers_out.getAllRawHeaders()])) |
|
85 self.headers = [(str(k), str(v)) for k, v in self.headers] |
|
86 if body: |
|
87 self.body = [body] |
|
88 else: |
|
89 self.body = [] |
|
90 |
|
91 def __iter__(self): |
|
92 return iter(self.body) |
|
93 |
|
94 |
|
95 class CubicWebWSGIApplication(object): |
|
96 """This is the wsgi application which will be called by the |
|
97 wsgi server with the WSGI ``environ`` and ``start_response`` |
|
98 parameters. |
|
99 """ |
|
100 |
|
101 def __init__(self, config): |
|
102 self.appli = CubicWebPublisher(config.repository(), config) |
|
103 self.config = config |
|
104 self.base_url = self.config['base-url'] |
|
105 self.url_rewriter = self.appli.vreg['components'].select_or_none('urlrewriter') |
|
106 |
|
107 def _render(self, req): |
|
108 """this function performs the actual rendering |
|
109 """ |
|
110 try: |
|
111 path = req.path |
|
112 result = self.appli.handle_request(req, path) |
|
113 except DirectResponse as ex: |
|
114 return ex.response |
|
115 return WSGIResponse(req.status_out, req, result) |
|
116 |
|
117 |
|
118 def __call__(self, environ, start_response): |
|
119 """WSGI protocol entry point""" |
|
120 req = CubicWebWsgiRequest(environ, self.appli.vreg) |
|
121 response = self._render(req) |
|
122 start_response(response.status, response.headers) |
|
123 return response.body |
|
124 |
|
125 |
|
126 |
|
127 # these are overridden by set_log_methods below |
|
128 # only defining here to prevent pylint from complaining |
|
129 info = warning = error = critical = exception = debug = lambda msg,*a,**kw: None |
|
130 |
|
131 |
|
132 from logging import getLogger |
|
133 from cubicweb import set_log_methods |
|
134 set_log_methods(CubicWebWSGIApplication, getLogger('cubicweb.wsgi')) |
|