diff options
author | Ian Bicking <ian@ianbicking.org> | 2005-08-15 16:49:21 +0000 |
---|---|---|
committer | Ian Bicking <ian@ianbicking.org> | 2005-08-15 16:49:21 +0000 |
commit | e41dd70c39b4dfa6b0c69e0f1e6bbc34489f465d (patch) | |
tree | 46ce6255d1be8678e8aa99c0b187b2a55e62027a | |
parent | 23ba269d2c0959358f0753221b0b6ae9709a2c46 (diff) | |
download | paste-git-e41dd70c39b4dfa6b0c69e0f1e6bbc34489f465d.tar.gz |
Added CGI proxy application
-rw-r--r-- | paste/cgiapp.py | 88 | ||||
-rwxr-xr-x | paste/tests/cgiapp_data/error.cgi | 3 | ||||
-rwxr-xr-x | paste/tests/cgiapp_data/form.cgi | 12 | ||||
-rwxr-xr-x | paste/tests/cgiapp_data/ok.cgi | 6 | ||||
-rwxr-xr-x | paste/tests/cgiapp_data/stderr.cgi | 8 | ||||
-rw-r--r-- | paste/tests/test_cgiapp.py | 35 |
6 files changed, 152 insertions, 0 deletions
diff --git a/paste/cgiapp.py b/paste/cgiapp.py new file mode 100644 index 0000000..edc156a --- /dev/null +++ b/paste/cgiapp.py @@ -0,0 +1,88 @@ +""" +Application that runs a CGI script. +""" +import os +import subprocess + +__all__ = ['CGIError', 'CGIApplication'] + +class CGIError(Exception): + pass + +class CGIApplication(object): + + """ + This object acts as a proxy to a CGI application. You pass in the + script path (``script``), an optional path to search for the + script (if the name isn't absolute) (``path``). If you don't give + a path, then ``$PATH`` will be used. + """ + + def __init__(self, script, path=None, + include_os_environ=True): + self.script_filename = script + if isinstance(path, (str, unicode)): + path = [path] + if path is None: + path = os.environ.get('PATH', '').split(':') + self.path = path + if os.path.abspath(script) != script: + # relative path + for path_dir in self.path: + if os.path.exists(os.path.join(path_dir, script)): + self.script = os.path.join(path_dir, script) + break + else: + raise CGIError( + "Script %r not found in path %r" + % (script, self.path)) + else: + self.script = script + self.include_os_environ = include_os_environ + + def __call__(self, environ, start_response): + if self.include_os_environ: + cgi_environ = os.environ.copy() + else: + cgi_environ = {} + for name in environ: + # Should unicode values be encoded? + if (name.upper() == name + and isinstance(environ[name], str)): + cgi_environ[name] = environ[name] + # Default status in CGI: + status = '200 OK' + headers = [] + proc = subprocess.Popen( + [self.script], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + env=cgi_environ, + cwd=os.path.dirname(self.script), + ) + proc.stdin.write(environ['wsgi.input'].read()) + stdout = proc.stdout + while 1: + line = stdout.readline() + line = line.rstrip('\n').rstrip('\r') + if not line: + break + if ':' not in line: + raise CGIError( + "Bad header line: %r" % line) + name, value = line.split(':', 1) + value = value.lstrip() + name = name.strip() + if name.lower() == 'status': + status = value + else: + headers.append((name, value)) + writer = start_response(status, headers) + while 1: + data = stdout.read(4096) + if not data: + break + writer(data) + environ['wsgi.errors'].write(proc.stderr.read()) + return [] diff --git a/paste/tests/cgiapp_data/error.cgi b/paste/tests/cgiapp_data/error.cgi new file mode 100755 index 0000000..5afc9c9 --- /dev/null +++ b/paste/tests/cgiapp_data/error.cgi @@ -0,0 +1,3 @@ +#!/usr/bin/env python + +print 'hey you!' diff --git a/paste/tests/cgiapp_data/form.cgi b/paste/tests/cgiapp_data/form.cgi new file mode 100755 index 0000000..6d2e038 --- /dev/null +++ b/paste/tests/cgiapp_data/form.cgi @@ -0,0 +1,12 @@ +#!/usr/bin/env python + +import cgi + +print 'Content-type: text/plain' +print + +form = cgi.FieldStorage() + +print 'Filename:', form['up'].filename +print 'Name:', form['name'].value +print 'Content:', form['up'].file.read() diff --git a/paste/tests/cgiapp_data/ok.cgi b/paste/tests/cgiapp_data/ok.cgi new file mode 100755 index 0000000..8b8eb29 --- /dev/null +++ b/paste/tests/cgiapp_data/ok.cgi @@ -0,0 +1,6 @@ +#!/usr/bin/env python + +print 'Content-type: text/html; charset=UTF-8' +print 'Status: 200 Okay' +print +print 'This is the body' diff --git a/paste/tests/cgiapp_data/stderr.cgi b/paste/tests/cgiapp_data/stderr.cgi new file mode 100755 index 0000000..89dae0a --- /dev/null +++ b/paste/tests/cgiapp_data/stderr.cgi @@ -0,0 +1,8 @@ +#!/usr/bin/env python + +import sys +print 'Status: 500 Server Error' +print 'Content-type: text/html' +print +print 'There was an error' +print >> sys.stderr, 'some data on the error' diff --git a/paste/tests/test_cgiapp.py b/paste/tests/test_cgiapp.py new file mode 100644 index 0000000..133cd87 --- /dev/null +++ b/paste/tests/test_cgiapp.py @@ -0,0 +1,35 @@ +import os +import py.test +from paste.cgiapp import CGIApplication, CGIError +from fixture import * +del setup_module + +data_dir = os.path.join(os.path.dirname(__file__), 'cgiapp_data') + + +def test_ok(): + app = TestApp(CGIApplication('ok.cgi', [data_dir])) + res = app.get('') + assert res.header('content-type') == 'text/html; charset=UTF-8' + assert res.full_status == '200 Okay' + assert 'This is the body' in res + +def test_form(): + app = TestApp(CGIApplication('form.cgi', [data_dir])) + res = app.post('', params={'name': 'joe'}, + upload_files=[('up', 'file.txt', 'x'*10000)]) + assert 'file.txt' in res + assert 'joe' in res + assert 'x'*10000 in res + +def test_error(): + app = TestApp(CGIApplication('error.cgi', [data_dir])) + py.test.raises(CGIError, "app.get('', status=500)") + +def test_stderr(): + app = TestApp(CGIApplication('stderr.cgi', [data_dir])) + res = app.get('', expect_errors=True) + assert res.status == 500 + assert 'error' in res + assert 'some data' in res.errors + |