PageRenderTime 83ms CodeModel.GetById 40ms app.highlight 13ms RepoModel.GetById 27ms app.codeStats 0ms

/silversupport/requests.py

https://bitbucket.org/ianb/silverlining/
Python | 133 lines | 107 code | 6 blank | 20 comment | 3 complexity | 8dc4807d8567f88c701a27a8b12d5bee MD5 | raw file
  1"""For running internal requests in production"""
  2
  3from cStringIO import StringIO
  4import os
  5import sys
  6import urllib
  7from silversupport.shell import run
  8
  9__all__ = ['internal_request']
 10
 11
 12def internal_request(app_config, hostname, path, body=None, environ=None,
 13                     capture_stdout=True):
 14    if app_config.platform == 'python':
 15        func = wsgi_internal_request
 16    elif app_config.platform == 'php':
 17        func = php_internal_request
 18    else:
 19        assert 0
 20    assert not body or isinstance(body, basestring), (
 21        "Incorrect body argument: %r" % body)
 22    return func(
 23        app_config, hostname, path, body, environ,
 24        capture_stdout=capture_stdout)
 25
 26
 27def wsgi_internal_request(app_config, hostname, path,
 28                          body=None, environ=None, capture_stdout=True):
 29    """Make an internal request:
 30
 31    ``wsgi_app``: The application to request from (use
 32    ``create_wsgi_app`` to get this)
 33
 34    ``hostname``: the hostname to request agains
 35
 36    ``path``: the request path
 37
 38    ``body``: any request body
 39
 40    ``environ``: any extra WSGI environment you want to add
 41
 42    This makes an entirely internal request.  appdata.map does not
 43    need to be updated to run this command, you can run it on an old
 44    app or an application that has not been entirely deployed.
 45
 46    This returns ``(status, header_list, body_as_str)``
 47    """
 48    os.environ['SILVER_CANONICAL_HOSTNAME'] = hostname
 49    wsgi_app = app_config.get_app_from_runner()
 50    basic_environ = {
 51        'PATH_INFO': urllib.unquote(str(path)),
 52        'SCRIPT_NAME': '',
 53        'SERVER_NAME': hostname,
 54        'SERVER_PORT': '80',
 55        'REQUEST_METHOD': 'GET',
 56        'HTTP_HOST': '%s:80' % hostname,
 57        'CONTENT_LENGTH': '0',
 58        'REMOTE_ADDR': '127.0.0.1',
 59        'SERVER_PROTOCOL': 'HTTP/1.0',
 60        'wsgi.input': StringIO(''),
 61        'wsgi.errors': sys.stderr,
 62        'wsgi.version': (1, 0),
 63        'wsgi.multithread': False,
 64        'wsgi.multiprocess': False,
 65        'wsgi.run_once': True,
 66        'wsgi.url_scheme': 'http',
 67        'silverlining.internal': True,
 68        }
 69    if body:
 70        basic_environ['wsgi.input'] = StringIO(body)
 71        basic_environ['CONTENT_LENGTH'] = len(body)
 72        basic_environ['REQUEST_METHOD'] = 'POST'
 73    if environ:
 74        basic_environ.update(environ)
 75    basic_environ['SILVER_INSTANCE_NAME'] = app_config.instance_name
 76    ## FIXME: This isn't a very good guess of the path:
 77    basic_environ['SILVER_MATCH_PATH'] = ''
 78    out = StringIO()
 79    info = []
 80
 81    def start_response(status, headers, exc_info=None):
 82        if exc_info is not None:
 83            raise exc_info[0], exc_info[1], exc_info[2]
 84        info[:] = [status, headers]
 85        if capture_stdout:
 86            return out.write
 87        else:
 88            return sys.stdout.write
 89    app_iter = wsgi_app(basic_environ, start_response)
 90    try:
 91        for item in app_iter:
 92            if capture_stdout:
 93                sys.stdout.write(item)
 94            else:
 95                out.write(item)
 96    finally:
 97        if hasattr(app_iter, 'close'):
 98            app_iter.close()
 99    status, headers = info
100    return status, headers, out.getvalue()
101
102
103def create_wsgi_app(instance_name, hostname):
104    ## FIXME: should this even exist?
105    os.environ['SITE'] = instance_name
106    fn = '/usr/local/share/silverlining/mgr-scripts/master-runner.py'
107    ns = {'__file__': fn,
108          '__name__': '__main__'}
109    execfile(fn, ns)
110    wsgi_app = ns['application']
111    return wsgi_app
112
113
114def php_internal_request(app_config, hostname, path, body=None, environ=None, capture_stdout=True):
115    assert app_config.platform == 'php'
116    env = {}
117    env['SILVER_SCRIPT_NAME'] = env['SCRIPT_NAME'] = urllib.unquote(path)
118    env['SILVER_INSTANCE_NAME'] = app_config.instance_name
119    env['SILVER_CANONICAL_HOSTNAME'] = hostname
120    ## FIXME: nice if this was more... intelligent:
121    env['SILVER_MATCH_PATH'] = '/'
122    if body:
123        env['REQUEST_METHOD'] = 'POST'
124    else:
125        env['REQUEST_METHOD'] = 'GET'
126    env.update(environ)
127    for key, value in env.items():
128        if not isinstance(value, str):
129            env[key] = str(value)
130    stdout, stderr, returncode = run(
131        ['php5', '/usr/local/share/silverlining/mgr-scripts/master-runner.php'], capture_stdout=capture_stdout,
132        extra_env=env, stdin=body)
133    return '200 OK', [], stdout