wsgi/handler.py
changeset 11057 0b59724cb3f2
parent 11052 058bb3dc685f
child 11058 23eb30449fe5
equal deleted inserted replaced
11052:058bb3dc685f 11057:0b59724cb3f2
     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'))