Skip to content

Commit a3d607a

Browse files
Merge branch 'release/4.3.1'
2 parents 1242f83 + 0256029 commit a3d607a

File tree

10 files changed

+395
-17
lines changed

10 files changed

+395
-17
lines changed

Makefile.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
APXS = @APXS@
1616
PYTHON = @PYTHON@
1717

18-
DESTDIR =
18+
DESTDIR = @DESTDIR@
1919
LIBEXECDIR = @LIBEXECDIR@
2020

2121
CPPFLAGS = @CPPFLAGS@

configure

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,7 @@ ac_unique_file="src/server/mod_wsgi.c"
585585
ac_subst_vars='LTLIBOBJS
586586
LIBOBJS
587587
LIBEXECDIR
588+
DESTDIR
588589
LDLIBS
589590
PYTHON
590591
OBJEXT
@@ -1932,15 +1933,24 @@ fi
19321933
19331934
XCODE_PREFIX="/Applications/Xcode.app/Contents/Developer/Toolchains/"
19341935
XCODE_CC="${XCODE_PREFIX}XcodeDefault.xctoolchain/usr/bin/cc"
1936+
XCODE_BIN_PATTERN="${XCODE_PREFIX}.*/usr/bin/"
19351937
19361938
if test -x "${APXS}"; then
19371939
APXS_CC=`${APXS} -q CC`
19381940
APXS_LIBTOOL=`${APXS} -q LIBTOOL | sed -e "s/ .*$//"`
19391941
if [[ ${APXS_CC} = ${XCODE_PREFIX}* ]]; then
1940-
cat "${APXS_LIBTOOL}" | sed -e \
1941-
"s/OSX10.[89].xctoolchain/XcodeDefault.xctoolchain/" > ./libtool
1942-
cat "${APXS}" | sed -e "s%get_vars(\"CC\")%\"${XCODE_CC}\"%" \
1943-
-e 's%^my $libtool = .*;%my $libtool = \"./libtool\";%' > ./apxs
1942+
if test ! -x ${XCODE_CC}; then
1943+
cat "${APXS_LIBTOOL}" | sed -e \
1944+
"s%${XCODE_BIN_PATTERN}%/usr/bin/%" > ./libtool
1945+
cat "${APXS}" | sed -e "s%get_vars(\"CC\")%\"/usr/bin/cc\"%" \
1946+
-e 's%^my $libtool = .*;%my $libtool = \"./libtool\";%' > ./apxs
1947+
else
1948+
cat "${APXS_LIBTOOL}" | sed -e \
1949+
"s%OSX10.[0-9][0-9]*.xctoolchain%XcodeDefault.xctoolchain%" > ./libtool
1950+
cat "${APXS}" | sed -e "s%get_vars(\"CC\")%\"${XCODE_CC}\"%" \
1951+
-e 's%^my $libtool = .*;%my $libtool = \"./libtool\";%' > ./apxs
1952+
fi
1953+
19441954
chmod +x ./apxs ./libtool
19451955
APXS=./apxs
19461956
fi
@@ -2950,6 +2960,7 @@ LDLIBS="${LDLIBS} ${LDLIBS1} ${LDLIBS2} ${LDLIBS3}"
29502960
29512961
29522962
2963+
29532964
LIBEXECDIR="`${APXS} -q LIBEXECDIR`"
29542965
29552966

configure.ac

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,24 @@ fi
3939

4040
XCODE_PREFIX="/Applications/Xcode.app/Contents/Developer/Toolchains/"
4141
XCODE_CC="${XCODE_PREFIX}XcodeDefault.xctoolchain/usr/bin/cc"
42+
XCODE_BIN_PATTERN="${XCODE_PREFIX}.*/usr/bin/"
4243

4344
if test -x "${APXS}"; then
4445
APXS_CC=`${APXS} -q CC`
4546
APXS_LIBTOOL=`${APXS} -q LIBTOOL | sed -e "s/ .*$//"`
4647
if [[[ ${APXS_CC} = ${XCODE_PREFIX}* ]]]; then
47-
cat "${APXS_LIBTOOL}" | sed -e \
48-
"s/OSX10.[[89]].xctoolchain/XcodeDefault.xctoolchain/" > ./libtool
49-
cat "${APXS}" | sed -e "s%get_vars(\"CC\")%\"${XCODE_CC}\"%" \
50-
-e 's%^my $libtool = .*;%my $libtool = \"./libtool\";%' > ./apxs
48+
if test ! -x ${XCODE_CC}; then
49+
cat "${APXS_LIBTOOL}" | sed -e \
50+
"s%${XCODE_BIN_PATTERN}%/usr/bin/%" > ./libtool
51+
cat "${APXS}" | sed -e "s%get_vars(\"CC\")%\"/usr/bin/cc\"%" \
52+
-e 's%^my $libtool = .*;%my $libtool = \"./libtool\";%' > ./apxs
53+
else
54+
cat "${APXS_LIBTOOL}" | sed -e \
55+
"s%OSX10.[[0-9]][[0-9]]*.xctoolchain%XcodeDefault.xctoolchain%" > ./libtool
56+
cat "${APXS}" | sed -e "s%get_vars(\"CC\")%\"${XCODE_CC}\"%" \
57+
-e 's%^my $libtool = .*;%my $libtool = \"./libtool\";%' > ./apxs
58+
fi
59+
5160
chmod +x ./apxs ./libtool
5261
APXS=./apxs
5362
fi
@@ -206,6 +215,7 @@ LDLIBS="${LDLIBS} ${LDLIBS1} ${LDLIBS2} ${LDLIBS3}"
206215
AC_SUBST(CFLAGS)
207216
AC_SUBST(LDFLAGS)
208217
AC_SUBST(LDLIBS)
218+
AC_SUBST(DESTDIR)
209219

210220
LIBEXECDIR="`${APXS} -q LIBEXECDIR`"
211221
AC_SUBST(LIBEXECDIR)

docs/release-notes/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Release Notes
55
.. toctree::
66
:maxdepth: 2
77

8+
version-4.3.1.rst
89
version-4.3.0.rst
910

1011
version-4.2.8.rst

docs/release-notes/version-4.2.8.rst

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,21 @@ This needs to be inforced as Apache Runtime library has a definition in
2626
header files which changes sizes from 10.7 to 10.8 and trying to compile
2727
for compatability back to 10.6 as Python 3.4 tries to enforce, will cause
2828
mod_wsgi daemon mode processes to crash at runtime.
29+
30+
3. Python 3.3+ pyvenv style virtual environments would not work with
31+
mod_wsgi via the ``WSGIPythonHome`` directive or the ``home`` option to the
32+
``WSGIDaemonProcess`` directive. This is because the support in Python for
33+
pyvenv will not work with embedded systems which set the equivalent of
34+
``PYTHONHOME`` via the Python C API.
35+
36+
The underlying problem in Python is described in issue:
37+
38+
* http://bugs.python.org/issue22213
39+
40+
of the Python issue tracer.
41+
42+
To support both normal virtualenv style virtual environments and pyvenv
43+
style virtual environments, the manner in which virtual environments are
44+
setup by mod_wsgi has been changed. This has at this point only been done
45+
on UNIX systems however, as it isn't known at this point whether the same
46+
trick will work on Windows systems.

docs/release-notes/version-4.3.1.rst

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
=============
2+
Version 4.3.1
3+
=============
4+
5+
Version 4.3.1 of mod_wsgi can be obtained from:
6+
7+
https://github.com/GrahamDumpleton/mod_wsgi/archive/4.3.1.tar.gz
8+
9+
Known Issues
10+
------------
11+
12+
1. The makefiles for building mod_wsgi on Windows are currently broken and
13+
need updating. As most new changes relate to mod_wsgi daemon mode, which is
14+
not supported under Windows, you should keep using the last available
15+
binary for version 3.X on Windows instead.
16+
17+
Bugs Fixed
18+
----------
19+
20+
1. The ``install-module`` sub command of ``mod_wsgi-express`` was incorrectly
21+
trying to install the mod_wsgi ``.so`` file onto itself rather than into
22+
the Apache modules directory.
23+
24+
2. The workaround for the broken MacOS X Apache build scripts as implemented
25+
by the ``configure`` script used when building using the traditional make
26+
command wasn't working correctly for MacOS X 10.10 (Yosemite).
27+
28+
In fixing this issue, the ``configure`` script has been enhanced such that
29+
it is now no longer to have the whole of the Xcode package installed on
30+
MacOS X. Instead the minimum required now is the developer command line
31+
tools. If using Python and you wanted to be able to install Python packages
32+
which has a source code component you would have already likely installed
33+
the developer command line tools.
34+
35+
New Features
36+
------------
37+
38+
1. Added the ``--add-handler`` option to ``mod_wsgi-express`` to allow a
39+
WSGI application script file to be provided which is to handle any requests
40+
against static resources in the document root directory matching a specific
41+
extension type.
42+
43+
2. Added a mechanism to limit the amount of response content that can
44+
buffered in the Apache child worker processes when proxying back the response
45+
from a request which had been handled in a mod_wsgi daemon process.
46+
47+
This is to combat a lack of flow control within Apache 2.2 which can cause
48+
excessive amounts of memory usage as a result of such buffered content.
49+
This issue in Apache 2.2 was fixed in Apache 2.4, but the new mechanism is
50+
applied to both versions for consistency.
51+
52+
The default maximum on the amount of buffered content is 65536 bytes. This
53+
can be increased by using the ``proxy-buffer-size`` option to the
54+
``WSGIDaemonProcess`` directive or the ``--proxy-buffer-size`` option to
55+
``mod_wsgi-express``. If using Apache 2.4, its own flow control mechanism
56+
may override the value in increasing the buffer size.

src/server/__init__.py

Lines changed: 99 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import imp
1313
import pwd
1414
import grp
15+
import re
1516

1617
try:
1718
import Queue as queue
@@ -243,6 +244,7 @@ def find_mimetypes():
243244
send-buffer-size=%(send_buffer_size)s \\
244245
receive-buffer-size=%(receive_buffer_size)s \\
245246
header-buffer-size=%(header_buffer_size)s \\
247+
proxy-buffer-size=%(proxy_buffer_size)s \\
246248
server-metrics=%(daemon_server_metrics_flag)s
247249
</IfDefine>
248250
<IfDefine !WSGI_MULTIPROCESS>
@@ -265,7 +267,7 @@ def find_mimetypes():
265267
shutdown-timeout=%(shutdown_timeout)s \\
266268
send-buffer-size=%(send_buffer_size)s \\
267269
receive-buffer-size=%(receive_buffer_size)s \\
268-
header-buffer-size=%(header_buffer_size)s \\
270+
proxy-buffer-size=%(proxy_buffer_size)s \\
269271
server-metrics=%(daemon_server_metrics_flag)s
270272
</IfDefine>
271273
</IfDefine>
@@ -618,6 +620,15 @@ def find_mimetypes():
618620
PassEnv '%(name)s'
619621
"""
620622

623+
APACHE_HANDLERS_CONFIG = """
624+
WSGIHandlerScript wsgi-resource '%(server_root)s/resource.wsgi' \\
625+
process-group='%(host)s:%(port)s' application-group=%%{GLOBAL}
626+
"""
627+
628+
APACHE_EXTENSION_CONFIG = """
629+
AddHandler wsgi-resource %(extension)s
630+
"""
631+
621632
APACHE_INCLUDE_CONFIG = """
622633
Include '%(filename)s'
623634
"""
@@ -677,6 +688,13 @@ def generate_apache_config(options):
677688
for name in options['passenv_variables']:
678689
print(APACHE_PASSENV_CONFIG % dict(name=name), file=fp)
679690

691+
if options['handler_scripts']:
692+
print(APACHE_HANDLERS_CONFIG % options, file=fp)
693+
694+
for extension, script in options['handler_scripts']:
695+
print(APACHE_EXTENSION_CONFIG % dict(extension=extension),
696+
file=fp)
697+
680698
if options['include_files']:
681699
for filename in options['include_files']:
682700
filename = os.path.abspath(filename)
@@ -902,6 +920,48 @@ def handle_request(self, environ, start_response):
902920
def __call__(self, environ, start_response):
903921
return self.handle_request(environ, start_response)
904922

923+
class ResourceHandler(object):
924+
925+
def __init__(self, resources):
926+
self.resources = {}
927+
928+
for extension, script in resources:
929+
extension_name = re.sub('[^\w]{1}', '_', extension)
930+
module_name = '__wsgi_resource%s__' % extension_name
931+
module = imp.new_module(module_name)
932+
module.__file__ = script
933+
934+
with open(script, 'r') as fp:
935+
code = compile(fp.read(), script, 'exec',
936+
dont_inherit=True)
937+
exec(code, module.__dict__)
938+
939+
sys.modules[module_name] = module
940+
self.resources[extension] = module
941+
942+
def resource_extension(self, resource):
943+
return os.path.splitext(resource)[-1]
944+
945+
def reload_required(self, resource):
946+
extension = self.resource_extension(resource)
947+
function = getattr(self.resources[extension], 'reload_required', None)
948+
if function is not None:
949+
return function(environ)
950+
return False
951+
952+
def handle_request(self, environ, start_response):
953+
resource = environ['SCRIPT_NAME']
954+
extension = self.resource_extension(resource)
955+
module = self.resources[extension]
956+
function = getattr(module, 'handle_request', None)
957+
if function is not None:
958+
return function(environ, start_response)
959+
function = getattr(module, 'application')
960+
return function(environ, start_response)
961+
962+
def __call__(self, environ, start_response):
963+
return self.handle_request(environ, start_response)
964+
905965
WSGI_HANDLER_SCRIPT = """
906966
import mod_wsgi.server
907967
@@ -926,6 +986,17 @@ def __call__(self, environ, start_response):
926986
mod_wsgi.server.start_reloader()
927987
"""
928988

989+
WSGI_RESOURCE_SCRIPT = """
990+
import mod_wsgi.server
991+
992+
resources = %(resources)s
993+
994+
handler = mod_wsgi.server.ResourceHandler(resources)
995+
996+
reload_required = handler.reload_required
997+
handle_request = handler.handle_request
998+
"""
999+
9291000
WSGI_DEFAULT_SCRIPT = """
9301001
CONTENT = b'''
9311002
<html>
@@ -975,6 +1046,11 @@ def generate_wsgi_handler_script(options):
9751046
with open(path, 'w') as fp:
9761047
print(WSGI_HANDLER_SCRIPT % options, file=fp)
9771048

1049+
path = os.path.join(options['server_root'], 'resource.wsgi')
1050+
with open(path, 'w') as fp:
1051+
print(WSGI_RESOURCE_SCRIPT % dict(resources=repr(
1052+
options['handler_scripts'])), file=fp)
1053+
9781054
path = os.path.join(options['server_root'], 'default.wsgi')
9791055
with open(path, 'w') as fp:
9801056
print(WSGI_DEFAULT_SCRIPT % options, file=fp)
@@ -1275,6 +1351,12 @@ def check_percentage(option, opt_str, value, parser):
12751351
metavar='NUMBER', help='Size of buffer used for reading '
12761352
'response headers from daemon processes. Defaults to 0, '
12771353
'indicating internal default of 32768 bytes is used.'),
1354+
optparse.make_option('--proxy-buffer-size', type='int', default=0,
1355+
metavar='NUMBER', help='Maximum amount of response content '
1356+
'that will be allowed to be buffered in the Apache child '
1357+
'worker process when proxying the response from a daemon '
1358+
'process. Defaults to 0, indicating internal default of '
1359+
'65536 bytes is used.'),
12781360

12791361
optparse.make_option('--reload-on-changes', action='store_true',
12801362
default=False, help='Flag indicating whether worker processes '
@@ -1362,7 +1444,7 @@ def check_percentage(option, opt_str, value, parser):
13621444
default=None, help='Specify a Python script file for '
13631445
'performing group based authorization in conjunction with '
13641446
'a user authentication script.'),
1365-
optparse.make_option('--auth-group', metavar='SCRIPT-PATH',
1447+
optparse.make_option('--auth-group', metavar='NAME',
13661448
default='wsgi', help='Specify the group which users should '
13671449
'be a member of when using a group based authorization script. '
13681450
'Defaults to \'wsgi\' as a place holder but should be '
@@ -1450,6 +1532,12 @@ def check_percentage(option, opt_str, value, parser):
14501532
metavar='FILE-PATH', help='Override the path to the mime types '
14511533
'file used by the web server.'),
14521534

1535+
optparse.make_option('--add-handler', action='append', nargs=2,
1536+
dest='handler_scripts', metavar='EXTENSION SCRIPT-PATH',
1537+
help='Specify a WSGI application to be used as a special '
1538+
'handler for any resources matched from the document root '
1539+
'directory with a specific extension type.'),
1540+
14531541
optparse.make_option('--with-newrelic', action='store_true',
14541542
default=False, help='Flag indicating whether all New Relic '
14551543
'performance monitoring features should be enabled.'),
@@ -1644,6 +1732,14 @@ def _cmd_setup_server(command, args, options):
16441732
else:
16451733
options['daemon_server_metrics_flag'] = 'Off'
16461734

1735+
if options['handler_scripts']:
1736+
handler_scripts = []
1737+
for extension, script in options['handler_scripts']:
1738+
if not os.path.isabs(script):
1739+
script = os.path.abspath(script)
1740+
handler_scripts.append((extension, script))
1741+
options['handler_scripts'] = handler_scripts
1742+
16471743
if options['with_newrelic']:
16481744
options['with_newrelic_agent'] = True
16491745
options['with_newrelic_platform'] = True
@@ -1902,7 +1998,7 @@ def cmd_install_module(params):
19021998
parser.error('Incorrect number of arguments.')
19031999

19042000
target = os.path.abspath(os.path.join(options.modules_directory,
1905-
MOD_WSGI_SO))
2001+
os.path.basename(MOD_WSGI_SO)))
19062002

19072003
shutil.copyfile(where(), target)
19082004

0 commit comments

Comments
 (0)