##// END OF EJS Templates
hgweb: pass strings in WSGI environment correctly from wsgicgi...
Manuel Jacob -
r51830:04bfcb41 stable
parent child Browse files
Show More
@@ -0,0 +1,18 b''
1 $ hg init test
2 $ cat >hgweb.cgi <<HGWEB
3 > #!$PYTHON
4 > from mercurial import demandimport; demandimport.enable()
5 > from mercurial.hgweb import hgweb
6 > from mercurial.hgweb import wsgicgi
7 > application = hgweb(b"test", b"Empty test repository")
8 > wsgicgi.launch(application)
9 > HGWEB
10 $ chmod 755 hgweb.cgi
11
12 Check that non-ASCII bytes roundtrip correctly.
13
14 $ . "$TESTDIR/cgienv"
15 $ PATH_INFO="/rev/$(python -c 'import sys; sys.stdout.buffer.write(b"\xe2\x80\x94")')"; export PATH_INFO
16 $ QUERY_STRING="style=raw"; export QUERY_STRING
17 $ "$PYTHON" ./hgweb.cgi | grep error
18 error: unknown revision '\xe2\x80\x94' (esc)
@@ -1,93 +1,94 b''
1 # hgweb/wsgicgi.py - CGI->WSGI translator
1 # hgweb/wsgicgi.py - CGI->WSGI translator
2 #
2 #
3 # Copyright 2006 Eric Hopper <hopper@omnifarious.org>
3 # Copyright 2006 Eric Hopper <hopper@omnifarious.org>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7 #
7 #
8 # This was originally copied from the public domain code at
8 # This was originally copied from the public domain code at
9 # http://www.python.org/dev/peps/pep-0333/#the-server-gateway-side
9 # http://www.python.org/dev/peps/pep-0333/#the-server-gateway-side
10
10
11
11
12 import os
13
14 from ..pycompat import getattr
12 from ..pycompat import getattr
15 from .. import pycompat
13 from .. import encoding, pycompat
16
14
17 from ..utils import procutil
15 from ..utils import procutil
18
16
19 from . import common
17 from . import common
20
18
21
19
22 def launch(application):
20 def launch(application):
23 procutil.setbinary(procutil.stdin)
21 procutil.setbinary(procutil.stdin)
24 procutil.setbinary(procutil.stdout)
22 procutil.setbinary(procutil.stdout)
25
23
26 environ = dict(os.environ.items()) # re-exports
24 environ = {
25 k.decode('iso8859-1'): v.decode('iso8859-1')
26 for k, v in encoding.environ.items()
27 } # re-exports
27 environ.setdefault('PATH_INFO', '')
28 environ.setdefault('PATH_INFO', '')
28 if environ.get('SERVER_SOFTWARE', '').startswith('Microsoft-IIS'):
29 if environ.get('SERVER_SOFTWARE', '').startswith('Microsoft-IIS'):
29 # IIS includes script_name in PATH_INFO
30 # IIS includes script_name in PATH_INFO
30 scriptname = environ['SCRIPT_NAME']
31 scriptname = environ['SCRIPT_NAME']
31 if environ['PATH_INFO'].startswith(scriptname):
32 if environ['PATH_INFO'].startswith(scriptname):
32 environ['PATH_INFO'] = environ['PATH_INFO'][len(scriptname) :]
33 environ['PATH_INFO'] = environ['PATH_INFO'][len(scriptname) :]
33
34
34 stdin = procutil.stdin
35 stdin = procutil.stdin
35 if environ.get('HTTP_EXPECT', '').lower() == '100-continue':
36 if environ.get('HTTP_EXPECT', '').lower() == '100-continue':
36 stdin = common.continuereader(stdin, procutil.stdout.write)
37 stdin = common.continuereader(stdin, procutil.stdout.write)
37
38
38 environ['wsgi.input'] = stdin
39 environ['wsgi.input'] = stdin
39 environ['wsgi.errors'] = procutil.stderr
40 environ['wsgi.errors'] = procutil.stderr
40 environ['wsgi.version'] = (1, 0)
41 environ['wsgi.version'] = (1, 0)
41 environ['wsgi.multithread'] = False
42 environ['wsgi.multithread'] = False
42 environ['wsgi.multiprocess'] = True
43 environ['wsgi.multiprocess'] = True
43 environ['wsgi.run_once'] = True
44 environ['wsgi.run_once'] = True
44
45
45 if environ.get('HTTPS', 'off').lower() in ('on', '1', 'yes'):
46 if environ.get('HTTPS', 'off').lower() in ('on', '1', 'yes'):
46 environ['wsgi.url_scheme'] = 'https'
47 environ['wsgi.url_scheme'] = 'https'
47 else:
48 else:
48 environ['wsgi.url_scheme'] = 'http'
49 environ['wsgi.url_scheme'] = 'http'
49
50
50 headers_set = []
51 headers_set = []
51 headers_sent = []
52 headers_sent = []
52 out = procutil.stdout
53 out = procutil.stdout
53
54
54 def write(data):
55 def write(data):
55 if not headers_set:
56 if not headers_set:
56 raise AssertionError(b"write() before start_response()")
57 raise AssertionError(b"write() before start_response()")
57
58
58 elif not headers_sent:
59 elif not headers_sent:
59 # Before the first output, send the stored headers
60 # Before the first output, send the stored headers
60 status, response_headers = headers_sent[:] = headers_set
61 status, response_headers = headers_sent[:] = headers_set
61 out.write(b'Status: %s\r\n' % pycompat.bytesurl(status))
62 out.write(b'Status: %s\r\n' % pycompat.bytesurl(status))
62 for hk, hv in response_headers:
63 for hk, hv in response_headers:
63 out.write(
64 out.write(
64 b'%s: %s\r\n'
65 b'%s: %s\r\n'
65 % (pycompat.bytesurl(hk), pycompat.bytesurl(hv))
66 % (pycompat.bytesurl(hk), pycompat.bytesurl(hv))
66 )
67 )
67 out.write(b'\r\n')
68 out.write(b'\r\n')
68
69
69 out.write(data)
70 out.write(data)
70 out.flush()
71 out.flush()
71
72
72 def start_response(status, response_headers, exc_info=None):
73 def start_response(status, response_headers, exc_info=None):
73 if exc_info:
74 if exc_info:
74 try:
75 try:
75 if headers_sent:
76 if headers_sent:
76 # Re-raise original exception if headers sent
77 # Re-raise original exception if headers sent
77 raise exc_info[0](exc_info[1], exc_info[2])
78 raise exc_info[0](exc_info[1], exc_info[2])
78 finally:
79 finally:
79 del exc_info # avoid dangling circular ref
80 del exc_info # avoid dangling circular ref
80 elif headers_set:
81 elif headers_set:
81 raise AssertionError(b"Headers already set!")
82 raise AssertionError(b"Headers already set!")
82
83
83 headers_set[:] = [status, response_headers]
84 headers_set[:] = [status, response_headers]
84 return write
85 return write
85
86
86 content = application(environ, start_response)
87 content = application(environ, start_response)
87 try:
88 try:
88 for chunk in content:
89 for chunk in content:
89 write(chunk)
90 write(chunk)
90 if not headers_sent:
91 if not headers_sent:
91 write(b'') # send headers now if body was empty
92 write(b'') # send headers now if body was empty
92 finally:
93 finally:
93 getattr(content, 'close', lambda: None)()
94 getattr(content, 'close', lambda: None)()
General Comments 0
You need to be logged in to leave comments. Login now