source: OpenRLabs-Git/deploy/rlabs-docker/web2py-rlabs/handlers/modpythonhandler.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: 6.0 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4"""
5This file is part of the web2py Web Framework
6Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
7License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
8
9WSGI wrapper for mod_python. Requires Python 2.2 or greater.
10Part of CherryPy mut modified by Massimo Di Pierro (2008) for web2py
11
12<Location /myapp>
13    SetHandler python-program
14    PythonHandler modpythonhandler
15    PythonPath \"['/path/to/web2py/'] + sys.path\"
16    PythonOption SCRIPT_NAME /myapp
17</Location>
18
19Some WSGI implementations assume that the SCRIPT_NAME environ variable will
20always be equal to 'the root URL of the app'; Apache probably won't act as
21you expect in that case. You can add another PythonOption directive to tell
22modpython_gateway to force that behavior:
23
24    PythonOption SCRIPT_NAME /mcontrol
25
26The module.function will be called with no arguments on server shutdown,
27once for each child process or thread.
28"""
29
30import traceback
31import sys
32import os
33from mod_python import apache
34
35path = os.path.dirname(os.path.abspath(__file__))
36os.chdir(path)
37
38if not os.path.isdir('applications'):
39    raise RuntimeError('Running from the wrong folder')
40
41sys.path = [path] + [p for p in sys.path if not p == path]
42
43import gluon.main
44
45
46class InputWrapper(object):
47    """ Input wrapper for the wsgi handler  """
48
49    def __init__(self, req):
50        """ InputWrapper constructor  """
51
52        self.req = req
53
54    def close(self):
55        """ """
56
57        pass
58
59    def read(self, size=-1):
60        """ Wrapper for req.read  """
61
62        return self.req.read(size)
63
64    def readline(self, size=-1):
65        """ Wrapper for req.readline  """
66
67        return self.req.readline(size)
68
69    def readlines(self, hint=-1):
70        """ Wrapper for req.readlines  """
71
72        return self.req.readlines(hint)
73
74    def __iter__(self):
75        """ Defines a generator with the req data  """
76
77        line = self.readline()
78        while line:
79            yield line
80
81            # Notice this won't prefetch the next line; it only
82            # gets called if the generator is resumed.
83            line = self.readline()
84
85
86class ErrorWrapper(object):
87    """ Error wrapper for the wsgi handler  """
88
89    def __init__(self, req):
90        """ ErrorWrapper constructor """
91
92        self.req = req
93
94    def flush(self):
95        """   """
96
97        pass
98
99    def write(self, msg):
100        """ Logs the given msg in the log file """
101
102        self.req.log_error(msg)
103
104    def writelines(self, seq):
105        """ Writes various lines in the log file """
106
107        self.write(''.join(seq))
108
109
110bad_value = "You must provide a PythonOption '%s', either 'on' or 'off', when running a version of mod_python < 3.1"
111
112
113class Handler:
114    """ Defines the handler  """
115
116    def __init__(self, req):
117        """ Handler constructor  """
118
119        self.started = False
120        options = req.get_options()
121
122        # Threading and forking
123        try:
124            q = apache.mpm_query
125            threaded = q(apache.AP_MPMQ_IS_THREADED)
126            forked = q(apache.AP_MPMQ_IS_FORKED)
127        except AttributeError:
128            threaded = options.get('multithread', '').lower()
129
130            if threaded == 'on':
131                threaded = True
132            elif threaded == 'off':
133                threaded = False
134            else:
135                raise ValueError(bad_value % 'multithread')
136
137            forked = options.get('multiprocess', '').lower()
138
139            if forked == 'on':
140                forked = True
141            elif forked == 'off':
142                forked = False
143            else:
144                raise ValueError(bad_value % 'multiprocess')
145
146        env = self.environ = dict(apache.build_cgi_env(req))
147
148        if 'SCRIPT_NAME' in options:
149            # Override SCRIPT_NAME and PATH_INFO if requested.
150            env['SCRIPT_NAME'] = options['SCRIPT_NAME']
151            env['PATH_INFO'] = req.uri[len(options['SCRIPT_NAME']):]
152
153        env['wsgi.input'] = InputWrapper(req)
154        env['wsgi.errors'] = ErrorWrapper(req)
155        env['wsgi.version'] = (1, 0)
156        env['wsgi.run_once'] = False
157
158        if env.get('HTTPS') in ('yes', 'on', '1'):
159            env['wsgi.url_scheme'] = 'https'
160        else:
161            env['wsgi.url_scheme'] = 'http'
162
163        env['wsgi.multithread'] = threaded
164        env['wsgi.multiprocess'] = forked
165
166        self.request = req
167
168    def run(self, application):
169        """ Run the application  """
170
171        try:
172            result = application(self.environ, self.start_response)
173
174            for data in result:
175                self.write(data)
176
177            if not self.started:
178                self.request.set_content_length(0)
179
180            if hasattr(result, 'close'):
181                result.close()
182        except:
183            traceback.print_exc(None, self.environ['wsgi.errors'])
184
185            if not self.started:
186                self.request.status = 500
187                self.request.content_type = 'text/plain'
188                data = 'A server error occurred. Please contact the ' + \
189                       'administrator.'
190                self.request.set_content_length(len(data))
191                self.request.write(data)
192
193    def start_response(self, status, headers, exc_info=None):
194        """ Defines the request data  """
195
196        if exc_info:
197            try:
198                if self.started:
199                    raise exc_info[0], exc_info[1], exc_info[2]
200            finally:
201                exc_info = None
202
203        self.request.status = int(status[:3])
204
205        for (key, val) in headers:
206            if key.lower() == 'content-length':
207                self.request.set_content_length(int(val))
208            elif key.lower() == 'content-type':
209                self.request.content_type = val
210            else:
211                self.request.headers_out.add(key, val)
212
213        return self.write
214
215    def write(self, data):
216        """ Write the request data  """
217
218        if not self.started:
219            self.started = True
220
221        self.request.write(data)
222
223
224def handler(req):
225    """ Execute the gluon app  """
226
227    Handler(req).run(gluon.main.wsgibase)
228    return apache.OK
Note: See TracBrowser for help on using the repository browser.