root/galaxy-central/eggs/PasteDeploy-1.3.3-py2.6.egg/paste/deploy/config.py @ 3

リビジョン 3, 11.1 KB (コミッタ: kohda, 14 年 前)

Install Unix tools  http://hannonlab.cshl.edu/galaxy_unix_tools/galaxy.html

行番号 
1# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
2# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
3"""Paste Configuration Middleware and Objects"""
4import threading
5import re
6# Loaded lazily
7wsgilib = None
8local = None
9
10__all__ = ['DispatchingConfig', 'CONFIG', 'ConfigMiddleware', 'PrefixMiddleware']
11
12def local_dict():
13    global config_local, local
14    try:
15        return config_local.wsgi_dict
16    except NameError:
17        from paste.deploy.util.threadinglocal import local
18        config_local = local()
19        config_local.wsgi_dict = result = {}
20        return result
21    except AttributeError:
22        config_local.wsgi_dict = result = {}
23        return result
24
25class DispatchingConfig(object):
26
27    """
28    This is a configuration object that can be used globally,
29    imported, have references held onto.  The configuration may differ
30    by thread (or may not).
31
32    Specific configurations are registered (and deregistered) either
33    for the process or for threads.
34    """
35
36    # @@: What should happen when someone tries to add this
37    # configuration to itself?  Probably the conf should become
38    # resolved, and get rid of this delegation wrapper
39
40    _constructor_lock = threading.Lock()
41
42    def __init__(self):
43        self._constructor_lock.acquire()
44        try:
45            self.dispatching_id = 0
46            while 1:
47                self._local_key = 'paste.processconfig_%i' % self.dispatching_id
48                if not local_dict().has_key(self._local_key):
49                    break
50                self.dispatching_id += 1
51        finally:
52            self._constructor_lock.release()
53        self._process_configs = []
54
55    def push_thread_config(self, conf):
56        """
57        Make ``conf`` the active configuration for this thread.
58        Thread-local configuration always overrides process-wide
59        configuration.
60
61        This should be used like::
62
63            conf = make_conf()
64            dispatching_config.push_thread_config(conf)
65            try:
66                ... do stuff ...
67            finally:
68                dispatching_config.pop_thread_config(conf)
69        """
70        local_dict().setdefault(self._local_key, []).append(conf)
71
72    def pop_thread_config(self, conf=None):
73        """
74        Remove a thread-local configuration.  If ``conf`` is given,
75        it is checked against the popped configuration and an error
76        is emitted if they don't match.
77        """
78        self._pop_from(local_dict()[self._local_key], conf)
79
80    def _pop_from(self, lst, conf):
81        popped = lst.pop()
82        if conf is not None and popped is not conf:
83            raise AssertionError(
84                "The config popped (%s) is not the same as the config "
85                "expected (%s)"
86                % (popped, conf))
87
88    def push_process_config(self, conf):
89        """
90        Like push_thread_config, but applies the configuration to
91        the entire process.
92        """
93        self._process_configs.append(conf)
94
95    def pop_process_config(self, conf=None):
96        self._pop_from(self._process_configs, conf)
97           
98    def __getattr__(self, attr):
99        conf = self.current_conf()
100        if conf is None:
101            raise AttributeError(
102                "No configuration has been registered for this process "
103                "or thread")
104        return getattr(conf, attr)
105
106    def current_conf(self):
107        thread_configs = local_dict().get(self._local_key)
108        if thread_configs:
109            return thread_configs[-1]
110        elif self._process_configs:
111            return self._process_configs[-1]
112        else:
113            return None
114
115    def __getitem__(self, key):
116        # I thought __getattr__ would catch this, but apparently not
117        conf = self.current_conf()
118        if conf is None:
119            raise TypeError(
120                "No configuration has been registered for this process "
121                "or thread")
122        return conf[key]
123
124    def __contains__(self, key):
125        # I thought __getattr__ would catch this, but apparently not
126        return self.has_key(key)
127
128    def __setitem__(self, key, value):
129        # I thought __getattr__ would catch this, but apparently not
130        conf = self.current_conf()
131        conf[key] = value
132
133CONFIG = DispatchingConfig()
134
135class ConfigMiddleware(object):
136
137    """
138    A WSGI middleware that adds a ``paste.config`` key to the request
139    environment, as well as registering the configuration temporarily
140    (for the length of the request) with ``paste.CONFIG``.
141    """
142
143    def __init__(self, application, config):
144        """
145        This delegates all requests to `application`, adding a *copy*
146        of the configuration `config`.
147        """
148        self.application = application
149        self.config = config
150
151    def __call__(self, environ, start_response):
152        global wsgilib
153        if wsgilib is None:
154            import pkg_resources
155            pkg_resources.require('Paste')
156            from paste import wsgilib
157        popped_config = None
158        if 'paste.config' in environ:
159            popped_config = environ['paste.config']       
160        conf = environ['paste.config'] = self.config.copy()
161        app_iter = None
162        CONFIG.push_thread_config(conf)
163        try:
164            app_iter = self.application(environ, start_response)
165        finally:
166            if app_iter is None:
167                # An error occurred...
168                CONFIG.pop_thread_config(conf)
169                if popped_config is not None:
170                    environ['paste.config'] = popped_config
171        if type(app_iter) in (list, tuple):
172            # Because it is a concrete iterator (not a generator) we
173            # know the configuration for this thread is no longer
174            # needed:
175            CONFIG.pop_thread_config(conf)
176            if popped_config is not None:
177                environ['paste.config'] = popped_config
178            return app_iter
179        else:
180            def close_config():
181                CONFIG.pop_thread_config(conf)
182            new_app_iter = wsgilib.add_close(app_iter, close_config)
183            return new_app_iter
184
185def make_config_filter(app, global_conf, **local_conf):
186    conf = global_conf.copy()
187    conf.update(local_conf)
188    return ConfigMiddleware(app, conf)
189
190make_config_middleware = ConfigMiddleware.__doc__
191
192class PrefixMiddleware(object):
193    """Translate a given prefix into a SCRIPT_NAME for the filtered
194    application.
195   
196    PrefixMiddleware provides a way to manually override the root prefix
197    (SCRIPT_NAME) of your application for certain, rare situations.
198
199    When running an application under a prefix (such as '/james') in
200    FastCGI/apache, the SCRIPT_NAME environment variable is automatically
201    set to to the appropriate value: '/james'. Pylons' URL generating
202    functions, such as url_for, always take the SCRIPT_NAME value into account.
203
204    One situation where PrefixMiddleware is required is when an application
205    is accessed via a reverse proxy with a prefix. The application is accessed
206    through the reverse proxy via the the URL prefix '/james', whereas the
207    reverse proxy forwards those requests to the application at the prefix '/'.
208
209    The reverse proxy, being an entirely separate web server, has no way of
210    specifying the SCRIPT_NAME variable; it must be manually set by a
211    PrefixMiddleware instance. Without setting SCRIPT_NAME, url_for will
212    generate URLs such as: '/purchase_orders/1', when it should be
213    generating: '/james/purchase_orders/1'.
214
215    To filter your application through a PrefixMiddleware instance, add the
216    following to the '[app:main]' section of your .ini file:
217   
218    .. code-block:: ini
219       
220        filter-with = proxy-prefix
221
222        [filter:proxy-prefix]
223        use = egg:PasteDeploy#prefix
224        prefix = /james
225
226    The name ``proxy-prefix`` simply acts as an identifier of the filter
227    section; feel free to rename it.
228
229    Also, unless disabled, the ``X-Forwarded-Server`` header will be
230    translated to the ``Host`` header, for cases when that header is
231    lost in the proxying.  Also ``X-Forwarded-Host``,
232    ``X-Forwarded-Scheme``, and ``X-Forwarded-Proto`` are translated.
233
234    If ``force_port`` is set, SERVER_PORT and HTTP_HOST will be
235    rewritten with the given port.  You can use a number, string (like
236    '80') or the empty string (whatever is the default port for the
237    scheme).  This is useful in situations where there is port
238    forwarding going on, and the server believes itself to be on a
239    different port than what the outside world sees.
240
241    You can also use ``scheme`` to explicitly set the scheme (like
242    ``scheme = https``).
243    """
244    def __init__(self, app, global_conf=None, prefix='/',
245                 translate_forwarded_server=True,
246                 force_port=None, scheme=None):
247        self.app = app
248        self.prefix = prefix.rstrip('/')
249        self.translate_forwarded_server = translate_forwarded_server
250        self.regprefix = re.compile("^%s(.*)$" % self.prefix)
251        self.force_port = force_port
252        self.scheme = scheme
253   
254    def __call__(self, environ, start_response):
255        url = environ['PATH_INFO']
256        url = re.sub(self.regprefix, r'\1', url)
257        if not url: url = '/'
258        environ['PATH_INFO'] = url
259        environ['SCRIPT_NAME'] = self.prefix
260        if self.translate_forwarded_server:
261            if 'HTTP_X_FORWARDED_SERVER' in environ:
262                environ['SERVER_NAME'] = environ['HTTP_HOST'] = environ.pop('HTTP_X_FORWARDED_SERVER').split(',')[0]
263            if 'HTTP_X_FORWARDED_HOST' in environ:
264                environ['HTTP_HOST'] = environ.pop('HTTP_X_FORWARDED_HOST').split(',')[0]
265            if 'HTTP_X_FORWARDED_FOR' in environ:
266                environ['REMOTE_ADDR'] = environ.pop('HTTP_X_FORWARDED_FOR')
267            if 'HTTP_X_FORWARDED_SCHEME' in environ:
268                environ['wsgi.url_scheme'] = environ.pop('HTTP_X_FORWARDED_SCHEME')
269            elif 'HTTP_X_FORWARDED_PROTO' in environ:
270                environ['wsgi.url_scheme'] = environ.pop('HTTP_X_FORWARDED_PROTO')
271        if self.force_port is not None:
272            host = environ.get('HTTP_HOST', '').split(':', 1)[0]
273            if self.force_port:
274                host = '%s:%s' % (host, self.force_port)
275                environ['SERVER_PORT'] = str(self.force_port)
276            else:
277                if environ['wsgi.url_scheme'] == 'http':
278                    port = '80'
279                else:
280                    port = '443'
281                environ['SERVER_PORT'] = port
282            environ['HTTP_HOST'] = host
283        if self.scheme is not None:
284            environ['wsgi.url_scheme'] = self.scheme
285        return self.app(environ, start_response)
286
287def make_prefix_middleware(
288    app, global_conf, prefix='/',
289    translate_forwarded_server=True,
290    force_port=None, scheme=None):
291    from paste.deploy.converters import asbool
292    translate_forwarded_server = asbool(translate_forwarded_server)
293    return PrefixMiddleware(
294        app, prefix=prefix,
295        translate_forwarded_server=translate_forwarded_server,
296        force_port=force_port, scheme=scheme)
297
298make_prefix_middleware.__doc__ = PrefixMiddleware.__doc__
Note: リポジトリブラウザについてのヘルプは TracBrowser を参照してください。