Compare commits
No commits in common. "c8-stream-2.4" and "a9" have entirely different histories.
c8-stream-
...
a9
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,2 +1,2 @@
|
||||
SOURCES/apache-poweredby.png
|
||||
SOURCES/httpd-2.4.37.tar.bz2
|
||||
SOURCES/httpd-2.4.57.tar.bz2
|
||||
|
@ -1,2 +1,2 @@
|
||||
3a7449d6cff00e5ccb3ed8571f34c0528555d38f SOURCES/apache-poweredby.png
|
||||
4a38471de821288b0300148016f2b03dfee8adf2 SOURCES/httpd-2.4.37.tar.bz2
|
||||
01044512374941fad939ec4b1537428cc7edc769 SOURCES/httpd-2.4.57.tar.bz2
|
||||
|
@ -23,7 +23,6 @@ LoadModule authz_host_module modules/mod_authz_host.so
|
||||
LoadModule authz_owner_module modules/mod_authz_owner.so
|
||||
LoadModule authz_user_module modules/mod_authz_user.so
|
||||
LoadModule autoindex_module modules/mod_autoindex.so
|
||||
LoadModule brotli_module modules/mod_brotli.so
|
||||
LoadModule cache_module modules/mod_cache.so
|
||||
LoadModule cache_disk_module modules/mod_cache_disk.so
|
||||
LoadModule cache_socache_module modules/mod_cache_socache.so
|
||||
@ -55,6 +54,7 @@ LoadModule slotmem_plain_module modules/mod_slotmem_plain.so
|
||||
LoadModule slotmem_shm_module modules/mod_slotmem_shm.so
|
||||
LoadModule socache_dbm_module modules/mod_socache_dbm.so
|
||||
LoadModule socache_memcache_module modules/mod_socache_memcache.so
|
||||
LoadModule socache_redis_module modules/mod_socache_redis.so
|
||||
LoadModule socache_shmcb_module modules/mod_socache_shmcb.so
|
||||
LoadModule status_module modules/mod_status.so
|
||||
LoadModule substitute_module modules/mod_substitute.so
|
||||
|
1
SOURCES/00-brotli.conf
Normal file
1
SOURCES/00-brotli.conf
Normal file
@ -0,0 +1 @@
|
||||
LoadModule brotli_module modules/mod_brotli.so
|
@ -4,6 +4,7 @@
|
||||
#
|
||||
|
||||
#LoadModule asis_module modules/mod_asis.so
|
||||
#LoadModule authnz_fcgi_module modules/mod_authnz_fcgi.so
|
||||
#LoadModule buffer_module modules/mod_buffer.so
|
||||
#LoadModule heartbeat_module modules/mod_heartbeat.so
|
||||
#LoadModule heartmonitor_module modules/mod_heartmonitor.so
|
||||
|
@ -2,10 +2,7 @@
|
||||
# which has been configured in 00-mpm.conf. mod_cgid should be used
|
||||
# with a threaded MPM; mod_cgi with the prefork MPM.
|
||||
|
||||
<IfModule mpm_worker_module>
|
||||
LoadModule cgid_module modules/mod_cgid.so
|
||||
</IfModule>
|
||||
<IfModule mpm_event_module>
|
||||
<IfModule !mpm_prefork_module>
|
||||
LoadModule cgid_module modules/mod_cgid.so
|
||||
</IfModule>
|
||||
<IfModule mpm_prefork_module>
|
||||
|
8818
SOURCES/KEYS
Normal file
8818
SOURCES/KEYS
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,2 +1,2 @@
|
||||
#!/bin/sh
|
||||
exec /sbin/apachectl configtest "$@"
|
||||
exec /usr/sbin/httpd -t
|
||||
|
@ -1,2 +1,2 @@
|
||||
#!/bin/sh
|
||||
exec /sbin/apachectl graceful "$@"
|
||||
exec /sbin/apachectl graceful
|
||||
|
74
SOURCES/apachectl.sh
Executable file
74
SOURCES/apachectl.sh
Executable file
@ -0,0 +1,74 @@
|
||||
#!/usr/bin/sh
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
###
|
||||
### NOTE: This is a replacement version of the "apachectl" script with
|
||||
### some differences in behaviour to the version distributed with
|
||||
### Apache httpd. Please read the apachectl(8) man page for more
|
||||
### information.
|
||||
###
|
||||
|
||||
if [ "x$1" = "x-k" ]; then
|
||||
shift
|
||||
fi
|
||||
|
||||
ACMD="$1"
|
||||
ARGV="$@"
|
||||
SVC='httpd.service'
|
||||
HTTPD='@HTTPDBIN@'
|
||||
|
||||
if [ "x$2" != "x" ] ; then
|
||||
echo Passing arguments to httpd using apachectl is no longer supported.
|
||||
echo You can only start/stop/restart httpd using this script.
|
||||
echo To pass extra arguments to httpd, see the $SVC'(8)'
|
||||
echo man page.
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case $ACMD in
|
||||
start|stop|restart|status)
|
||||
/usr/bin/systemctl --no-pager $ACMD $SVC
|
||||
ERROR=$?
|
||||
;;
|
||||
graceful)
|
||||
if /usr/bin/systemctl -q is-active $SVC; then
|
||||
/usr/bin/systemctl kill --signal=SIGUSR1 --kill-who=main $SVC
|
||||
else
|
||||
/usr/bin/systemctl start $SVC
|
||||
fi
|
||||
ERROR=$?
|
||||
;;
|
||||
graceful-stop)
|
||||
/usr/bin/systemctl kill --signal=SIGWINCH --kill-who=main $SVC
|
||||
ERROR=$?
|
||||
;;
|
||||
configtest|-t)
|
||||
$HTTPD -t
|
||||
ERROR=$?
|
||||
;;
|
||||
-v|-V)
|
||||
$HTTPD $ACMD
|
||||
ERROR=$?
|
||||
;;
|
||||
*)
|
||||
echo apachectl: The \"$ACMD\" option is not supported. 1>&2
|
||||
ERROR=2
|
||||
;;
|
||||
esac
|
||||
|
||||
exit $ERROR
|
||||
|
191
SOURCES/apachectl.xml
Normal file
191
SOURCES/apachectl.xml
Normal file
@ -0,0 +1,191 @@
|
||||
<?xml version='1.0' encoding='UTF-8' ?>
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">[
|
||||
|
||||
]>
|
||||
<!--
|
||||
Copyright 2020 Red Hat, Inc.
|
||||
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<refentry>
|
||||
<refentryinfo>
|
||||
<title>apachectl</title>
|
||||
<productname>httpd</productname>
|
||||
<author><contrib>Apache man page</contrib><othername>Apache Software Foundation contributors</othername></author>
|
||||
<author><contrib>Fedora man page</contrib><surname>Dana</surname><firstname>Frank</firstname></author>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>apachectl</refentrytitle>
|
||||
<manvolnum>8</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>apachectl</refname>
|
||||
<refpurpose>Server control interface for httpd</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv id='synopsis'>
|
||||
<cmdsynopsis>
|
||||
<command>apachectl</command>
|
||||
<arg choice='opt'><replaceable>command</replaceable> </arg>
|
||||
<sbr/>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<!-- body begins here -->
|
||||
<refsect1 id='description'>
|
||||
<title>Description</title>
|
||||
|
||||
<para><command>apachectl</command> is a front end to the Apache HyperText
|
||||
Transfer Protocol (HTTP) server. It is designed to help the
|
||||
administrator control the functioning of the Apache
|
||||
<command>httpd</command> daemon.</para>
|
||||
|
||||
<para>The <command>apachectl</command> script takes one-word arguments like
|
||||
<option>start</option>,
|
||||
<option>restart</option>, and
|
||||
<option>stop</option>, and translates them
|
||||
into appropriate signals to <command>httpd</command>.</para>
|
||||
|
||||
<para>The <command>apachectl</command> script returns a 0 exit value on
|
||||
success, and >0 if an error occurs.</para>
|
||||
|
||||
<refsect2 id="compatibility">
|
||||
<title>Compatibility</title>
|
||||
|
||||
<para>The version of <command>apachectl</command> used on this
|
||||
system is a replacement script intended to be mostly (but not
|
||||
completely) compatible with version provided with
|
||||
<emphasis>Apache httpd</emphasis>. This
|
||||
<command>apachectl</command> mostly acts as a wrapper around
|
||||
<command>systemctl</command> and manipulates the
|
||||
<command>systemd</command> service for <command>httpd</command>.
|
||||
The interface to the <emphasis>Apache</emphasis> version of
|
||||
<command>apachectl</command> is described at <ulink
|
||||
url="https://httpd.apache.org/docs/2.4/programs/apachectl.html"/>.</para>
|
||||
|
||||
<para>The following differences are present in the version of
|
||||
<command>apachectl</command> present on this system:
|
||||
|
||||
<itemizedlist>
|
||||
<listitem><para>Option arguments passed when starting
|
||||
<command>httpd</command> are not allowed. These should be
|
||||
configured in the systemd service directly (see <citerefentry><refentrytitle>httpd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>).</para></listitem>
|
||||
|
||||
<listitem><para>The <command>"fullstatus"</command> option is
|
||||
not available.</para></listitem>
|
||||
|
||||
<listitem><para>The <command>"status"</command> option does
|
||||
not use or rely on the running server's
|
||||
<emphasis>server-status</emphasis> output.</para></listitem>
|
||||
</itemizedlist>
|
||||
|
||||
</para>
|
||||
</refsect2>
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id='options'>
|
||||
<title>Options</title>
|
||||
<variablelist remap='TP'>
|
||||
<varlistentry>
|
||||
<term><option>start</option></term>
|
||||
<listitem>
|
||||
<para>Start the Apache <command>httpd</command> daemon. Gives an error if it
|
||||
is already running. This is equivalent to <command>systemctl start httpd.service</command>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>stop</option></term>
|
||||
<listitem>
|
||||
<para>Stops the Apache <command>httpd</command> daemon. This is equivalent to
|
||||
<command>systemctl stop httpd.service</command>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>restart</option></term>
|
||||
<listitem>
|
||||
<para>Restarts the Apache <command>httpd</command> daemon. If the daemon is
|
||||
not running, it is started. This is equivalent
|
||||
to <command>systemctl restart httpd.service</command>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>status</option></term>
|
||||
<listitem>
|
||||
<para>Displays a brief status report. This is equivalent to <command>systemctl status httpd.service.</command></para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>graceful</option></term>
|
||||
<listitem>
|
||||
<para>Gracefully restarts the Apache <command>httpd</command> daemon. If the
|
||||
daemon is not running, it is started. This differs from a normal
|
||||
restart in that currently open connections are not aborted. A side
|
||||
effect is that old log files will not be closed immediately. This
|
||||
means that if used in a log rotation script, a substantial delay may
|
||||
be necessary to ensure that the old log files are closed before
|
||||
processing them. This is equivalent to
|
||||
<command>systemctl kill --signal=SIGUSR1 --kill-who=main httpd.service</command>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>graceful-stop</option></term>
|
||||
<listitem>
|
||||
<para>Gracefully stops the Apache <command>httpd</command> daemon.
|
||||
This differs from a normal stop in that currently open connections are not
|
||||
aborted. A side effect is that old log files will not be closed immediately.
|
||||
This is equivalent to
|
||||
<command>systemctl kill --signal=SIGWINCH --kill-who=main httpd.service</command>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>configtest</option></term>
|
||||
<listitem>
|
||||
<para>Run a configuration file syntax test. It parses the configuration
|
||||
files and either reports <literal>Syntax OK</literal>
|
||||
or detailed information about the particular syntax error. This is
|
||||
equivalent to <command>httpd -t</command>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id='bugs'>
|
||||
<title>Bugs</title>
|
||||
<para>Please report bugs by filing an issue in Bugzilla via <ulink url='https://bugzilla.redhat.com/'/>.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See also</title>
|
||||
|
||||
<para>
|
||||
<citerefentry><refentrytitle>httpd</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>httpd.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>httpd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
@ -1,29 +0,0 @@
|
||||
|
||||
- Fix config for /icons/ dir to allow symlink to poweredby.png
|
||||
- Avoid using coredump GIF for a directory called "core"
|
||||
|
||||
Upstream-Status: vendor specific patch
|
||||
|
||||
diff --git a/docs/conf/extra/httpd-autoindex.conf.in b/docs/conf/extra/httpd-autoindex.conf.in
|
||||
index 51b02ed..dd6f2c6 100644
|
||||
--- a/docs/conf/extra/httpd-autoindex.conf.in
|
||||
+++ b/docs/conf/extra/httpd-autoindex.conf.in
|
||||
@@ -21,7 +21,7 @@ IndexOptions FancyIndexing HTMLTable VersionSort
|
||||
Alias /icons/ "@exp_iconsdir@/"
|
||||
|
||||
<Directory "@exp_iconsdir@">
|
||||
- Options Indexes MultiViews
|
||||
+ Options Indexes MultiViews FollowSymlinks
|
||||
AllowOverride None
|
||||
Require all granted
|
||||
</Directory>
|
||||
@@ -53,7 +53,8 @@ AddIcon /icons/dvi.gif .dvi
|
||||
AddIcon /icons/uuencoded.gif .uu
|
||||
AddIcon /icons/script.gif .conf .sh .shar .csh .ksh .tcl
|
||||
AddIcon /icons/tex.gif .tex
|
||||
-AddIcon /icons/bomb.gif core
|
||||
+AddIcon /icons/bomb.gif /core
|
||||
+AddIcon /icons/bomb.gif */core.*
|
||||
|
||||
AddIcon /icons/back.gif ..
|
||||
AddIcon /icons/hand.right.gif README
|
@ -1,16 +0,0 @@
|
||||
diff --git a/modules/aaa/mod_access_compat.c b/modules/aaa/mod_access_compat.c
|
||||
index 3023803..2edf440 100644
|
||||
--- a/modules/aaa/mod_access_compat.c
|
||||
+++ b/modules/aaa/mod_access_compat.c
|
||||
@@ -152,6 +152,11 @@ static const char *allow_cmd(cmd_parms *cmd, void *dv, const char *from,
|
||||
if (strcasecmp(from, "from"))
|
||||
return "allow and deny must be followed by 'from'";
|
||||
|
||||
+ s = ap_strchr(where, '#');
|
||||
+ if (s) {
|
||||
+ *s = '\0';
|
||||
+ }
|
||||
+
|
||||
a = (allowdeny *) apr_array_push(cmd->info ? d->allows : d->denys);
|
||||
a->x.from = where;
|
||||
a->limited = cmd->limited;
|
@ -1,22 +0,0 @@
|
||||
|
||||
There is no need to "suck in" the apr/apr-util symbols when using
|
||||
a shared libapr{,util}, it just bloats the symbol table; so don't.
|
||||
|
||||
Upstream-HEAD: needed
|
||||
Upstream-2.0: omit
|
||||
Upstream-Status: EXPORT_DIRS change is conditional on using shared apr
|
||||
|
||||
diff --git a/server/Makefile.in b/server/Makefile.in
|
||||
index 1fa3344..f635d76 100644
|
||||
--- a/server/Makefile.in
|
||||
+++ b/server/Makefile.in
|
||||
@@ -60,9 +60,6 @@ export_files:
|
||||
ls $$dir/*.h ; \
|
||||
done; \
|
||||
echo "$(top_srcdir)/server/mpm_fdqueue.h"; \
|
||||
- for dir in $(EXPORT_DIRS_APR); do \
|
||||
- ls $$dir/ap[ru].h $$dir/ap[ru]_*.h 2>/dev/null; \
|
||||
- done; \
|
||||
) | sed -e s,//,/,g | sort -u > $@
|
||||
|
||||
exports.c: export_files
|
@ -1,19 +0,0 @@
|
||||
diff --git a/server/mpm/event/event.c b/server/mpm/event/event.c
|
||||
index 16e39be..2543693 100644
|
||||
--- a/server/mpm/event/event.c
|
||||
+++ b/server/mpm/event/event.c
|
||||
@@ -1111,10 +1111,11 @@ read_request:
|
||||
"network write failure in core output filter");
|
||||
cs->pub.state = CONN_STATE_LINGER;
|
||||
}
|
||||
- else if (c->data_in_output_filters) {
|
||||
+ else if (c->data_in_output_filters ||
|
||||
+ cs->pub.sense == CONN_SENSE_WANT_READ) {
|
||||
/* Still in WRITE_COMPLETION_STATE:
|
||||
- * Set a write timeout for this connection, and let the
|
||||
- * event thread poll for writeability.
|
||||
+ * Set a read/write timeout for this connection, and let the
|
||||
+ * event thread poll for read/writeability.
|
||||
*/
|
||||
cs->queue_timestamp = apr_time_now();
|
||||
notify_suspend(cs);
|
@ -1,113 +0,0 @@
|
||||
diff --git a/docs/man/apachectl.8 b/docs/man/apachectl.8
|
||||
index 870a048..32d3ee5 100644
|
||||
--- a/docs/man/apachectl.8
|
||||
+++ b/docs/man/apachectl.8
|
||||
@@ -74,7 +74,7 @@ Restarts the Apache httpd daemon\&. If the daemon is not running, it is started\
|
||||
Displays a full status report from mod_status\&. For this to work, you need to have mod_status enabled on your server and a text-based browser such as \fBlynx\fR available on your system\&. The URL used to access the status report can be set by editing the \fBSTATUSURL\fR variable in the script\&.
|
||||
.TP
|
||||
\fBstatus\fR
|
||||
-Displays a brief status report\&. Similar to the \fBfullstatus\fR option, except that the list of requests currently being served is omitted\&.
|
||||
+Displays a brief status report using systemd\&.
|
||||
.TP
|
||||
\fBgraceful\fR
|
||||
Gracefully restarts the Apache httpd daemon\&. If the daemon is not running, it is started\&. This differs from a normal restart in that currently open connections are not aborted\&. A side effect is that old log files will not be closed immediately\&. This means that if used in a log rotation script, a substantial delay may be necessary to ensure that the old log files are closed before processing them\&. This command automatically checks the configuration files as in \fBconfigtest\fR before initiating the restart to make sure Apache doesn't die\&. This is equivalent to \fBapachectl -k graceful\fR\&.
|
||||
diff --git a/support/apachectl.in b/support/apachectl.in
|
||||
index 3281c2e..8ce6f2b 100644
|
||||
--- a/support/apachectl.in
|
||||
+++ b/support/apachectl.in
|
||||
@@ -44,19 +44,20 @@ ARGV="$@"
|
||||
# the path to your httpd binary, including options if necessary
|
||||
HTTPD='@exp_sbindir@/@progname@'
|
||||
#
|
||||
-# pick up any necessary environment variables
|
||||
-if test -f @exp_sbindir@/envvars; then
|
||||
- . @exp_sbindir@/envvars
|
||||
-fi
|
||||
#
|
||||
# a command that outputs a formatted text version of the HTML at the
|
||||
# url given on the command line. Designed for lynx, however other
|
||||
# programs may work.
|
||||
-LYNX="@LYNX_PATH@ -dump"
|
||||
+if [ -x "@LYNX_PATH@" ]; then
|
||||
+ LYNX="@LYNX_PATH@ -dump"
|
||||
+else
|
||||
+ LYNX=none
|
||||
+fi
|
||||
#
|
||||
# the URL to your server's mod_status status page. If you do not
|
||||
# have one, then status and fullstatus will not work.
|
||||
STATUSURL="http://localhost:@PORT@/server-status"
|
||||
+
|
||||
#
|
||||
# Set this variable to a command that increases the maximum
|
||||
# number of file descriptors allowed per child process. This is
|
||||
@@ -76,9 +77,46 @@ if [ "x$ARGV" = "x" ] ; then
|
||||
ARGV="-h"
|
||||
fi
|
||||
|
||||
+function checklynx() {
|
||||
+if [ "$LYNX" = "none" ]; then
|
||||
+ echo "The 'links' package is required for this functionality."
|
||||
+ exit 8
|
||||
+fi
|
||||
+}
|
||||
+
|
||||
+function testconfig() {
|
||||
+# httpd is denied terminal access in SELinux, so run in the
|
||||
+# current context to get stdout from $HTTPD -t.
|
||||
+if test -x /usr/sbin/selinuxenabled && /usr/sbin/selinuxenabled; then
|
||||
+ runcon -- `id -Z` /usr/sbin/httpd $OPTIONS -t
|
||||
+else
|
||||
+ /usr/sbin/httpd $OPTIONS -t
|
||||
+fi
|
||||
+ERROR=$?
|
||||
+}
|
||||
+
|
||||
+if [ "x$2" != "x" ] ; then
|
||||
+ echo Passing arguments to httpd using apachectl is no longer supported.
|
||||
+ echo You can only start/stop/restart httpd using this script.
|
||||
+ echo If you want to pass extra arguments to httpd, edit the
|
||||
+ echo /etc/sysconfig/httpd config file.
|
||||
+fi
|
||||
+
|
||||
case $ACMD in
|
||||
-start|stop|restart|graceful|graceful-stop)
|
||||
- $HTTPD -k $ARGV
|
||||
+start|stop|restart|status)
|
||||
+ /usr/bin/systemctl $ACMD httpd.service
|
||||
+ ERROR=$?
|
||||
+ ;;
|
||||
+graceful)
|
||||
+ if /usr/bin/systemctl -q is-active httpd.service; then
|
||||
+ /usr/bin/systemctl reload httpd.service
|
||||
+ else
|
||||
+ /usr/bin/systemctl start httpd.service
|
||||
+ fi
|
||||
+ ERROR=$?
|
||||
+ ;;
|
||||
+graceful-stop)
|
||||
+ /usr/bin/systemctl stop httpd.service
|
||||
ERROR=$?
|
||||
;;
|
||||
startssl|sslstart|start-SSL)
|
||||
@@ -88,17 +126,14 @@ startssl|sslstart|start-SSL)
|
||||
ERROR=2
|
||||
;;
|
||||
configtest)
|
||||
- $HTTPD -t
|
||||
- ERROR=$?
|
||||
- ;;
|
||||
-status)
|
||||
- $LYNX $STATUSURL | awk ' /process$/ { print; exit } { print } '
|
||||
+ testconfig
|
||||
;;
|
||||
fullstatus)
|
||||
+ checklynx
|
||||
$LYNX $STATUSURL
|
||||
;;
|
||||
*)
|
||||
- $HTTPD "$@"
|
||||
+ /usr/sbin/httpd $OPTIONS "$@"
|
||||
ERROR=$?
|
||||
esac
|
||||
|
@ -1,77 +0,0 @@
|
||||
diff --git a/Makefile.in b/Makefile.in
|
||||
index ea8366e..06b8c5a 100644
|
||||
--- a/Makefile.in
|
||||
+++ b/Makefile.in
|
||||
@@ -4,7 +4,7 @@ CLEAN_SUBDIRS = test
|
||||
|
||||
PROGRAM_NAME = $(progname)
|
||||
PROGRAM_SOURCES = modules.c
|
||||
-PROGRAM_LDADD = buildmark.o $(HTTPD_LDFLAGS) $(PROGRAM_DEPENDENCIES) $(PCRE_LIBS) $(EXTRA_LIBS) $(AP_LIBS) $(LIBS)
|
||||
+PROGRAM_LDADD = buildmark.o $(HTTPD_LDFLAGS) $(PROGRAM_DEPENDENCIES) $(HTTPD_LIBS) $(EXTRA_LIBS) $(AP_LIBS) $(LIBS)
|
||||
PROGRAM_PRELINK = $(COMPILE) -c $(top_srcdir)/server/buildmark.c
|
||||
PROGRAM_DEPENDENCIES = \
|
||||
server/libmain.la \
|
||||
diff --git a/acinclude.m4 b/acinclude.m4
|
||||
index ce1d637..0ad0c13 100644
|
||||
--- a/acinclude.m4
|
||||
+++ b/acinclude.m4
|
||||
@@ -606,6 +606,30 @@ AC_DEFUN([APACHE_CHECK_OPENSSL],[
|
||||
fi
|
||||
])
|
||||
|
||||
+AC_DEFUN(APACHE_CHECK_SYSTEMD, [
|
||||
+dnl Check for systemd support for listen.c's socket activation.
|
||||
+case $host in
|
||||
+*-linux-*)
|
||||
+ if test -n "$PKGCONFIG" && $PKGCONFIG --exists libsystemd; then
|
||||
+ SYSTEMD_LIBS=`$PKGCONFIG --libs libsystemd`
|
||||
+ elif test -n "$PKGCONFIG" && $PKGCONFIG --exists libsystemd-daemon; then
|
||||
+ SYSTEMD_LIBS=`$PKGCONFIG --libs libsystemd-daemon`
|
||||
+ else
|
||||
+ AC_CHECK_LIB(systemd-daemon, sd_notify, SYSTEMD_LIBS="-lsystemd-daemon")
|
||||
+ fi
|
||||
+ if test -n "$SYSTEMD_LIBS"; then
|
||||
+ AC_CHECK_HEADERS(systemd/sd-daemon.h)
|
||||
+ if test "${ac_cv_header_systemd_sd_daemon_h}" = "no" || test -z "${SYSTEMD_LIBS}"; then
|
||||
+ AC_MSG_WARN([Your system does not support systemd.])
|
||||
+ else
|
||||
+ APR_ADDTO(HTTPD_LIBS, [$SYSTEMD_LIBS])
|
||||
+ AC_DEFINE(HAVE_SYSTEMD, 1, [Define if systemd is supported])
|
||||
+ fi
|
||||
+ fi
|
||||
+ ;;
|
||||
+esac
|
||||
+])
|
||||
+
|
||||
dnl
|
||||
dnl APACHE_EXPORT_ARGUMENTS
|
||||
dnl Export (via APACHE_SUBST) the various path-related variables that
|
||||
diff --git a/configure.in b/configure.in
|
||||
index 82bfeef..eedba50 100644
|
||||
--- a/configure.in
|
||||
+++ b/configure.in
|
||||
@@ -234,6 +234,7 @@ if test "$PCRE_CONFIG" != "false"; then
|
||||
AC_MSG_NOTICE([Using external PCRE library from $PCRE_CONFIG])
|
||||
APR_ADDTO(PCRE_INCLUDES, [`$PCRE_CONFIG --cflags`])
|
||||
APR_ADDTO(PCRE_LIBS, [`$PCRE_CONFIG --libs`])
|
||||
+ APR_ADDTO(HTTPD_LIBS, [\$(PCRE_LIBS)])
|
||||
else
|
||||
AC_MSG_ERROR([pcre-config for libpcre not found. PCRE is required and available from http://pcre.org/])
|
||||
fi
|
||||
@@ -504,6 +505,8 @@ if test "$ac_cv_struct_tm_gmtoff" = "yes"; then
|
||||
AC_DEFINE(HAVE_GMTOFF, 1, [Define if struct tm has a tm_gmtoff field])
|
||||
fi
|
||||
|
||||
+APACHE_CHECK_SYSTEMD
|
||||
+
|
||||
dnl ## Set up any appropriate OS-specific environment variables for apachectl
|
||||
|
||||
case $host in
|
||||
@@ -677,6 +680,7 @@ APACHE_SUBST(OS_DIR)
|
||||
APACHE_SUBST(BUILTIN_LIBS)
|
||||
APACHE_SUBST(SHLIBPATH_VAR)
|
||||
APACHE_SUBST(OS_SPECIFIC_VARS)
|
||||
+APACHE_SUBST(HTTPD_LIBS)
|
||||
|
||||
PRE_SHARED_CMDS='echo ""'
|
||||
POST_SHARED_CMDS='echo ""'
|
@ -1,15 +0,0 @@
|
||||
diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c
|
||||
index a5e86e4..6611610 100644
|
||||
--- a/modules/ssl/ssl_engine_kernel.c
|
||||
+++ b/modules/ssl/ssl_engine_kernel.c
|
||||
@@ -1823,8 +1823,8 @@ int ssl_callback_SSLVerify(int ok, X509_STORE_CTX *ctx)
|
||||
/*
|
||||
* Perform OCSP-based revocation checks
|
||||
*/
|
||||
- if (ok && ((sc->server->ocsp_mask & SSL_OCSPCHECK_CHAIN) ||
|
||||
- (errdepth == 0 && (sc->server->ocsp_mask & SSL_OCSPCHECK_LEAF)))) {
|
||||
+ if (ok && ((mctx->ocsp_mask & SSL_OCSPCHECK_CHAIN) ||
|
||||
+ (errdepth == 0 && (mctx->ocsp_mask & SSL_OCSPCHECK_LEAF)))) {
|
||||
/* If there was an optional verification error, it's not
|
||||
* possible to perform OCSP validation since the issuer may be
|
||||
* missing/untrusted. Fail in that case. */
|
@ -1,16 +0,0 @@
|
||||
diff --git a/modules/ssl/ssl_engine_io.c b/modules/ssl/ssl_engine_io.c
|
||||
index d52d5e3..8a57659 100644
|
||||
--- a/modules/ssl/ssl_engine_io.c
|
||||
+++ b/modules/ssl/ssl_engine_io.c
|
||||
@@ -1415,6 +1415,11 @@ static apr_status_t ssl_io_filter_handshake(ssl_filter_ctx_t *filter_ctx)
|
||||
"\"SSLVerifyClient optional_no_ca\" "
|
||||
"configuration");
|
||||
ssl_log_ssl_error(SSLLOG_MARK, APLOG_INFO, server);
|
||||
+
|
||||
+ /* on session resumption ssl_callback_SSLVerify()
|
||||
+ * will not be called, therefore we have to set it here
|
||||
+ */
|
||||
+ sslconn->verify_info = "GENEROUS";
|
||||
}
|
||||
else {
|
||||
const char *error = sslconn->verify_error ?
|
@ -1,140 +0,0 @@
|
||||
diff --git a/modules/proxy/ajp.h b/modules/proxy/ajp.h
|
||||
index c119a7e..267150a 100644
|
||||
--- a/modules/proxy/ajp.h
|
||||
+++ b/modules/proxy/ajp.h
|
||||
@@ -413,12 +413,14 @@ apr_status_t ajp_ilink_receive(apr_socket_t *sock, ajp_msg_t *msg);
|
||||
* @param sock backend socket
|
||||
* @param r current request
|
||||
* @param buffsize max size of the AJP packet.
|
||||
+ * @param secret authentication secret
|
||||
* @param uri requested uri
|
||||
* @return APR_SUCCESS or error
|
||||
*/
|
||||
apr_status_t ajp_send_header(apr_socket_t *sock, request_rec *r,
|
||||
apr_size_t buffsize,
|
||||
- apr_uri_t *uri);
|
||||
+ apr_uri_t *uri,
|
||||
+ const char *secret);
|
||||
|
||||
/**
|
||||
* Read the ajp message and return the type of the message.
|
||||
diff --git a/modules/proxy/ajp_header.c b/modules/proxy/ajp_header.c
|
||||
index 67353a7..680a8f3 100644
|
||||
--- a/modules/proxy/ajp_header.c
|
||||
+++ b/modules/proxy/ajp_header.c
|
||||
@@ -213,7 +213,8 @@ AJPV13_REQUEST/AJPV14_REQUEST=
|
||||
|
||||
static apr_status_t ajp_marshal_into_msgb(ajp_msg_t *msg,
|
||||
request_rec *r,
|
||||
- apr_uri_t *uri)
|
||||
+ apr_uri_t *uri,
|
||||
+ const char *secret)
|
||||
{
|
||||
int method;
|
||||
apr_uint32_t i, num_headers = 0;
|
||||
@@ -293,17 +294,15 @@ static apr_status_t ajp_marshal_into_msgb(ajp_msg_t *msg,
|
||||
i, elts[i].key, elts[i].val);
|
||||
}
|
||||
|
||||
-/* XXXX need to figure out how to do this
|
||||
- if (s->secret) {
|
||||
+ if (secret) {
|
||||
if (ajp_msg_append_uint8(msg, SC_A_SECRET) ||
|
||||
- ajp_msg_append_string(msg, s->secret)) {
|
||||
+ ajp_msg_append_string(msg, secret)) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(03228)
|
||||
- "Error ajp_marshal_into_msgb - "
|
||||
+ "ajp_marshal_into_msgb: "
|
||||
"Error appending secret");
|
||||
return APR_EGENERAL;
|
||||
}
|
||||
}
|
||||
- */
|
||||
|
||||
if (r->user) {
|
||||
if (ajp_msg_append_uint8(msg, SC_A_REMOTE_USER) ||
|
||||
@@ -671,7 +670,8 @@ static apr_status_t ajp_unmarshal_response(ajp_msg_t *msg,
|
||||
apr_status_t ajp_send_header(apr_socket_t *sock,
|
||||
request_rec *r,
|
||||
apr_size_t buffsize,
|
||||
- apr_uri_t *uri)
|
||||
+ apr_uri_t *uri,
|
||||
+ const char *secret)
|
||||
{
|
||||
ajp_msg_t *msg;
|
||||
apr_status_t rc;
|
||||
@@ -683,7 +683,7 @@ apr_status_t ajp_send_header(apr_socket_t *sock,
|
||||
return rc;
|
||||
}
|
||||
|
||||
- rc = ajp_marshal_into_msgb(msg, r, uri);
|
||||
+ rc = ajp_marshal_into_msgb(msg, r, uri, secret);
|
||||
if (rc != APR_SUCCESS) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00988)
|
||||
"ajp_send_header: ajp_marshal_into_msgb failed");
|
||||
diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c
|
||||
index 69a35ce..800ede1 100644
|
||||
--- a/modules/proxy/mod_proxy.c
|
||||
+++ b/modules/proxy/mod_proxy.c
|
||||
@@ -327,6 +327,12 @@ static const char *set_worker_param(apr_pool_t *p,
|
||||
worker->s->response_field_size = (s ? s : HUGE_STRING_LEN);
|
||||
worker->s->response_field_size_set = 1;
|
||||
}
|
||||
+ else if (!strcasecmp(key, "secret")) {
|
||||
+ if (PROXY_STRNCPY(worker->s->secret, val) != APR_SUCCESS) {
|
||||
+ return apr_psprintf(p, "Secret length must be < %d characters",
|
||||
+ (int)sizeof(worker->s->secret));
|
||||
+ }
|
||||
+ }
|
||||
else {
|
||||
if (set_worker_hc_param_f) {
|
||||
return set_worker_hc_param_f(p, s, worker, key, val, NULL);
|
||||
diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h
|
||||
index aabd09f..3419023 100644
|
||||
--- a/modules/proxy/mod_proxy.h
|
||||
+++ b/modules/proxy/mod_proxy.h
|
||||
@@ -357,6 +357,7 @@ PROXY_WORKER_HC_FAIL )
|
||||
#define PROXY_WORKER_MAX_HOSTNAME_SIZE 64
|
||||
#define PROXY_BALANCER_MAX_HOSTNAME_SIZE PROXY_WORKER_MAX_HOSTNAME_SIZE
|
||||
#define PROXY_BALANCER_MAX_STICKY_SIZE 64
|
||||
+#define PROXY_WORKER_MAX_SECRET_SIZE 64
|
||||
|
||||
#define PROXY_RFC1035_HOSTNAME_SIZE 256
|
||||
|
||||
@@ -450,6 +451,7 @@ typedef struct {
|
||||
hcmethod_t method; /* method to use for health check */
|
||||
apr_interval_time_t interval;
|
||||
char upgrade[PROXY_WORKER_MAX_SCHEME_SIZE];/* upgrade protocol used by mod_proxy_wstunnel */
|
||||
+ char secret[PROXY_WORKER_MAX_SECRET_SIZE]; /* authentication secret (e.g. AJP13) */
|
||||
char hostname_ex[PROXY_RFC1035_HOSTNAME_SIZE]; /* RFC1035 compliant version of the remote backend address */
|
||||
apr_size_t response_field_size; /* Size of proxy response buffer in bytes. */
|
||||
unsigned int response_field_size_set:1;
|
||||
diff --git a/modules/proxy/mod_proxy_ajp.c b/modules/proxy/mod_proxy_ajp.c
|
||||
index 73716af..6faabea 100644
|
||||
--- a/modules/proxy/mod_proxy_ajp.c
|
||||
+++ b/modules/proxy/mod_proxy_ajp.c
|
||||
@@ -193,6 +193,7 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r,
|
||||
apr_off_t content_length = 0;
|
||||
int original_status = r->status;
|
||||
const char *original_status_line = r->status_line;
|
||||
+ const char *secret = NULL;
|
||||
|
||||
if (psf->io_buffer_size_set)
|
||||
maxsize = psf->io_buffer_size;
|
||||
@@ -202,12 +203,15 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r,
|
||||
maxsize = AJP_MSG_BUFFER_SZ;
|
||||
maxsize = APR_ALIGN(maxsize, 1024);
|
||||
|
||||
+ if (*conn->worker->s->secret)
|
||||
+ secret = conn->worker->s->secret;
|
||||
+
|
||||
/*
|
||||
* Send the AJP request to the remote server
|
||||
*/
|
||||
|
||||
/* send request headers */
|
||||
- status = ajp_send_header(conn->sock, r, maxsize, uri);
|
||||
+ status = ajp_send_header(conn->sock, r, maxsize, uri, secret);
|
||||
if (status != APR_SUCCESS) {
|
||||
conn->close = 1;
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(00868)
|
@ -1,708 +0,0 @@
|
||||
# ./pullrev.sh 1830819 1830836 1830912 1830913 1830927 1831168 1831173
|
||||
|
||||
http://svn.apache.org/viewvc?view=revision&revision=1830819
|
||||
http://svn.apache.org/viewvc?view=revision&revision=1830912
|
||||
http://svn.apache.org/viewvc?view=revision&revision=1830913
|
||||
http://svn.apache.org/viewvc?view=revision&revision=1830927
|
||||
http://svn.apache.org/viewvc?view=revision&revision=1831168
|
||||
http://svn.apache.org/viewvc?view=revision&revision=1831173
|
||||
http://svn.apache.org/viewvc?view=revision&revision=1835240
|
||||
http://svn.apache.org/viewvc?view=revision&revision=1835242
|
||||
http://svn.apache.org/viewvc?view=revision&revision=1835615
|
||||
|
||||
diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c
|
||||
index 43397f9..ff8f429 100644
|
||||
--- httpd-2.4.35/modules/ssl/ssl_engine_config.c.r1830819+
|
||||
+++ httpd-2.4.35/modules/ssl/ssl_engine_config.c
|
||||
@@ -899,7 +899,9 @@
|
||||
SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
|
||||
const char *err;
|
||||
|
||||
- if ((err = ssl_cmd_check_file(cmd, &arg))) {
|
||||
+ /* Only check for non-ENGINE based certs. */
|
||||
+ if (!modssl_is_engine_id(arg)
|
||||
+ && (err = ssl_cmd_check_file(cmd, &arg))) {
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -915,7 +917,9 @@
|
||||
SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
|
||||
const char *err;
|
||||
|
||||
- if ((err = ssl_cmd_check_file(cmd, &arg))) {
|
||||
+ /* Check keyfile exists for non-ENGINE keys. */
|
||||
+ if (!modssl_is_engine_id(arg)
|
||||
+ && (err = ssl_cmd_check_file(cmd, &arg))) {
|
||||
return err;
|
||||
}
|
||||
|
||||
--- httpd-2.4.35/modules/ssl/ssl_engine_init.c.r1830819+
|
||||
+++ httpd-2.4.35/modules/ssl/ssl_engine_init.c
|
||||
@@ -1186,12 +1186,18 @@
|
||||
(certfile = APR_ARRAY_IDX(mctx->pks->cert_files, i,
|
||||
const char *));
|
||||
i++) {
|
||||
+ EVP_PKEY *pkey;
|
||||
+ const char *engine_certfile = NULL;
|
||||
+
|
||||
key_id = apr_psprintf(ptemp, "%s:%d", vhost_id, i);
|
||||
|
||||
ERR_clear_error();
|
||||
|
||||
/* first the certificate (public key) */
|
||||
- if (mctx->cert_chain) {
|
||||
+ if (modssl_is_engine_id(certfile)) {
|
||||
+ engine_certfile = certfile;
|
||||
+ }
|
||||
+ else if (mctx->cert_chain) {
|
||||
if ((SSL_CTX_use_certificate_file(mctx->ssl_ctx, certfile,
|
||||
SSL_FILETYPE_PEM) < 1)) {
|
||||
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02561)
|
||||
@@ -1220,12 +1226,46 @@
|
||||
|
||||
ERR_clear_error();
|
||||
|
||||
- if ((SSL_CTX_use_PrivateKey_file(mctx->ssl_ctx, keyfile,
|
||||
- SSL_FILETYPE_PEM) < 1) &&
|
||||
- (ERR_GET_FUNC(ERR_peek_last_error())
|
||||
- != X509_F_X509_CHECK_PRIVATE_KEY)) {
|
||||
+ if (modssl_is_engine_id(keyfile)) {
|
||||
+ apr_status_t rv;
|
||||
+
|
||||
+ cert = NULL;
|
||||
+
|
||||
+ if ((rv = modssl_load_engine_keypair(s, ptemp, vhost_id,
|
||||
+ engine_certfile, keyfile,
|
||||
+ &cert, &pkey))) {
|
||||
+ return rv;
|
||||
+ }
|
||||
+
|
||||
+ if (cert) {
|
||||
+ if (SSL_CTX_use_certificate(mctx->ssl_ctx, cert) < 1) {
|
||||
+ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10137)
|
||||
+ "Failed to configure engine certificate %s, check %s",
|
||||
+ key_id, certfile);
|
||||
+ ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
|
||||
+ return APR_EGENERAL;
|
||||
+ }
|
||||
+
|
||||
+ /* SSL_CTX now owns the cert. */
|
||||
+ X509_free(cert);
|
||||
+ }
|
||||
+
|
||||
+ if (SSL_CTX_use_PrivateKey(mctx->ssl_ctx, pkey) < 1) {
|
||||
+ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10130)
|
||||
+ "Failed to configure private key %s from engine",
|
||||
+ keyfile);
|
||||
+ ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
|
||||
+ return APR_EGENERAL;
|
||||
+ }
|
||||
+
|
||||
+ /* SSL_CTX now owns the key */
|
||||
+ EVP_PKEY_free(pkey);
|
||||
+ }
|
||||
+ else if ((SSL_CTX_use_PrivateKey_file(mctx->ssl_ctx, keyfile,
|
||||
+ SSL_FILETYPE_PEM) < 1)
|
||||
+ && (ERR_GET_FUNC(ERR_peek_last_error())
|
||||
+ != X509_F_X509_CHECK_PRIVATE_KEY)) {
|
||||
ssl_asn1_t *asn1;
|
||||
- EVP_PKEY *pkey;
|
||||
const unsigned char *ptr;
|
||||
|
||||
ERR_clear_error();
|
||||
@@ -1312,8 +1352,9 @@
|
||||
/*
|
||||
* Try to read DH parameters from the (first) SSLCertificateFile
|
||||
*/
|
||||
- if ((certfile = APR_ARRAY_IDX(mctx->pks->cert_files, 0, const char *)) &&
|
||||
- (dhparams = ssl_dh_GetParamFromFile(certfile))) {
|
||||
+ certfile = APR_ARRAY_IDX(mctx->pks->cert_files, 0, const char *);
|
||||
+ if (certfile && !modssl_is_engine_id(certfile)
|
||||
+ && (dhparams = ssl_dh_GetParamFromFile(certfile))) {
|
||||
SSL_CTX_set_tmp_dh(mctx->ssl_ctx, dhparams);
|
||||
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02540)
|
||||
"Custom DH parameters (%d bits) for %s loaded from %s",
|
||||
@@ -1325,10 +1366,10 @@
|
||||
/*
|
||||
* Similarly, try to read the ECDH curve name from SSLCertificateFile...
|
||||
*/
|
||||
- if ((certfile != NULL) &&
|
||||
- (ecparams = ssl_ec_GetParamFromFile(certfile)) &&
|
||||
- (nid = EC_GROUP_get_curve_name(ecparams)) &&
|
||||
- (eckey = EC_KEY_new_by_curve_name(nid))) {
|
||||
+ if (certfile && !modssl_is_engine_id(certfile)
|
||||
+ && (ecparams = ssl_ec_GetParamFromFile(certfile))
|
||||
+ && (nid = EC_GROUP_get_curve_name(ecparams))
|
||||
+ && (eckey = EC_KEY_new_by_curve_name(nid))) {
|
||||
SSL_CTX_set_tmp_ecdh(mctx->ssl_ctx, eckey);
|
||||
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02541)
|
||||
"ECDH curve %s for %s specified in %s",
|
||||
--- httpd-2.4.35/modules/ssl/ssl_engine_pphrase.c.r1830819+
|
||||
+++ httpd-2.4.35/modules/ssl/ssl_engine_pphrase.c
|
||||
@@ -143,9 +143,6 @@
|
||||
const char *key_id = asn1_table_vhost_key(mc, p, sc->vhost_id, idx);
|
||||
EVP_PKEY *pPrivateKey = NULL;
|
||||
ssl_asn1_t *asn1;
|
||||
- unsigned char *ucp;
|
||||
- long int length;
|
||||
- BOOL bReadable;
|
||||
int nPassPhrase = (*pphrases)->nelts;
|
||||
int nPassPhraseRetry = 0;
|
||||
apr_time_t pkey_mtime = 0;
|
||||
@@ -222,16 +219,12 @@
|
||||
* is not empty. */
|
||||
ERR_clear_error();
|
||||
|
||||
- bReadable = ((pPrivateKey = modssl_read_privatekey(ppcb_arg.pkey_file,
|
||||
- NULL, ssl_pphrase_Handle_CB, &ppcb_arg)) != NULL ?
|
||||
- TRUE : FALSE);
|
||||
-
|
||||
- /*
|
||||
- * when the private key file now was readable,
|
||||
- * it's fine and we go out of the loop
|
||||
- */
|
||||
- if (bReadable)
|
||||
- break;
|
||||
+ pPrivateKey = modssl_read_privatekey(ppcb_arg.pkey_file,
|
||||
+ ssl_pphrase_Handle_CB, &ppcb_arg);
|
||||
+ /* If the private key was successfully read, nothing more to
|
||||
+ do here. */
|
||||
+ if (pPrivateKey != NULL)
|
||||
+ break;
|
||||
|
||||
/*
|
||||
* when we have more remembered pass phrases
|
||||
@@ -356,19 +349,12 @@
|
||||
nPassPhrase++;
|
||||
}
|
||||
|
||||
- /*
|
||||
- * Insert private key into the global module configuration
|
||||
- * (we convert it to a stand-alone DER byte sequence
|
||||
- * because the SSL library uses static variables inside a
|
||||
- * RSA structure which do not survive DSO reloads!)
|
||||
- */
|
||||
- length = i2d_PrivateKey(pPrivateKey, NULL);
|
||||
- ucp = ssl_asn1_table_set(mc->tPrivateKey, key_id, length);
|
||||
- (void)i2d_PrivateKey(pPrivateKey, &ucp); /* 2nd arg increments */
|
||||
+ /* Cache the private key in the global module configuration so it
|
||||
+ * can be used after subsequent reloads. */
|
||||
+ asn1 = ssl_asn1_table_set(mc->tPrivateKey, key_id, pPrivateKey);
|
||||
|
||||
if (ppcb_arg.nPassPhraseDialogCur != 0) {
|
||||
/* remember mtime of encrypted keys */
|
||||
- asn1 = ssl_asn1_table_get(mc->tPrivateKey, key_id);
|
||||
asn1->source_mtime = pkey_mtime;
|
||||
}
|
||||
|
||||
@@ -619,3 +605,303 @@
|
||||
*/
|
||||
return (len);
|
||||
}
|
||||
+
|
||||
+
|
||||
+#if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_INIT)
|
||||
+
|
||||
+/* OpenSSL UI implementation for passphrase entry; largely duplicated
|
||||
+ * from ssl_pphrase_Handle_CB but adjusted for UI API. TODO: Might be
|
||||
+ * worth trying to shift pphrase handling over to the UI API
|
||||
+ * completely. */
|
||||
+static int passphrase_ui_open(UI *ui)
|
||||
+{
|
||||
+ pphrase_cb_arg_t *ppcb = UI_get0_user_data(ui);
|
||||
+ SSLSrvConfigRec *sc = mySrvConfig(ppcb->s);
|
||||
+
|
||||
+ ppcb->nPassPhraseDialog++;
|
||||
+ ppcb->nPassPhraseDialogCur++;
|
||||
+
|
||||
+ /*
|
||||
+ * Builtin or Pipe dialog
|
||||
+ */
|
||||
+ if (sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN
|
||||
+ || sc->server->pphrase_dialog_type == SSL_PPTYPE_PIPE) {
|
||||
+ if (sc->server->pphrase_dialog_type == SSL_PPTYPE_PIPE) {
|
||||
+ if (!readtty) {
|
||||
+ ap_log_error(APLOG_MARK, APLOG_INFO, 0, ppcb->s,
|
||||
+ APLOGNO(10143)
|
||||
+ "Init: Creating pass phrase dialog pipe child "
|
||||
+ "'%s'", sc->server->pphrase_dialog_path);
|
||||
+ if (ssl_pipe_child_create(ppcb->p,
|
||||
+ sc->server->pphrase_dialog_path)
|
||||
+ != APR_SUCCESS) {
|
||||
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, ppcb->s,
|
||||
+ APLOGNO(10144)
|
||||
+ "Init: Failed to create pass phrase pipe '%s'",
|
||||
+ sc->server->pphrase_dialog_path);
|
||||
+ return 0;
|
||||
+ }
|
||||
+ }
|
||||
+ ap_log_error(APLOG_MARK, APLOG_INFO, 0, ppcb->s, APLOGNO(10145)
|
||||
+ "Init: Requesting pass phrase via piped dialog");
|
||||
+ }
|
||||
+ else { /* sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN */
|
||||
+#ifdef WIN32
|
||||
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, ppcb->s, APLOGNO(10146)
|
||||
+ "Init: Failed to create pass phrase pipe '%s'",
|
||||
+ sc->server->pphrase_dialog_path);
|
||||
+ return 0;
|
||||
+#else
|
||||
+ /*
|
||||
+ * stderr has already been redirected to the error_log.
|
||||
+ * rather than attempting to temporarily rehook it to the terminal,
|
||||
+ * we print the prompt to stdout before EVP_read_pw_string turns
|
||||
+ * off tty echo
|
||||
+ */
|
||||
+ apr_file_open_stdout(&writetty, ppcb->p);
|
||||
+
|
||||
+ ap_log_error(APLOG_MARK, APLOG_INFO, 0, ppcb->s, APLOGNO(10147)
|
||||
+ "Init: Requesting pass phrase via builtin terminal "
|
||||
+ "dialog");
|
||||
+#endif
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * The first time display a header to inform the user about what
|
||||
+ * program he actually speaks to, which module is responsible for
|
||||
+ * this terminal dialog and why to the hell he has to enter
|
||||
+ * something...
|
||||
+ */
|
||||
+ if (ppcb->nPassPhraseDialog == 1) {
|
||||
+ apr_file_printf(writetty, "%s mod_ssl (Pass Phrase Dialog)\n",
|
||||
+ AP_SERVER_BASEVERSION);
|
||||
+ apr_file_printf(writetty,
|
||||
+ "A pass phrase is required to access the private key.\n");
|
||||
+ }
|
||||
+ if (ppcb->bPassPhraseDialogOnce) {
|
||||
+ ppcb->bPassPhraseDialogOnce = FALSE;
|
||||
+ apr_file_printf(writetty, "\n");
|
||||
+ apr_file_printf(writetty, "Private key %s (%s)\n",
|
||||
+ ppcb->key_id, ppcb->pkey_file);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+static int passphrase_ui_read(UI *ui, UI_STRING *uis)
|
||||
+{
|
||||
+ pphrase_cb_arg_t *ppcb = UI_get0_user_data(ui);
|
||||
+ SSLSrvConfigRec *sc = mySrvConfig(ppcb->s);
|
||||
+ const char *prompt;
|
||||
+ int i;
|
||||
+ int bufsize;
|
||||
+ int len;
|
||||
+ char *buf;
|
||||
+
|
||||
+ prompt = UI_get0_output_string(uis);
|
||||
+ if (prompt == NULL) {
|
||||
+ prompt = "Enter pass phrase:";
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * Get the maximum expected size and allocate the buffer
|
||||
+ */
|
||||
+ bufsize = UI_get_result_maxsize(uis);
|
||||
+ buf = apr_pcalloc(ppcb->p, bufsize);
|
||||
+
|
||||
+ if (sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN
|
||||
+ || sc->server->pphrase_dialog_type == SSL_PPTYPE_PIPE) {
|
||||
+ /*
|
||||
+ * Get the pass phrase through a callback.
|
||||
+ * Empty input is not accepted.
|
||||
+ */
|
||||
+ for (;;) {
|
||||
+ if (sc->server->pphrase_dialog_type == SSL_PPTYPE_PIPE) {
|
||||
+ i = pipe_get_passwd_cb(buf, bufsize, "", FALSE);
|
||||
+ }
|
||||
+ else { /* sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN */
|
||||
+ i = EVP_read_pw_string(buf, bufsize, "", FALSE);
|
||||
+ }
|
||||
+ if (i != 0) {
|
||||
+ OPENSSL_cleanse(buf, bufsize);
|
||||
+ return 0;
|
||||
+ }
|
||||
+ len = strlen(buf);
|
||||
+ if (len < 1){
|
||||
+ apr_file_printf(writetty, "Apache:mod_ssl:Error: Pass phrase"
|
||||
+ "empty (needs to be at least 1 character).\n");
|
||||
+ apr_file_puts(prompt, writetty);
|
||||
+ }
|
||||
+ else {
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ /*
|
||||
+ * Filter program
|
||||
+ */
|
||||
+ else if (sc->server->pphrase_dialog_type == SSL_PPTYPE_FILTER) {
|
||||
+ const char *cmd = sc->server->pphrase_dialog_path;
|
||||
+ const char **argv = apr_palloc(ppcb->p, sizeof(char *) * 3);
|
||||
+ char *result;
|
||||
+
|
||||
+ ap_log_error(APLOG_MARK, APLOG_INFO, 0, ppcb->s, APLOGNO(10148)
|
||||
+ "Init: Requesting pass phrase from dialog filter "
|
||||
+ "program (%s)", cmd);
|
||||
+
|
||||
+ argv[0] = cmd;
|
||||
+ argv[1] = ppcb->key_id;
|
||||
+ argv[2] = NULL;
|
||||
+
|
||||
+ result = ssl_util_readfilter(ppcb->s, ppcb->p, cmd, argv);
|
||||
+ apr_cpystrn(buf, result, bufsize);
|
||||
+ len = strlen(buf);
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * Ok, we now have the pass phrase, so give it back
|
||||
+ */
|
||||
+ ppcb->cpPassPhraseCur = apr_pstrdup(ppcb->p, buf);
|
||||
+ UI_set_result(ui, uis, buf);
|
||||
+
|
||||
+ /* Clear sensitive data. */
|
||||
+ OPENSSL_cleanse(buf, bufsize);
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+static int passphrase_ui_write(UI *ui, UI_STRING *uis)
|
||||
+{
|
||||
+ pphrase_cb_arg_t *ppcb = UI_get0_user_data(ui);
|
||||
+ SSLSrvConfigRec *sc;
|
||||
+ const char *prompt;
|
||||
+
|
||||
+ sc = mySrvConfig(ppcb->s);
|
||||
+
|
||||
+ if (sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN
|
||||
+ || sc->server->pphrase_dialog_type == SSL_PPTYPE_PIPE) {
|
||||
+ prompt = UI_get0_output_string(uis);
|
||||
+ apr_file_puts(prompt, writetty);
|
||||
+ }
|
||||
+
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+static int passphrase_ui_close(UI *ui)
|
||||
+{
|
||||
+ /*
|
||||
+ * Close the pipes if they were opened
|
||||
+ */
|
||||
+ if (readtty) {
|
||||
+ apr_file_close(readtty);
|
||||
+ apr_file_close(writetty);
|
||||
+ readtty = writetty = NULL;
|
||||
+ }
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+static apr_status_t pp_ui_method_cleanup(void *uip)
|
||||
+{
|
||||
+ UI_METHOD *uim = uip;
|
||||
+
|
||||
+ UI_destroy_method(uim);
|
||||
+
|
||||
+ return APR_SUCCESS;
|
||||
+}
|
||||
+
|
||||
+static UI_METHOD *get_passphrase_ui(apr_pool_t *p)
|
||||
+{
|
||||
+ UI_METHOD *ui_method = UI_create_method("Passphrase UI");
|
||||
+
|
||||
+ UI_method_set_opener(ui_method, passphrase_ui_open);
|
||||
+ UI_method_set_reader(ui_method, passphrase_ui_read);
|
||||
+ UI_method_set_writer(ui_method, passphrase_ui_write);
|
||||
+ UI_method_set_closer(ui_method, passphrase_ui_close);
|
||||
+
|
||||
+ apr_pool_cleanup_register(p, ui_method, pp_ui_method_cleanup,
|
||||
+ pp_ui_method_cleanup);
|
||||
+
|
||||
+ return ui_method;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+apr_status_t modssl_load_engine_keypair(server_rec *s, apr_pool_t *p,
|
||||
+ const char *vhostid,
|
||||
+ const char *certid, const char *keyid,
|
||||
+ X509 **pubkey, EVP_PKEY **privkey)
|
||||
+{
|
||||
+ const char *c, *scheme;
|
||||
+ ENGINE *e;
|
||||
+ UI_METHOD *ui_method = get_passphrase_ui(p);
|
||||
+ pphrase_cb_arg_t ppcb;
|
||||
+
|
||||
+ memset(&ppcb, 0, sizeof ppcb);
|
||||
+ ppcb.s = s;
|
||||
+ ppcb.p = p;
|
||||
+ ppcb.bPassPhraseDialogOnce = TRUE;
|
||||
+ ppcb.key_id = vhostid;
|
||||
+ ppcb.pkey_file = keyid;
|
||||
+
|
||||
+ c = ap_strchr_c(keyid, ':');
|
||||
+ if (!c || c == keyid) {
|
||||
+ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10131)
|
||||
+ "Init: Unrecognized private key identifier `%s'",
|
||||
+ keyid);
|
||||
+ return ssl_die(s);
|
||||
+ }
|
||||
+
|
||||
+ scheme = apr_pstrmemdup(p, keyid, c - keyid);
|
||||
+ if (!(e = ENGINE_by_id(scheme))) {
|
||||
+ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10132)
|
||||
+ "Init: Failed to load engine for private key %s",
|
||||
+ keyid);
|
||||
+ ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
|
||||
+ return ssl_die(s);
|
||||
+ }
|
||||
+
|
||||
+ if (!ENGINE_init(e)) {
|
||||
+ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10149)
|
||||
+ "Init: Failed to initialize engine %s for private key %s",
|
||||
+ scheme, keyid);
|
||||
+ ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
|
||||
+ return ssl_die(s);
|
||||
+ }
|
||||
+
|
||||
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
|
||||
+ "Init: Initialized engine %s for private key %s",
|
||||
+ scheme, keyid);
|
||||
+
|
||||
+ if (APLOGdebug(s)) {
|
||||
+ ENGINE_ctrl_cmd_string(e, "VERBOSE", NULL, 0);
|
||||
+ }
|
||||
+
|
||||
+ if (certid) {
|
||||
+ struct {
|
||||
+ const char *cert_id;
|
||||
+ X509 *cert;
|
||||
+ } params = { certid, NULL };
|
||||
+
|
||||
+ if (!ENGINE_ctrl_cmd(e, "LOAD_CERT_CTRL", 0, ¶ms, NULL, 1)) {
|
||||
+ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10136)
|
||||
+ "Init: Unable to get the certificate");
|
||||
+ ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
|
||||
+ return ssl_die(s);
|
||||
+ }
|
||||
+
|
||||
+ *pubkey = params.cert;
|
||||
+ }
|
||||
+
|
||||
+ *privkey = ENGINE_load_private_key(e, keyid, ui_method, &ppcb);
|
||||
+ if (*privkey == NULL) {
|
||||
+ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10133)
|
||||
+ "Init: Unable to get the private key");
|
||||
+ ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
|
||||
+ return ssl_die(s);
|
||||
+ }
|
||||
+
|
||||
+ ENGINE_finish(e);
|
||||
+ ENGINE_free(e);
|
||||
+
|
||||
+ return APR_SUCCESS;
|
||||
+}
|
||||
+#endif
|
||||
--- httpd-2.4.35/modules/ssl/ssl_private.h.r1830819+
|
||||
+++ httpd-2.4.35/modules/ssl/ssl_private.h
|
||||
@@ -986,21 +986,28 @@
|
||||
apr_status_t ssl_load_encrypted_pkey(server_rec *, apr_pool_t *, int,
|
||||
const char *, apr_array_header_t **);
|
||||
|
||||
+/* Load public and/or private key from the configured ENGINE. Private
|
||||
+ * key returned as *pkey. certid can be NULL, in which case *pubkey
|
||||
+ * is not altered. Errors logged on failure. */
|
||||
+apr_status_t modssl_load_engine_keypair(server_rec *s, apr_pool_t *p,
|
||||
+ const char *vhostid,
|
||||
+ const char *certid, const char *keyid,
|
||||
+ X509 **pubkey, EVP_PKEY **privkey);
|
||||
+
|
||||
/** Diffie-Hellman Parameter Support */
|
||||
DH *ssl_dh_GetParamFromFile(const char *);
|
||||
#ifdef HAVE_ECC
|
||||
EC_GROUP *ssl_ec_GetParamFromFile(const char *);
|
||||
#endif
|
||||
|
||||
-unsigned char *ssl_asn1_table_set(apr_hash_t *table,
|
||||
- const char *key,
|
||||
- long int length);
|
||||
-
|
||||
-ssl_asn1_t *ssl_asn1_table_get(apr_hash_t *table,
|
||||
- const char *key);
|
||||
-
|
||||
-void ssl_asn1_table_unset(apr_hash_t *table,
|
||||
- const char *key);
|
||||
+/* Store the EVP_PKEY key (serialized into DER) in the hash table with
|
||||
+ * key, returning the ssl_asn1_t structure pointer. */
|
||||
+ssl_asn1_t *ssl_asn1_table_set(apr_hash_t *table, const char *key,
|
||||
+ EVP_PKEY *pkey);
|
||||
+/* Retrieve the ssl_asn1_t structure with given key from the hash. */
|
||||
+ssl_asn1_t *ssl_asn1_table_get(apr_hash_t *table, const char *key);
|
||||
+/* Remove and free the ssl_asn1_t structure with given key. */
|
||||
+void ssl_asn1_table_unset(apr_hash_t *table, const char *key);
|
||||
|
||||
/** Mutex Support */
|
||||
int ssl_mutex_init(server_rec *, apr_pool_t *);
|
||||
@@ -1088,6 +1095,10 @@
|
||||
int ssl_is_challenge(conn_rec *c, const char *servername,
|
||||
X509 **pcert, EVP_PKEY **pkey);
|
||||
|
||||
+/* Returns non-zero if the cert/key filename should be handled through
|
||||
+ * the configured ENGINE. */
|
||||
+int modssl_is_engine_id(const char *name);
|
||||
+
|
||||
#endif /* SSL_PRIVATE_H */
|
||||
/** @} */
|
||||
|
||||
--- httpd-2.4.35/modules/ssl/ssl_util.c.r1830819+
|
||||
+++ httpd-2.4.35/modules/ssl/ssl_util.c
|
||||
@@ -175,45 +175,37 @@
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
-/*
|
||||
- * certain key data needs to survive restarts,
|
||||
- * which are stored in the user data table of s->process->pool.
|
||||
- * to prevent "leaking" of this data, we use malloc/free
|
||||
- * rather than apr_palloc and these wrappers to help make sure
|
||||
- * we do not leak the malloc-ed data.
|
||||
- */
|
||||
-unsigned char *ssl_asn1_table_set(apr_hash_t *table,
|
||||
- const char *key,
|
||||
- long int length)
|
||||
+/* Decrypted private keys are cached to survive restarts. The cached
|
||||
+ * data must have lifetime of the process (hence malloc/free rather
|
||||
+ * than pools), and uses raw DER since the EVP_PKEY structure
|
||||
+ * internals may not survive across a module reload. */
|
||||
+ssl_asn1_t *ssl_asn1_table_set(apr_hash_t *table, const char *key,
|
||||
+ EVP_PKEY *pkey)
|
||||
{
|
||||
apr_ssize_t klen = strlen(key);
|
||||
ssl_asn1_t *asn1 = apr_hash_get(table, key, klen);
|
||||
+ apr_size_t length = i2d_PrivateKey(pkey, NULL);
|
||||
+ unsigned char *p;
|
||||
|
||||
- /*
|
||||
- * if a value for this key already exists,
|
||||
- * reuse as much of the already malloc-ed data
|
||||
- * as possible.
|
||||
- */
|
||||
+ /* Re-use structure if cached previously. */
|
||||
if (asn1) {
|
||||
if (asn1->nData != length) {
|
||||
- free(asn1->cpData); /* XXX: realloc? */
|
||||
- asn1->cpData = NULL;
|
||||
+ asn1->cpData = ap_realloc(asn1->cpData, length);
|
||||
}
|
||||
}
|
||||
else {
|
||||
asn1 = ap_malloc(sizeof(*asn1));
|
||||
asn1->source_mtime = 0; /* used as a note for encrypted private keys */
|
||||
- asn1->cpData = NULL;
|
||||
- }
|
||||
-
|
||||
- asn1->nData = length;
|
||||
- if (!asn1->cpData) {
|
||||
asn1->cpData = ap_malloc(length);
|
||||
+
|
||||
+ apr_hash_set(table, key, klen, asn1);
|
||||
}
|
||||
|
||||
- apr_hash_set(table, key, klen, asn1);
|
||||
+ asn1->nData = length;
|
||||
+ p = asn1->cpData;
|
||||
+ i2d_PrivateKey(pkey, &p); /* increases p by length */
|
||||
|
||||
- return asn1->cpData; /* caller will assign a value to this */
|
||||
+ return asn1;
|
||||
}
|
||||
|
||||
ssl_asn1_t *ssl_asn1_table_get(apr_hash_t *table,
|
||||
@@ -463,3 +455,13 @@
|
||||
}
|
||||
|
||||
#endif /* #if APR_HAS_THREADS && MODSSL_USE_OPENSSL_PRE_1_1_API */
|
||||
+
|
||||
+int modssl_is_engine_id(const char *name)
|
||||
+{
|
||||
+#if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_INIT)
|
||||
+ /* ### Can handle any other special ENGINE key names here? */
|
||||
+ return strncmp(name, "pkcs11:", 7) == 0;
|
||||
+#else
|
||||
+ return 0;
|
||||
+#endif
|
||||
+}
|
||||
--- httpd-2.4.35/modules/ssl/ssl_util_ssl.c.r1830819+
|
||||
+++ httpd-2.4.35/modules/ssl/ssl_util_ssl.c
|
||||
@@ -74,7 +74,7 @@
|
||||
** _________________________________________________________________
|
||||
*/
|
||||
|
||||
-EVP_PKEY *modssl_read_privatekey(const char* filename, EVP_PKEY **key, pem_password_cb *cb, void *s)
|
||||
+EVP_PKEY *modssl_read_privatekey(const char *filename, pem_password_cb *cb, void *s)
|
||||
{
|
||||
EVP_PKEY *rc;
|
||||
BIO *bioS;
|
||||
@@ -83,7 +83,7 @@
|
||||
/* 1. try PEM (= DER+Base64+headers) */
|
||||
if ((bioS=BIO_new_file(filename, "r")) == NULL)
|
||||
return NULL;
|
||||
- rc = PEM_read_bio_PrivateKey(bioS, key, cb, s);
|
||||
+ rc = PEM_read_bio_PrivateKey(bioS, NULL, cb, s);
|
||||
BIO_free(bioS);
|
||||
|
||||
if (rc == NULL) {
|
||||
@@ -107,41 +107,9 @@
|
||||
BIO_free(bioS);
|
||||
}
|
||||
}
|
||||
- if (rc != NULL && key != NULL) {
|
||||
- if (*key != NULL)
|
||||
- EVP_PKEY_free(*key);
|
||||
- *key = rc;
|
||||
- }
|
||||
return rc;
|
||||
}
|
||||
|
||||
-typedef struct {
|
||||
- const char *pass;
|
||||
- int pass_len;
|
||||
-} pass_ctx;
|
||||
-
|
||||
-static int provide_pass(char *buf, int size, int rwflag, void *baton)
|
||||
-{
|
||||
- pass_ctx *ctx = baton;
|
||||
- if (ctx->pass_len > 0) {
|
||||
- if (ctx->pass_len < size) {
|
||||
- size = (int)ctx->pass_len;
|
||||
- }
|
||||
- memcpy(buf, ctx->pass, size);
|
||||
- }
|
||||
- return ctx->pass_len;
|
||||
-}
|
||||
-
|
||||
-EVP_PKEY *modssl_read_encrypted_pkey(const char *filename, EVP_PKEY **key,
|
||||
- const char *pass, apr_size_t pass_len)
|
||||
-{
|
||||
- pass_ctx ctx;
|
||||
-
|
||||
- ctx.pass = pass;
|
||||
- ctx.pass_len = pass_len;
|
||||
- return modssl_read_privatekey(filename, key, provide_pass, &ctx);
|
||||
-}
|
||||
-
|
||||
/* _________________________________________________________________
|
||||
**
|
||||
** Smart shutdown
|
||||
--- httpd-2.4.35/modules/ssl/ssl_util_ssl.h.r1830819+
|
||||
+++ httpd-2.4.35/modules/ssl/ssl_util_ssl.h
|
||||
@@ -64,8 +64,11 @@
|
||||
void modssl_init_app_data2_idx(void);
|
||||
void *modssl_get_app_data2(SSL *);
|
||||
void modssl_set_app_data2(SSL *, void *);
|
||||
-EVP_PKEY *modssl_read_privatekey(const char *, EVP_PKEY **, pem_password_cb *, void *);
|
||||
-EVP_PKEY *modssl_read_encrypted_pkey(const char *, EVP_PKEY **, const char *, apr_size_t);
|
||||
+
|
||||
+/* Read private key from filename in either PEM or raw base64(DER)
|
||||
+ * format, using password entry callback cb and userdata. */
|
||||
+EVP_PKEY *modssl_read_privatekey(const char *filename, pem_password_cb *cb, void *ud);
|
||||
+
|
||||
int modssl_smart_shutdown(SSL *ssl);
|
||||
BOOL modssl_X509_getBC(X509 *, int *, int *);
|
||||
char *modssl_X509_NAME_ENTRY_to_string(apr_pool_t *p, X509_NAME_ENTRY *xsne,
|
@ -1,22 +0,0 @@
|
||||
diff --git a/modules/filters/mod_deflate.c b/modules/filters/mod_deflate.c
|
||||
index d218bab..9f86b09 100644
|
||||
--- a/modules/filters/mod_deflate.c
|
||||
+++ b/modules/filters/mod_deflate.c
|
||||
@@ -864,7 +864,7 @@ static apr_status_t deflate_out_filter(ap_filter_t *f,
|
||||
|
||||
if (c->note_output_name) {
|
||||
apr_table_setn(r->notes, c->note_output_name,
|
||||
- (ctx->stream.total_in > 0)
|
||||
+ (ctx->stream.total_out > 0)
|
||||
? apr_off_t_toa(r->pool,
|
||||
ctx->stream.total_out)
|
||||
: "-");
|
||||
@@ -1336,8 +1336,6 @@ static apr_status_t deflate_in_filter(ap_filter_t *f,
|
||||
ctx->stream.next_in = (unsigned char *)data;
|
||||
ctx->stream.avail_in = (int)len;
|
||||
|
||||
- zRC = Z_OK;
|
||||
-
|
||||
if (!ctx->validation_buffer) {
|
||||
while (ctx->stream.avail_in != 0) {
|
||||
if (ctx->stream.avail_out == 0) {
|
@ -1,245 +0,0 @@
|
||||
--- httpd-2.4.33/modules/arch/unix/config5.m4.systemd
|
||||
+++ httpd-2.4.33/modules/arch/unix/config5.m4
|
||||
@@ -18,6 +18,16 @@
|
||||
fi
|
||||
])
|
||||
|
||||
+APACHE_MODULE(systemd, Systemd support, , , all, [
|
||||
+ if test "${ac_cv_header_systemd_sd_daemon_h}" = "no" || test -z "${SYSTEMD_LIBS}"; then
|
||||
+ AC_MSG_WARN([Your system does not support systemd.])
|
||||
+ enable_systemd="no"
|
||||
+ else
|
||||
+ APR_ADDTO(MOD_SYSTEMD_LDADD, [$SYSTEMD_LIBS])
|
||||
+ enable_systemd="yes"
|
||||
+ fi
|
||||
+])
|
||||
+
|
||||
APR_ADDTO(INCLUDES, [-I\$(top_srcdir)/$modpath_current])
|
||||
|
||||
APACHE_MODPATH_FINISH
|
||||
--- httpd-2.4.33/modules/arch/unix/mod_systemd.c.systemd
|
||||
+++ httpd-2.4.33/modules/arch/unix/mod_systemd.c
|
||||
@@ -0,0 +1,223 @@
|
||||
+/* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
+ * contributor license agreements. See the NOTICE file distributed with
|
||||
+ * this work for additional information regarding copyright ownership.
|
||||
+ * The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
+ * (the "License"); you may not use this file except in compliance with
|
||||
+ * the License. You may obtain a copy of the License at
|
||||
+ *
|
||||
+ * http://www.apache.org/licenses/LICENSE-2.0
|
||||
+ *
|
||||
+ * Unless required by applicable law or agreed to in writing, software
|
||||
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
+ * See the License for the specific language governing permissions and
|
||||
+ * limitations under the License.
|
||||
+ *
|
||||
+ */
|
||||
+
|
||||
+#include <stdint.h>
|
||||
+#include <ap_config.h>
|
||||
+#include "ap_mpm.h"
|
||||
+#include <http_core.h>
|
||||
+#include <httpd.h>
|
||||
+#include <http_log.h>
|
||||
+#include <apr_version.h>
|
||||
+#include <apr_pools.h>
|
||||
+#include <apr_strings.h>
|
||||
+#include "unixd.h"
|
||||
+#include "scoreboard.h"
|
||||
+#include "mpm_common.h"
|
||||
+
|
||||
+#include "systemd/sd-daemon.h"
|
||||
+#include "systemd/sd-journal.h"
|
||||
+
|
||||
+#if APR_HAVE_UNISTD_H
|
||||
+#include <unistd.h>
|
||||
+#endif
|
||||
+
|
||||
+static int shutdown_timer = 0;
|
||||
+static int shutdown_counter = 0;
|
||||
+static unsigned long bytes_served;
|
||||
+static pid_t mainpid;
|
||||
+static char describe_listeners[50];
|
||||
+
|
||||
+static int systemd_pre_config(apr_pool_t *pconf, apr_pool_t *plog,
|
||||
+ apr_pool_t *ptemp)
|
||||
+{
|
||||
+ sd_notify(0,
|
||||
+ "RELOADING=1\n"
|
||||
+ "STATUS=Reading configuration...\n");
|
||||
+ ap_extended_status = 1;
|
||||
+ return OK;
|
||||
+}
|
||||
+
|
||||
+static char *dump_listener(ap_listen_rec *lr, apr_pool_t *p)
|
||||
+{
|
||||
+ apr_sockaddr_t *sa = lr->bind_addr;
|
||||
+ char addr[128];
|
||||
+
|
||||
+ if (apr_sockaddr_is_wildcard(sa)) {
|
||||
+ return apr_pstrcat(p, "port ", apr_itoa(p, sa->port), NULL);
|
||||
+ }
|
||||
+
|
||||
+ apr_sockaddr_ip_getbuf(addr, sizeof addr, sa);
|
||||
+
|
||||
+ return apr_psprintf(p, "%s port %u", addr, sa->port);
|
||||
+}
|
||||
+
|
||||
+static int systemd_post_config(apr_pool_t *pconf, apr_pool_t *plog,
|
||||
+ apr_pool_t *ptemp, server_rec *s)
|
||||
+{
|
||||
+ ap_listen_rec *lr;
|
||||
+ apr_size_t plen = sizeof describe_listeners;
|
||||
+ char *p = describe_listeners;
|
||||
+
|
||||
+ if (ap_state_query(AP_SQ_MAIN_STATE) == AP_SQ_MS_CREATE_PRE_CONFIG)
|
||||
+ return OK;
|
||||
+
|
||||
+ for (lr = ap_listeners; lr; lr = lr->next) {
|
||||
+ char *s = dump_listener(lr, ptemp);
|
||||
+
|
||||
+ if (strlen(s) + 3 < plen) {
|
||||
+ char *newp = apr_cpystrn(p, s, plen);
|
||||
+ if (lr->next)
|
||||
+ newp = apr_cpystrn(newp, ", ", 3);
|
||||
+ plen -= newp - p;
|
||||
+ p = newp;
|
||||
+ }
|
||||
+ else {
|
||||
+ if (plen < 4) {
|
||||
+ p = describe_listeners + sizeof describe_listeners - 4;
|
||||
+ plen = 4;
|
||||
+ }
|
||||
+ apr_cpystrn(p, "...", plen);
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ sd_journal_print(LOG_INFO, "Server configured, listening on: %s", describe_listeners);
|
||||
+
|
||||
+ return OK;
|
||||
+}
|
||||
+
|
||||
+static int systemd_pre_mpm(apr_pool_t *p, ap_scoreboard_e sb_type)
|
||||
+{
|
||||
+ int rv;
|
||||
+
|
||||
+ mainpid = getpid();
|
||||
+
|
||||
+ rv = sd_notifyf(0, "READY=1\n"
|
||||
+ "STATUS=Started, listening on: %s\n"
|
||||
+ "MAINPID=%" APR_PID_T_FMT,
|
||||
+ describe_listeners, mainpid);
|
||||
+ if (rv < 0) {
|
||||
+ ap_log_perror(APLOG_MARK, APLOG_ERR, 0, p, APLOGNO(02395)
|
||||
+ "sd_notifyf returned an error %d", rv);
|
||||
+ }
|
||||
+
|
||||
+ return OK;
|
||||
+}
|
||||
+
|
||||
+static int systemd_monitor(apr_pool_t *p, server_rec *s)
|
||||
+{
|
||||
+ ap_sload_t sload;
|
||||
+ apr_interval_time_t up_time;
|
||||
+ char bps[5];
|
||||
+ int rv;
|
||||
+
|
||||
+ if (!ap_extended_status) {
|
||||
+ /* Nothing useful to report if ExtendedStatus disabled. */
|
||||
+ return DECLINED;
|
||||
+ }
|
||||
+
|
||||
+ ap_get_sload(&sload);
|
||||
+
|
||||
+ if (sload.access_count == 0) {
|
||||
+ rv = sd_notifyf(0, "READY=1\n"
|
||||
+ "STATUS=Running, listening on: %s\n",
|
||||
+ describe_listeners);
|
||||
+ }
|
||||
+ else {
|
||||
+ /* up_time in seconds */
|
||||
+ up_time = (apr_uint32_t) apr_time_sec(apr_time_now() -
|
||||
+ ap_scoreboard_image->global->restart_time);
|
||||
+
|
||||
+ apr_strfsize((unsigned long)((float) (sload.bytes_served)
|
||||
+ / (float) up_time), bps);
|
||||
+
|
||||
+ rv = sd_notifyf(0, "READY=1\n"
|
||||
+ "STATUS=Total requests: %lu; Idle/Busy workers %d/%d;"
|
||||
+ "Requests/sec: %.3g; Bytes served/sec: %sB/sec\n",
|
||||
+ sload.access_count, sload.idle, sload.busy,
|
||||
+ ((float) sload.access_count) / (float) up_time, bps);
|
||||
+ }
|
||||
+
|
||||
+ if (rv < 0) {
|
||||
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02396)
|
||||
+ "sd_notifyf returned an error %d", rv);
|
||||
+ }
|
||||
+
|
||||
+ /* Shutdown httpd when nothing is sent for shutdown_timer seconds. */
|
||||
+ if (sload.bytes_served == bytes_served) {
|
||||
+ /* mpm_common.c: INTERVAL_OF_WRITABLE_PROBES is 10 */
|
||||
+ shutdown_counter += 10;
|
||||
+ if (shutdown_timer > 0 && shutdown_counter >= shutdown_timer) {
|
||||
+ rv = sd_notifyf(0, "READY=1\n"
|
||||
+ "STATUS=Stopped as result of IdleShutdown "
|
||||
+ "timeout.");
|
||||
+ if (rv < 0) {
|
||||
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02804)
|
||||
+ "sd_notifyf returned an error %d", rv);
|
||||
+ }
|
||||
+ kill(mainpid, AP_SIG_GRACEFUL);
|
||||
+ }
|
||||
+ }
|
||||
+ else {
|
||||
+ shutdown_counter = 0;
|
||||
+ }
|
||||
+
|
||||
+ bytes_served = sload.bytes_served;
|
||||
+
|
||||
+ return DECLINED;
|
||||
+}
|
||||
+
|
||||
+static void systemd_register_hooks(apr_pool_t *p)
|
||||
+{
|
||||
+ /* Enable ap_extended_status. */
|
||||
+ ap_hook_pre_config(systemd_pre_config, NULL, NULL, APR_HOOK_LAST);
|
||||
+ /* Grab the listener config. */
|
||||
+ ap_hook_post_config(systemd_post_config, NULL, NULL, APR_HOOK_LAST);
|
||||
+ /* We know the PID in this hook ... */
|
||||
+ ap_hook_pre_mpm(systemd_pre_mpm, NULL, NULL, APR_HOOK_LAST);
|
||||
+ /* Used to update httpd's status line using sd_notifyf */
|
||||
+ ap_hook_monitor(systemd_monitor, NULL, NULL, APR_HOOK_MIDDLE);
|
||||
+}
|
||||
+
|
||||
+static const char *set_shutdown_timer(cmd_parms *cmd, void *dummy,
|
||||
+ const char *arg)
|
||||
+{
|
||||
+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
|
||||
+ if (err != NULL) {
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
+ shutdown_timer = atoi(arg);
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+static const command_rec systemd_cmds[] =
|
||||
+{
|
||||
+AP_INIT_TAKE1("IdleShutdown", set_shutdown_timer, NULL, RSRC_CONF,
|
||||
+ "Number of seconds in idle-state after which httpd is shutdown"),
|
||||
+ {NULL}
|
||||
+};
|
||||
+
|
||||
+AP_DECLARE_MODULE(systemd) = {
|
||||
+ STANDARD20_MODULE_STUFF,
|
||||
+ NULL,
|
||||
+ NULL,
|
||||
+ NULL,
|
||||
+ NULL,
|
||||
+ systemd_cmds,
|
||||
+ systemd_register_hooks,
|
||||
+};
|
@ -1,20 +0,0 @@
|
||||
diff --git a/modules/dav/main/util.c b/modules/dav/main/util.c
|
||||
index 1ae5914027c..3f7822fc931 100644
|
||||
--- a/modules/dav/main/util.c
|
||||
+++ b/modules/dav/main/util.c
|
||||
@@ -801,8 +801,14 @@ static dav_error * dav_process_if_header(request_rec *r, dav_if_header **p_ih)
|
||||
"for the same state.");
|
||||
}
|
||||
condition = DAV_IF_COND_NOT;
|
||||
+ list += 2;
|
||||
+ }
|
||||
+ else {
|
||||
+ return dav_new_error(r->pool, HTTP_BAD_REQUEST,
|
||||
+ DAV_ERR_IF_UNK_CHAR, 0,
|
||||
+ "Invalid \"If:\" header: "
|
||||
+ "Unexpected character in List");
|
||||
}
|
||||
- list += 2;
|
||||
break;
|
||||
|
||||
case ' ':
|
@ -1,39 +0,0 @@
|
||||
diff --git a/modules/session/mod_session.c b/modules/session/mod_session.c
|
||||
index 10e6396..7ee477c 100644
|
||||
--- a/modules/session/mod_session.c
|
||||
+++ b/modules/session/mod_session.c
|
||||
@@ -126,20 +126,23 @@ static apr_status_t ap_session_load(request_rec * r, session_rec ** z)
|
||||
|
||||
/* found a session that hasn't expired? */
|
||||
now = apr_time_now();
|
||||
+
|
||||
if (zz) {
|
||||
- if (zz->expiry && zz->expiry < now) {
|
||||
+ /* load the session attibutes */
|
||||
+ rv = ap_run_session_decode(r, zz);
|
||||
+
|
||||
+ /* having a session we cannot decode is just as good as having
|
||||
+ none at all */
|
||||
+ if (OK != rv) {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01817)
|
||||
+ "error while decoding the session, "
|
||||
+ "session not loaded: %s", r->uri);
|
||||
zz = NULL;
|
||||
}
|
||||
- else {
|
||||
- /* having a session we cannot decode is just as good as having
|
||||
- none at all */
|
||||
- rv = ap_run_session_decode(r, zz);
|
||||
- if (OK != rv) {
|
||||
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01817)
|
||||
- "error while decoding the session, "
|
||||
- "session not loaded: %s", r->uri);
|
||||
- zz = NULL;
|
||||
- }
|
||||
+
|
||||
+ /* invalidate session if session is expired */
|
||||
+ if (zz && zz->expiry && zz->expiry < now) {
|
||||
+ zz = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -1,207 +0,0 @@
|
||||
diff --git a/include/scoreboard.h b/include/scoreboard.h
|
||||
index 9376da2..92d198d 100644
|
||||
--- a/include/scoreboard.h
|
||||
+++ b/include/scoreboard.h
|
||||
@@ -148,7 +148,9 @@ struct process_score {
|
||||
apr_uint32_t lingering_close; /* async connections in lingering close */
|
||||
apr_uint32_t keep_alive; /* async connections in keep alive */
|
||||
apr_uint32_t suspended; /* connections suspended by some module */
|
||||
- int bucket; /* Listener bucket used by this child */
|
||||
+ int bucket; /* Listener bucket used by this child; this field is DEPRECATED
|
||||
+ * and no longer updated by the MPMs (i.e. always zero).
|
||||
+ */
|
||||
};
|
||||
|
||||
/* Scoreboard is now in 'local' memory, since it isn't updated once created,
|
||||
diff --git a/server/mpm/event/event.c b/server/mpm/event/event.c
|
||||
index ffe8a23..048ae61 100644
|
||||
--- a/server/mpm/event/event.c
|
||||
+++ b/server/mpm/event/event.c
|
||||
@@ -2695,7 +2695,6 @@ static int make_child(server_rec * s, int slot, int bucket)
|
||||
|
||||
ap_scoreboard_image->parent[slot].quiescing = 0;
|
||||
ap_scoreboard_image->parent[slot].not_accepting = 0;
|
||||
- ap_scoreboard_image->parent[slot].bucket = bucket;
|
||||
event_note_child_started(slot, pid);
|
||||
active_daemons++;
|
||||
retained->total_daemons++;
|
||||
@@ -2734,6 +2733,7 @@ static void perform_idle_server_maintenance(int child_bucket, int num_buckets)
|
||||
* that threads_per_child is always > 0 */
|
||||
int status = SERVER_DEAD;
|
||||
int child_threads_active = 0;
|
||||
+ int bucket = i % num_buckets;
|
||||
|
||||
if (i >= retained->max_daemons_limit &&
|
||||
free_length == retained->idle_spawn_rate[child_bucket]) {
|
||||
@@ -2757,7 +2757,7 @@ static void perform_idle_server_maintenance(int child_bucket, int num_buckets)
|
||||
*/
|
||||
if (status <= SERVER_READY && !ps->quiescing && !ps->not_accepting
|
||||
&& ps->generation == retained->mpm->my_generation
|
||||
- && ps->bucket == child_bucket)
|
||||
+ && bucket == child_bucket)
|
||||
{
|
||||
++idle_thread_count;
|
||||
}
|
||||
@@ -2768,7 +2768,9 @@ static void perform_idle_server_maintenance(int child_bucket, int num_buckets)
|
||||
last_non_dead = i;
|
||||
}
|
||||
active_thread_count += child_threads_active;
|
||||
- if (!ps->pid && free_length < retained->idle_spawn_rate[child_bucket])
|
||||
+ if (!ps->pid
|
||||
+ && bucket == child_bucket
|
||||
+ && free_length < retained->idle_spawn_rate[child_bucket])
|
||||
free_slots[free_length++] = i;
|
||||
else if (child_threads_active == threads_per_child)
|
||||
had_healthy_child = 1;
|
||||
@@ -2951,13 +2953,14 @@ static void server_main_loop(int remaining_children_to_start, int num_buckets)
|
||||
retained->total_daemons--;
|
||||
if (processed_status == APEXIT_CHILDSICK) {
|
||||
/* resource shortage, minimize the fork rate */
|
||||
- retained->idle_spawn_rate[ps->bucket] = 1;
|
||||
+ retained->idle_spawn_rate[child_slot % num_buckets] = 1;
|
||||
}
|
||||
else if (remaining_children_to_start) {
|
||||
/* we're still doing a 1-for-1 replacement of dead
|
||||
* children with new children
|
||||
*/
|
||||
- make_child(ap_server_conf, child_slot, ps->bucket);
|
||||
+ make_child(ap_server_conf, child_slot,
|
||||
+ child_slot % num_buckets);
|
||||
--remaining_children_to_start;
|
||||
}
|
||||
}
|
||||
diff --git a/server/mpm/prefork/prefork.c b/server/mpm/prefork/prefork.c
|
||||
index 8efda72..7c00625 100644
|
||||
--- a/server/mpm/prefork/prefork.c
|
||||
+++ b/server/mpm/prefork/prefork.c
|
||||
@@ -637,8 +637,9 @@ static void child_main(int child_num_arg, int child_bucket)
|
||||
}
|
||||
|
||||
|
||||
-static int make_child(server_rec *s, int slot, int bucket)
|
||||
+static int make_child(server_rec *s, int slot)
|
||||
{
|
||||
+ int bucket = slot % retained->mpm->num_buckets;
|
||||
int pid;
|
||||
|
||||
if (slot + 1 > retained->max_daemons_limit) {
|
||||
@@ -716,7 +717,6 @@ static int make_child(server_rec *s, int slot, int bucket)
|
||||
child_main(slot, bucket);
|
||||
}
|
||||
|
||||
- ap_scoreboard_image->parent[slot].bucket = bucket;
|
||||
prefork_note_child_started(slot, pid);
|
||||
|
||||
return 0;
|
||||
@@ -732,7 +732,7 @@ static void startup_children(int number_to_start)
|
||||
if (ap_scoreboard_image->servers[i][0].status != SERVER_DEAD) {
|
||||
continue;
|
||||
}
|
||||
- if (make_child(ap_server_conf, i, i % retained->mpm->num_buckets) < 0) {
|
||||
+ if (make_child(ap_server_conf, i) < 0) {
|
||||
break;
|
||||
}
|
||||
--number_to_start;
|
||||
@@ -741,8 +741,6 @@ static void startup_children(int number_to_start)
|
||||
|
||||
static void perform_idle_server_maintenance(apr_pool_t *p)
|
||||
{
|
||||
- static int bucket_make_child_record = -1;
|
||||
- static int bucket_kill_child_record = -1;
|
||||
int i;
|
||||
int idle_count;
|
||||
worker_score *ws;
|
||||
@@ -789,6 +787,7 @@ static void perform_idle_server_maintenance(apr_pool_t *p)
|
||||
}
|
||||
retained->max_daemons_limit = last_non_dead + 1;
|
||||
if (idle_count > ap_daemons_max_free) {
|
||||
+ static int bucket_kill_child_record = -1;
|
||||
/* kill off one child... we use the pod because that'll cause it to
|
||||
* shut down gracefully, in case it happened to pick up a request
|
||||
* while we were counting
|
||||
@@ -819,10 +818,7 @@ static void perform_idle_server_maintenance(apr_pool_t *p)
|
||||
idle_count, total_non_dead);
|
||||
}
|
||||
for (i = 0; i < free_length; ++i) {
|
||||
- bucket_make_child_record++;
|
||||
- bucket_make_child_record %= retained->mpm->num_buckets;
|
||||
- make_child(ap_server_conf, free_slots[i],
|
||||
- bucket_make_child_record);
|
||||
+ make_child(ap_server_conf, free_slots[i]);
|
||||
}
|
||||
/* the next time around we want to spawn twice as many if this
|
||||
* wasn't good enough, but not if we've just done a graceful
|
||||
@@ -867,7 +863,7 @@ static int prefork_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
|
||||
|
||||
if (one_process) {
|
||||
AP_MONCONTROL(1);
|
||||
- make_child(ap_server_conf, 0, 0);
|
||||
+ make_child(ap_server_conf, 0);
|
||||
/* NOTREACHED */
|
||||
ap_assert(0);
|
||||
return !OK;
|
||||
@@ -976,8 +972,7 @@ static int prefork_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
|
||||
/* we're still doing a 1-for-1 replacement of dead
|
||||
* children with new children
|
||||
*/
|
||||
- make_child(ap_server_conf, child_slot,
|
||||
- ap_get_scoreboard_process(child_slot)->bucket);
|
||||
+ make_child(ap_server_conf, child_slot);
|
||||
--remaining_children_to_start;
|
||||
}
|
||||
#if APR_HAS_OTHER_CHILD
|
||||
diff --git a/server/mpm/worker/worker.c b/server/mpm/worker/worker.c
|
||||
index 8012fe2..a927942 100644
|
||||
--- a/server/mpm/worker/worker.c
|
||||
+++ b/server/mpm/worker/worker.c
|
||||
@@ -1339,7 +1339,6 @@ static int make_child(server_rec *s, int slot, int bucket)
|
||||
worker_note_child_lost_slot(slot, pid);
|
||||
}
|
||||
ap_scoreboard_image->parent[slot].quiescing = 0;
|
||||
- ap_scoreboard_image->parent[slot].bucket = bucket;
|
||||
worker_note_child_started(slot, pid);
|
||||
return 0;
|
||||
}
|
||||
@@ -1388,6 +1387,7 @@ static void perform_idle_server_maintenance(int child_bucket, int num_buckets)
|
||||
int any_dead_threads = 0;
|
||||
int all_dead_threads = 1;
|
||||
int child_threads_active = 0;
|
||||
+ int bucket = i % num_buckets;
|
||||
|
||||
if (i >= retained->max_daemons_limit &&
|
||||
totally_free_length == retained->idle_spawn_rate[child_bucket]) {
|
||||
@@ -1420,7 +1420,7 @@ static void perform_idle_server_maintenance(int child_bucket, int num_buckets)
|
||||
if (status <= SERVER_READY &&
|
||||
!ps->quiescing &&
|
||||
ps->generation == retained->mpm->my_generation &&
|
||||
- ps->bucket == child_bucket) {
|
||||
+ bucket == child_bucket) {
|
||||
++idle_thread_count;
|
||||
}
|
||||
if (status >= SERVER_READY && status < SERVER_GRACEFUL) {
|
||||
@@ -1430,6 +1430,7 @@ static void perform_idle_server_maintenance(int child_bucket, int num_buckets)
|
||||
}
|
||||
active_thread_count += child_threads_active;
|
||||
if (any_dead_threads
|
||||
+ && bucket == child_bucket
|
||||
&& totally_free_length < retained->idle_spawn_rate[child_bucket]
|
||||
&& free_length < MAX_SPAWN_RATE / num_buckets
|
||||
&& (!ps->pid /* no process in the slot */
|
||||
@@ -1615,14 +1616,15 @@ static void server_main_loop(int remaining_children_to_start, int num_buckets)
|
||||
ps->quiescing = 0;
|
||||
if (processed_status == APEXIT_CHILDSICK) {
|
||||
/* resource shortage, minimize the fork rate */
|
||||
- retained->idle_spawn_rate[ps->bucket] = 1;
|
||||
+ retained->idle_spawn_rate[child_slot % num_buckets] = 1;
|
||||
}
|
||||
else if (remaining_children_to_start
|
||||
&& child_slot < ap_daemons_limit) {
|
||||
/* we're still doing a 1-for-1 replacement of dead
|
||||
* children with new children
|
||||
*/
|
||||
- make_child(ap_server_conf, child_slot, ps->bucket);
|
||||
+ make_child(ap_server_conf, child_slot,
|
||||
+ child_slot % num_buckets);
|
||||
--remaining_children_to_start;
|
||||
}
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c
|
||||
index de0ffb0..e6a9f67 100644
|
||||
--- a/modules/ssl/ssl_engine_kernel.c
|
||||
+++ b/modules/ssl/ssl_engine_kernel.c
|
||||
@@ -1154,6 +1154,7 @@ static int ssl_hook_Access_modern(request_rec *r, SSLSrvConfigRec *sc, SSLDirCon
|
||||
ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, r->server);
|
||||
apr_table_setn(r->notes, "error-notes",
|
||||
"Reason: Cannot perform Post-Handshake Authentication.<br />");
|
||||
+ SSL_set_verify(ssl, vmode_inplace, NULL);
|
||||
return HTTP_FORBIDDEN;
|
||||
}
|
||||
|
||||
@@ -1175,6 +1176,7 @@ static int ssl_hook_Access_modern(request_rec *r, SSLSrvConfigRec *sc, SSLDirCon
|
||||
* Finally check for acceptable renegotiation results
|
||||
*/
|
||||
if (OK != (rc = ssl_check_post_client_verify(r, sc, dc, sslconn, ssl))) {
|
||||
+ SSL_set_verify(ssl, vmode_inplace, NULL);
|
||||
return rc;
|
||||
}
|
||||
}
|
@ -1,111 +0,0 @@
|
||||
--- a/modules/aaa/mod_auth_digest.c 2019/03/12 09:24:19 1855297
|
||||
+++ b/modules/aaa/mod_auth_digest.c 2019/03/12 09:24:26 1855298
|
||||
@@ -92,7 +92,6 @@
|
||||
int check_nc;
|
||||
const char *algorithm;
|
||||
char *uri_list;
|
||||
- const char *ha1;
|
||||
} digest_config_rec;
|
||||
|
||||
|
||||
@@ -153,6 +152,7 @@
|
||||
apr_time_t nonce_time;
|
||||
enum hdr_sts auth_hdr_sts;
|
||||
int needed_auth;
|
||||
+ const char *ha1;
|
||||
client_entry *client;
|
||||
} digest_header_rec;
|
||||
|
||||
@@ -1304,7 +1304,7 @@
|
||||
*/
|
||||
|
||||
static authn_status get_hash(request_rec *r, const char *user,
|
||||
- digest_config_rec *conf)
|
||||
+ digest_config_rec *conf, const char **rethash)
|
||||
{
|
||||
authn_status auth_result;
|
||||
char *password;
|
||||
@@ -1356,7 +1356,7 @@
|
||||
} while (current_provider);
|
||||
|
||||
if (auth_result == AUTH_USER_FOUND) {
|
||||
- conf->ha1 = password;
|
||||
+ *rethash = password;
|
||||
}
|
||||
|
||||
return auth_result;
|
||||
@@ -1483,25 +1483,24 @@
|
||||
|
||||
/* RFC-2069 */
|
||||
static const char *old_digest(const request_rec *r,
|
||||
- const digest_header_rec *resp, const char *ha1)
|
||||
+ const digest_header_rec *resp)
|
||||
{
|
||||
const char *ha2;
|
||||
|
||||
ha2 = ap_md5(r->pool, (unsigned char *)apr_pstrcat(r->pool, resp->method, ":",
|
||||
resp->uri, NULL));
|
||||
return ap_md5(r->pool,
|
||||
- (unsigned char *)apr_pstrcat(r->pool, ha1, ":", resp->nonce,
|
||||
- ":", ha2, NULL));
|
||||
+ (unsigned char *)apr_pstrcat(r->pool, resp->ha1, ":",
|
||||
+ resp->nonce, ":", ha2, NULL));
|
||||
}
|
||||
|
||||
/* RFC-2617 */
|
||||
static const char *new_digest(const request_rec *r,
|
||||
- digest_header_rec *resp,
|
||||
- const digest_config_rec *conf)
|
||||
+ digest_header_rec *resp)
|
||||
{
|
||||
const char *ha1, *ha2, *a2;
|
||||
|
||||
- ha1 = conf->ha1;
|
||||
+ ha1 = resp->ha1;
|
||||
|
||||
a2 = apr_pstrcat(r->pool, resp->method, ":", resp->uri, NULL);
|
||||
ha2 = ap_md5(r->pool, (const unsigned char *)a2);
|
||||
@@ -1514,7 +1513,6 @@
|
||||
NULL));
|
||||
}
|
||||
|
||||
-
|
||||
static void copy_uri_components(apr_uri_t *dst,
|
||||
apr_uri_t *src, request_rec *r) {
|
||||
if (src->scheme && src->scheme[0] != '\0') {
|
||||
@@ -1759,7 +1757,7 @@
|
||||
return HTTP_UNAUTHORIZED;
|
||||
}
|
||||
|
||||
- return_code = get_hash(r, r->user, conf);
|
||||
+ return_code = get_hash(r, r->user, conf, &resp->ha1);
|
||||
|
||||
if (return_code == AUTH_USER_NOT_FOUND) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01790)
|
||||
@@ -1789,7 +1787,7 @@
|
||||
|
||||
if (resp->message_qop == NULL) {
|
||||
/* old (rfc-2069) style digest */
|
||||
- if (strcmp(resp->digest, old_digest(r, resp, conf->ha1))) {
|
||||
+ if (strcmp(resp->digest, old_digest(r, resp))) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01792)
|
||||
"user %s: password mismatch: %s", r->user,
|
||||
r->uri);
|
||||
@@ -1819,7 +1817,7 @@
|
||||
return HTTP_UNAUTHORIZED;
|
||||
}
|
||||
|
||||
- exp_digest = new_digest(r, resp, conf);
|
||||
+ exp_digest = new_digest(r, resp);
|
||||
if (!exp_digest) {
|
||||
/* we failed to allocate a client struct */
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
@@ -1903,7 +1901,7 @@
|
||||
|
||||
/* calculate rspauth attribute
|
||||
*/
|
||||
- ha1 = conf->ha1;
|
||||
+ ha1 = resp->ha1;
|
||||
|
||||
a2 = apr_pstrcat(r->pool, ":", resp->uri, NULL);
|
||||
ha2 = ap_md5(r->pool, (const unsigned char *)a2);
|
@ -1,235 +0,0 @@
|
||||
diff --git a/docs/manual/mod/core.html.en b/docs/manual/mod/core.html.en
|
||||
index 0a24bc8..20d1e5a 100644
|
||||
--- a/docs/manual/mod/core.html.en
|
||||
+++ b/docs/manual/mod/core.html.en
|
||||
@@ -97,6 +97,7 @@ available</td></tr>
|
||||
<li><img alt="" src="../images/down.gif" /> <a href="#maxrangeoverlaps">MaxRangeOverlaps</a></li>
|
||||
<li><img alt="" src="../images/down.gif" /> <a href="#maxrangereversals">MaxRangeReversals</a></li>
|
||||
<li><img alt="" src="../images/down.gif" /> <a href="#maxranges">MaxRanges</a></li>
|
||||
+<li><img alt="" src="../images/down.gif" /> <a href="#mergeslashes">MergeSlashes</a></li>
|
||||
<li><img alt="" src="../images/down.gif" /> <a href="#mergetrailers">MergeTrailers</a></li>
|
||||
<li><img alt="" src="../images/down.gif" /> <a href="#mutex">Mutex</a></li>
|
||||
<li><img alt="" src="../images/down.gif" /> <a href="#namevirtualhost">NameVirtualHost</a></li>
|
||||
@@ -3465,6 +3466,30 @@ resource </td></tr>
|
||||
|
||||
</div>
|
||||
<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
|
||||
+<div class="directive-section"><h2><a name="MergeSlashes" id="MergeSlashes">MergeSlashes</a> <a name="mergeslashes" id="mergeslashes">Directive</a></h2>
|
||||
+<table class="directive">
|
||||
+<tr><th><a href="directive-dict.html#Description">Description:</a></th><td>Controls whether the server merges consecutive slashes in URLs. </td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Syntax">Syntax:</a></th><td><code>MergeSlashes ON | OFF</code></td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Default">Default:</a></th><td><code>MergeSlashes ON</code></td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Context">Context:</a></th><td>server config, virtual host</td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Status">Status:</a></th><td>Core</td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Module">Module:</a></th><td>core</td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Compatibility">Compatibility:</a></th><td>Available in Apache HTTP Server 2.4.6 in Red Hat Enterprise Linux 7</td></tr>
|
||||
+</table>
|
||||
+ <p>By default, the server merges (or collapses) multiple consecutive slash
|
||||
+ ('/') characters in the path component of the request URL.</p>
|
||||
+
|
||||
+ <p>When mapping URL's to the filesystem, these multiple slashes are not
|
||||
+ significant. However, URL's handled other ways, such as by CGI or proxy,
|
||||
+ might prefer to retain the significance of multiple consecutive slashes.
|
||||
+ In these cases <code class="directive">MergeSlashes</code> can be set to
|
||||
+ <em>OFF</em> to retain the multiple consecutive slashes. In these
|
||||
+ configurations, regular expressions used in the configuration file that match
|
||||
+ the path component of the URL (<code class="directive">LocationMatch</code>,
|
||||
+ <code class="directive">RewriteRule</code>, ...) need to take into account multiple
|
||||
+ consecutive slashes.</p>
|
||||
+</div>
|
||||
+<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
|
||||
<div class="directive-section"><h2><a name="MergeTrailers" id="MergeTrailers">MergeTrailers</a> <a name="mergetrailers" id="mergetrailers">Directive</a></h2>
|
||||
<table class="directive">
|
||||
<tr><th><a href="directive-dict.html#Description">Description:</a></th><td>Determines whether trailers are merged into headers</td></tr>
|
||||
--- a/include/http_core.h 2019/03/18 08:49:19 1855736
|
||||
+++ b/include/http_core.h 2019/03/18 08:49:59 1855737
|
||||
@@ -740,7 +740,7 @@
|
||||
#define AP_HTTP_METHODS_LENIENT 1
|
||||
#define AP_HTTP_METHODS_REGISTERED 2
|
||||
char http_methods;
|
||||
-
|
||||
+ unsigned int merge_slashes;
|
||||
} core_server_config;
|
||||
|
||||
/* for AddOutputFiltersByType in core.c */
|
||||
diff --git a/include/httpd.h b/include/httpd.h
|
||||
index 65392f8..99f7f04 100644
|
||||
--- a/include/httpd.h
|
||||
+++ b/include/httpd.h
|
||||
@@ -1697,11 +1697,21 @@ AP_DECLARE(int) ap_unescape_url_keep2f(char *url, int decode_slashes);
|
||||
AP_DECLARE(int) ap_unescape_urlencoded(char *query);
|
||||
|
||||
/**
|
||||
- * Convert all double slashes to single slashes
|
||||
- * @param name The string to convert
|
||||
+ * Convert all double slashes to single slashes, except where significant
|
||||
+ * to the filesystem on the current platform.
|
||||
+ * @param name The string to convert, assumed to be a filesystem path
|
||||
*/
|
||||
AP_DECLARE(void) ap_no2slash(char *name);
|
||||
|
||||
+/**
|
||||
+ * Convert all double slashes to single slashes, except where significant
|
||||
+ * to the filesystem on the current platform.
|
||||
+ * @param name The string to convert
|
||||
+ * @param is_fs_path if set to 0, the significance of any double-slashes is
|
||||
+ * ignored.
|
||||
+ */
|
||||
+AP_DECLARE(void) ap_no2slash_ex(char *name, int is_fs_path);
|
||||
+
|
||||
/**
|
||||
* Remove all ./ and xx/../ substrings from a file name. Also remove
|
||||
* any leading ../ or /../ substrings.
|
||||
diff --git a/server/request.c b/server/request.c
|
||||
index dbe3e07..d5c558a 100644
|
||||
--- a/server/request.c
|
||||
+++ b/server/request.c
|
||||
@@ -167,6 +167,8 @@ AP_DECLARE(int) ap_process_request_internal(request_rec *r)
|
||||
int file_req = (r->main && r->filename);
|
||||
int access_status;
|
||||
core_dir_config *d;
|
||||
+ core_server_config *sconf =
|
||||
+ ap_get_core_module_config(r->server->module_config);
|
||||
|
||||
/* Ignore embedded %2F's in path for proxy requests */
|
||||
if (!r->proxyreq && r->parsed_uri.path) {
|
||||
@@ -191,6 +193,12 @@ AP_DECLARE(int) ap_process_request_internal(request_rec *r)
|
||||
}
|
||||
|
||||
ap_getparents(r->uri); /* OK --- shrinking transformations... */
|
||||
+ if (sconf->merge_slashes != AP_CORE_CONFIG_OFF) {
|
||||
+ ap_no2slash(r->uri);
|
||||
+ if (r->parsed_uri.path) {
|
||||
+ ap_no2slash(r->parsed_uri.path);
|
||||
+ }
|
||||
+ }
|
||||
|
||||
/* All file subrequests are a huge pain... they cannot bubble through the
|
||||
* next several steps. Only file subrequests are allowed an empty uri,
|
||||
@@ -1411,20 +1419,7 @@ AP_DECLARE(int) ap_location_walk(request_rec *r)
|
||||
|
||||
cache = prep_walk_cache(AP_NOTE_LOCATION_WALK, r);
|
||||
cached = (cache->cached != NULL);
|
||||
-
|
||||
- /* Location and LocationMatch differ on their behaviour w.r.t. multiple
|
||||
- * slashes. Location matches multiple slashes with a single slash,
|
||||
- * LocationMatch doesn't. An exception, for backwards brokenness is
|
||||
- * absoluteURIs... in which case neither match multiple slashes.
|
||||
- */
|
||||
- if (r->uri[0] != '/') {
|
||||
- entry_uri = r->uri;
|
||||
- }
|
||||
- else {
|
||||
- char *uri = apr_pstrdup(r->pool, r->uri);
|
||||
- ap_no2slash(uri);
|
||||
- entry_uri = uri;
|
||||
- }
|
||||
+ entry_uri = r->uri;
|
||||
|
||||
/* If we have an cache->cached location that matches r->uri,
|
||||
* and the vhost's list of locations hasn't changed, we can skip
|
||||
@@ -1491,7 +1486,7 @@ AP_DECLARE(int) ap_location_walk(request_rec *r)
|
||||
pmatch = apr_palloc(rxpool, nmatch*sizeof(ap_regmatch_t));
|
||||
}
|
||||
|
||||
- if (ap_regexec(entry_core->r, r->uri, nmatch, pmatch, 0)) {
|
||||
+ if (ap_regexec(entry_core->r, entry_uri, nmatch, pmatch, 0)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1501,7 +1496,7 @@ AP_DECLARE(int) ap_location_walk(request_rec *r)
|
||||
apr_table_setn(r->subprocess_env,
|
||||
((const char **)entry_core->refs->elts)[i],
|
||||
apr_pstrndup(r->pool,
|
||||
- r->uri + pmatch[i].rm_so,
|
||||
+ entry_uri + pmatch[i].rm_so,
|
||||
pmatch[i].rm_eo - pmatch[i].rm_so));
|
||||
}
|
||||
}
|
||||
diff --git a/server/util.c b/server/util.c
|
||||
index fd7a0a1..e0c558c 100644
|
||||
--- a/server/util.c
|
||||
+++ b/server/util.c
|
||||
@@ -561,16 +561,20 @@ AP_DECLARE(void) ap_getparents(char *name)
|
||||
name[l] = '\0';
|
||||
}
|
||||
}
|
||||
-
|
||||
-AP_DECLARE(void) ap_no2slash(char *name)
|
||||
+AP_DECLARE(void) ap_no2slash_ex(char *name, int is_fs_path)
|
||||
{
|
||||
+
|
||||
char *d, *s;
|
||||
|
||||
+ if (!*name) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
s = d = name;
|
||||
|
||||
#ifdef HAVE_UNC_PATHS
|
||||
/* Check for UNC names. Leave leading two slashes. */
|
||||
- if (s[0] == '/' && s[1] == '/')
|
||||
+ if (is_fs_path && s[0] == '/' && s[1] == '/')
|
||||
*d++ = *s++;
|
||||
#endif
|
||||
|
||||
@@ -587,6 +591,10 @@ AP_DECLARE(void) ap_no2slash(char *name)
|
||||
*d = '\0';
|
||||
}
|
||||
|
||||
+AP_DECLARE(void) ap_no2slash(char *name)
|
||||
+{
|
||||
+ ap_no2slash_ex(name, 1);
|
||||
+}
|
||||
|
||||
/*
|
||||
* copy at most n leading directories of s into d
|
||||
diff --git a/server/core.c b/server/core.c
|
||||
index b5ab429..a31f1e4 100644
|
||||
--- a/server/core.c
|
||||
+++ b/server/core.c
|
||||
@@ -493,6 +493,7 @@ static void *create_core_server_config(apr_pool_t *a, server_rec *s)
|
||||
*/
|
||||
|
||||
conf->trace_enable = AP_TRACE_UNSET;
|
||||
+ conf->merge_slashes = AP_CORE_CONFIG_UNSET;
|
||||
|
||||
conf->protocols = apr_array_make(a, 5, sizeof(const char *));
|
||||
conf->protocols_honor_order = -1;
|
||||
@@ -561,7 +562,9 @@ static void *merge_core_server_configs(apr_pool_t *p, void *basev, void *virtv)
|
||||
conf->protocols_honor_order = ((virt->protocols_honor_order < 0)?
|
||||
base->protocols_honor_order :
|
||||
virt->protocols_honor_order);
|
||||
-
|
||||
+
|
||||
+ AP_CORE_MERGE_FLAG(merge_slashes, conf, base, virt);
|
||||
+
|
||||
return conf;
|
||||
}
|
||||
|
||||
@@ -1872,6 +1875,13 @@ static const char *set_qualify_redirect_url(cmd_parms *cmd, void *d_, int flag)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+static const char *set_core_server_flag(cmd_parms *cmd, void *s_, int flag)
|
||||
+{
|
||||
+ core_server_config *conf =
|
||||
+ ap_get_core_module_config(cmd->server->module_config);
|
||||
+ return ap_set_flag_slot(cmd, conf, flag);
|
||||
+}
|
||||
+
|
||||
static const char *set_override_list(cmd_parms *cmd, void *d_, int argc, char *const argv[])
|
||||
{
|
||||
core_dir_config *d = d_;
|
||||
@@ -4598,6 +4608,10 @@ AP_INIT_ITERATE("HttpProtocolOptions", set_http_protocol_options, NULL, RSRC_CON
|
||||
"'Unsafe' or 'Strict' (default). Sets HTTP acceptance rules"),
|
||||
AP_INIT_ITERATE("RegisterHttpMethod", set_http_method, NULL, RSRC_CONF,
|
||||
"Registers non-standard HTTP methods"),
|
||||
+AP_INIT_FLAG("MergeSlashes", set_core_server_flag,
|
||||
+ (void *)APR_OFFSETOF(core_server_config, merge_slashes),
|
||||
+ RSRC_CONF,
|
||||
+ "Controls whether consecutive slashes in the URI path are merged"),
|
||||
{ NULL }
|
||||
};
|
||||
|
@ -1,192 +0,0 @@
|
||||
diff --git a/modules/http/http_protocol.c b/modules/http/http_protocol.c
|
||||
index e419eb6..dcafa9c 100644
|
||||
--- a/modules/http/http_protocol.c
|
||||
+++ b/modules/http/http_protocol.c
|
||||
@@ -1132,13 +1132,10 @@ static const char *get_canned_error_string(int status,
|
||||
"\">here</a>.</p>\n",
|
||||
NULL));
|
||||
case HTTP_USE_PROXY:
|
||||
- return(apr_pstrcat(p,
|
||||
- "<p>This resource is only accessible "
|
||||
- "through the proxy\n",
|
||||
- ap_escape_html(r->pool, location),
|
||||
- "<br />\nYou will need to configure "
|
||||
- "your client to use that proxy.</p>\n",
|
||||
- NULL));
|
||||
+ return("<p>This resource is only accessible "
|
||||
+ "through the proxy\n"
|
||||
+ "<br />\nYou will need to configure "
|
||||
+ "your client to use that proxy.</p>\n");
|
||||
case HTTP_PROXY_AUTHENTICATION_REQUIRED:
|
||||
case HTTP_UNAUTHORIZED:
|
||||
return("<p>This server could not verify that you\n"
|
||||
@@ -1154,34 +1151,20 @@ static const char *get_canned_error_string(int status,
|
||||
"error-notes",
|
||||
"</p>\n"));
|
||||
case HTTP_FORBIDDEN:
|
||||
- s1 = apr_pstrcat(p,
|
||||
- "<p>You don't have permission to access ",
|
||||
- ap_escape_html(r->pool, r->uri),
|
||||
- "\non this server.<br />\n",
|
||||
- NULL);
|
||||
- return(add_optional_notes(r, s1, "error-notes", "</p>\n"));
|
||||
+ return(add_optional_notes(r, "<p>You don't have permission to access this resource.", "error-notes", "</p>\n"));
|
||||
case HTTP_NOT_FOUND:
|
||||
- return(apr_pstrcat(p,
|
||||
- "<p>The requested URL ",
|
||||
- ap_escape_html(r->pool, r->uri),
|
||||
- " was not found on this server.</p>\n",
|
||||
- NULL));
|
||||
+ return("<p>The requested URL was not found on this server.</p>\n");
|
||||
case HTTP_METHOD_NOT_ALLOWED:
|
||||
return(apr_pstrcat(p,
|
||||
"<p>The requested method ",
|
||||
ap_escape_html(r->pool, r->method),
|
||||
- " is not allowed for the URL ",
|
||||
- ap_escape_html(r->pool, r->uri),
|
||||
- ".</p>\n",
|
||||
+ " is not allowed for this URL.</p>\n",
|
||||
NULL));
|
||||
case HTTP_NOT_ACCEPTABLE:
|
||||
- s1 = apr_pstrcat(p,
|
||||
- "<p>An appropriate representation of the "
|
||||
- "requested resource ",
|
||||
- ap_escape_html(r->pool, r->uri),
|
||||
- " could not be found on this server.</p>\n",
|
||||
- NULL);
|
||||
- return(add_optional_notes(r, s1, "variant-list", ""));
|
||||
+ return(add_optional_notes(r,
|
||||
+ "<p>An appropriate representation of the requested resource "
|
||||
+ "could not be found on this server.</p>\n",
|
||||
+ "variant-list", ""));
|
||||
case HTTP_MULTIPLE_CHOICES:
|
||||
return(add_optional_notes(r, "", "variant-list", ""));
|
||||
case HTTP_LENGTH_REQUIRED:
|
||||
@@ -1192,18 +1175,13 @@ static const char *get_canned_error_string(int status,
|
||||
NULL);
|
||||
return(add_optional_notes(r, s1, "error-notes", "</p>\n"));
|
||||
case HTTP_PRECONDITION_FAILED:
|
||||
- return(apr_pstrcat(p,
|
||||
- "<p>The precondition on the request "
|
||||
- "for the URL ",
|
||||
- ap_escape_html(r->pool, r->uri),
|
||||
- " evaluated to false.</p>\n",
|
||||
- NULL));
|
||||
+ return("<p>The precondition on the request "
|
||||
+ "for this URL evaluated to false.</p>\n");
|
||||
case HTTP_NOT_IMPLEMENTED:
|
||||
s1 = apr_pstrcat(p,
|
||||
"<p>",
|
||||
- ap_escape_html(r->pool, r->method), " to ",
|
||||
- ap_escape_html(r->pool, r->uri),
|
||||
- " not supported.<br />\n",
|
||||
+ ap_escape_html(r->pool, r->method), " ",
|
||||
+ " not supported for current URL.<br />\n",
|
||||
NULL);
|
||||
return(add_optional_notes(r, s1, "error-notes", "</p>\n"));
|
||||
case HTTP_BAD_GATEWAY:
|
||||
@@ -1211,29 +1189,19 @@ static const char *get_canned_error_string(int status,
|
||||
"response from an upstream server.<br />" CRLF;
|
||||
return(add_optional_notes(r, s1, "error-notes", "</p>\n"));
|
||||
case HTTP_VARIANT_ALSO_VARIES:
|
||||
- return(apr_pstrcat(p,
|
||||
- "<p>A variant for the requested "
|
||||
- "resource\n<pre>\n",
|
||||
- ap_escape_html(r->pool, r->uri),
|
||||
- "\n</pre>\nis itself a negotiable resource. "
|
||||
- "This indicates a configuration error.</p>\n",
|
||||
- NULL));
|
||||
+ return("<p>A variant for the requested "
|
||||
+ "resource\n<pre>\n"
|
||||
+ "\n</pre>\nis itself a negotiable resource. "
|
||||
+ "This indicates a configuration error.</p>\n");
|
||||
case HTTP_REQUEST_TIME_OUT:
|
||||
return("<p>Server timeout waiting for the HTTP request from the client.</p>\n");
|
||||
case HTTP_GONE:
|
||||
- return(apr_pstrcat(p,
|
||||
- "<p>The requested resource<br />",
|
||||
- ap_escape_html(r->pool, r->uri),
|
||||
- "<br />\nis no longer available on this server "
|
||||
- "and there is no forwarding address.\n"
|
||||
- "Please remove all references to this "
|
||||
- "resource.</p>\n",
|
||||
- NULL));
|
||||
+ return("<p>The requested resource is no longer available on this server"
|
||||
+ " and there is no forwarding address.\n"
|
||||
+ "Please remove all references to this resource.</p>\n");
|
||||
case HTTP_REQUEST_ENTITY_TOO_LARGE:
|
||||
return(apr_pstrcat(p,
|
||||
- "The requested resource<br />",
|
||||
- ap_escape_html(r->pool, r->uri), "<br />\n",
|
||||
- "does not allow request data with ",
|
||||
+ "The requested resource does not allow request data with ",
|
||||
ap_escape_html(r->pool, r->method),
|
||||
" requests, or the amount of data provided in\n"
|
||||
"the request exceeds the capacity limit.\n",
|
||||
@@ -1317,11 +1285,9 @@ static const char *get_canned_error_string(int status,
|
||||
"the Server Name Indication (SNI) in use for this\n"
|
||||
"connection.</p>\n");
|
||||
case HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
|
||||
- s1 = apr_pstrcat(p,
|
||||
- "<p>Access to ", ap_escape_html(r->pool, r->uri),
|
||||
- "\nhas been denied for legal reasons.<br />\n",
|
||||
- NULL);
|
||||
- return(add_optional_notes(r, s1, "error-notes", "</p>\n"));
|
||||
+ return(add_optional_notes(r,
|
||||
+ "<p>Access to this URL has been denied for legal reasons.<br />\n",
|
||||
+ "error-notes", "</p>\n"));
|
||||
default: /* HTTP_INTERNAL_SERVER_ERROR */
|
||||
/*
|
||||
* This comparison to expose error-notes could be modified to
|
||||
diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c
|
||||
index 800ede1..de48735 100644
|
||||
--- a/modules/proxy/mod_proxy.c
|
||||
+++ b/modules/proxy/mod_proxy.c
|
||||
@@ -1055,9 +1055,10 @@ static int proxy_handler(request_rec *r)
|
||||
char *end;
|
||||
maxfwd = apr_strtoi64(str, &end, 10);
|
||||
if (maxfwd < 0 || maxfwd == APR_INT64_MAX || *end) {
|
||||
- return ap_proxyerror(r, HTTP_BAD_REQUEST,
|
||||
- apr_psprintf(r->pool,
|
||||
- "Max-Forwards value '%s' could not be parsed", str));
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO()
|
||||
+ "Max-Forwards value '%s' could not be parsed", str);
|
||||
+ return ap_proxyerror(r, HTTP_BAD_REQUEST,
|
||||
+ "Max-Forwards request header could not be parsed");
|
||||
}
|
||||
else if (maxfwd == 0) {
|
||||
switch (r->method_number) {
|
||||
diff --git a/modules/proxy/mod_proxy_ftp.c b/modules/proxy/mod_proxy_ftp.c
|
||||
index 4a10987..8f6f853 100644
|
||||
--- a/modules/proxy/mod_proxy_ftp.c
|
||||
+++ b/modules/proxy/mod_proxy_ftp.c
|
||||
@@ -1024,8 +1024,9 @@ static int proxy_ftp_handler(request_rec *r, proxy_worker *worker,
|
||||
/* We break the URL into host, port, path-search */
|
||||
if (r->parsed_uri.hostname == NULL) {
|
||||
if (APR_SUCCESS != apr_uri_parse(p, url, &uri)) {
|
||||
- return ap_proxyerror(r, HTTP_BAD_REQUEST,
|
||||
- apr_psprintf(p, "URI cannot be parsed: %s", url));
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO()
|
||||
+ "URI cannot be parsed: %s", url);
|
||||
+ return ap_proxyerror(r, HTTP_BAD_REQUEST, "URI cannot be parsed");
|
||||
}
|
||||
connectname = uri.hostname;
|
||||
connectport = uri.port;
|
||||
diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c
|
||||
index 6501c68..0bbfa59 100644
|
||||
--- a/modules/proxy/proxy_util.c
|
||||
+++ b/modules/proxy/proxy_util.c
|
||||
@@ -368,12 +368,9 @@ PROXY_DECLARE(char *)
|
||||
|
||||
PROXY_DECLARE(int) ap_proxyerror(request_rec *r, int statuscode, const char *message)
|
||||
{
|
||||
- const char *uri = ap_escape_html(r->pool, r->uri);
|
||||
apr_table_setn(r->notes, "error-notes",
|
||||
apr_pstrcat(r->pool,
|
||||
- "The proxy server could not handle the request <em><a href=\"",
|
||||
- uri, "\">", ap_escape_html(r->pool, r->method), " ", uri,
|
||||
- "</a></em>.<p>\n"
|
||||
+ "The proxy server could not handle the request<p>"
|
||||
"Reason: <strong>", ap_escape_html(r->pool, message),
|
||||
"</strong></p>",
|
||||
NULL));
|
@ -1,66 +0,0 @@
|
||||
diff --git a/modules/metadata/mod_remoteip.c b/modules/metadata/mod_remoteip.c
|
||||
index 4572ce1..a0cbc0f 100644
|
||||
--- a/modules/metadata/mod_remoteip.c
|
||||
+++ b/modules/metadata/mod_remoteip.c
|
||||
@@ -987,15 +987,13 @@ static remoteip_parse_status_t remoteip_process_v2_header(conn_rec *c,
|
||||
return HDR_ERROR;
|
||||
#endif
|
||||
default:
|
||||
- /* unsupported protocol, keep local connection address */
|
||||
- return HDR_DONE;
|
||||
+ /* unsupported protocol */
|
||||
+ ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(10183)
|
||||
+ "RemoteIPProxyProtocol: unsupported protocol %.2hx",
|
||||
+ (unsigned short)hdr->v2.fam);
|
||||
+ return HDR_ERROR;
|
||||
}
|
||||
break; /* we got a sockaddr now */
|
||||
-
|
||||
- case 0x00: /* LOCAL command */
|
||||
- /* keep local connection address for LOCAL */
|
||||
- return HDR_DONE;
|
||||
-
|
||||
default:
|
||||
/* not a supported command */
|
||||
ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(03507)
|
||||
@@ -1087,11 +1085,24 @@ static apr_status_t remoteip_input_filter(ap_filter_t *f,
|
||||
/* try to read a header's worth of data */
|
||||
while (!ctx->done) {
|
||||
if (APR_BRIGADE_EMPTY(ctx->bb)) {
|
||||
- ret = ap_get_brigade(f->next, ctx->bb, ctx->mode, block,
|
||||
- ctx->need - ctx->rcvd);
|
||||
+ apr_off_t got, want = ctx->need - ctx->rcvd;
|
||||
+
|
||||
+ ret = ap_get_brigade(f->next, ctx->bb, ctx->mode, block, want);
|
||||
if (ret != APR_SUCCESS) {
|
||||
+ ap_log_cerror(APLOG_MARK, APLOG_ERR, ret, f->c, APLOGNO(10184)
|
||||
+ "failed reading input");
|
||||
return ret;
|
||||
}
|
||||
+
|
||||
+ ret = apr_brigade_length(ctx->bb, 1, &got);
|
||||
+ if (ret || got > want) {
|
||||
+ ap_log_cerror(APLOG_MARK, APLOG_ERR, ret, f->c, APLOGNO(10185)
|
||||
+ "RemoteIPProxyProtocol header too long, "
|
||||
+ "got %" APR_OFF_T_FMT " expected %" APR_OFF_T_FMT,
|
||||
+ got, want);
|
||||
+ f->c->aborted = 1;
|
||||
+ return APR_ECONNABORTED;
|
||||
+ }
|
||||
}
|
||||
if (APR_BRIGADE_EMPTY(ctx->bb)) {
|
||||
return block == APR_NONBLOCK_READ ? APR_SUCCESS : APR_EOF;
|
||||
@@ -1139,6 +1150,13 @@ static apr_status_t remoteip_input_filter(ap_filter_t *f,
|
||||
if (ctx->rcvd >= MIN_V2_HDR_LEN) {
|
||||
ctx->need = MIN_V2_HDR_LEN +
|
||||
remoteip_get_v2_len((proxy_header *) ctx->header);
|
||||
+ if (ctx->need > sizeof(proxy_v2)) {
|
||||
+ ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, f->c, APLOGNO(10186)
|
||||
+ "RemoteIPProxyProtocol protocol header length too long");
|
||||
+ f->c->aborted = 1;
|
||||
+ apr_brigade_destroy(ctx->bb);
|
||||
+ return APR_ECONNABORTED;
|
||||
+ }
|
||||
}
|
||||
if (ctx->rcvd >= ctx->need) {
|
||||
psts = remoteip_process_v2_header(f->c, conn_conf,
|
@ -1,91 +0,0 @@
|
||||
diff --git a/include/ap_regex.h b/include/ap_regex.h
|
||||
index 7d8df79..7af2f99 100644
|
||||
--- a/include/ap_regex.h
|
||||
+++ b/include/ap_regex.h
|
||||
@@ -84,7 +84,11 @@ extern "C" {
|
||||
|
||||
#define AP_REG_DOLLAR_ENDONLY 0x200 /* '$' matches at end of subject string only */
|
||||
|
||||
-#define AP_REG_MATCH "MATCH_" /** suggested prefix for ap_regname */
|
||||
+#define AP_REG_NO_DEFAULT 0x400 /**< Don't implicitely add AP_REG_DEFAULT options */
|
||||
+
|
||||
+#define AP_REG_MATCH "MATCH_" /**< suggested prefix for ap_regname */
|
||||
+
|
||||
+#define AP_REG_DEFAULT (AP_REG_DOTALL|AP_REG_DOLLAR_ENDONLY)
|
||||
|
||||
/* Error values: */
|
||||
enum {
|
||||
diff --git a/modules/filters/mod_substitute.c b/modules/filters/mod_substitute.c
|
||||
index b7d5296..e976c51 100644
|
||||
--- a/modules/filters/mod_substitute.c
|
||||
+++ b/modules/filters/mod_substitute.c
|
||||
@@ -667,8 +667,10 @@ static const char *set_pattern(cmd_parms *cmd, void *cfg, const char *line)
|
||||
|
||||
/* first see if we can compile the regex */
|
||||
if (!is_pattern) {
|
||||
- r = ap_pregcomp(cmd->pool, from, AP_REG_EXTENDED |
|
||||
- (ignore_case ? AP_REG_ICASE : 0));
|
||||
+ int flags = AP_REG_NO_DEFAULT
|
||||
+ | (ap_regcomp_get_default_cflags() & AP_REG_DOLLAR_ENDONLY)
|
||||
+ | (ignore_case ? AP_REG_ICASE : 0);
|
||||
+ r = ap_pregcomp(cmd->pool, from, flags);
|
||||
if (!r)
|
||||
return "Substitute could not compile regex";
|
||||
}
|
||||
diff --git a/server/core.c b/server/core.c
|
||||
index 76432ce..6d00777 100644
|
||||
--- a/server/core.c
|
||||
+++ b/server/core.c
|
||||
@@ -4973,7 +4973,7 @@ static int core_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptem
|
||||
init_config_defines(pconf);
|
||||
apr_pool_cleanup_register(pconf, NULL, reset_config, apr_pool_cleanup_null);
|
||||
|
||||
- ap_regcomp_set_default_cflags(AP_REG_DOLLAR_ENDONLY);
|
||||
+ ap_regcomp_set_default_cflags(AP_REG_DEFAULT);
|
||||
|
||||
mpm_common_pre_config(pconf);
|
||||
|
||||
diff --git a/server/util_pcre.c b/server/util_pcre.c
|
||||
index f2cb1bb..2a665c8 100644
|
||||
--- a/server/util_pcre.c
|
||||
+++ b/server/util_pcre.c
|
||||
@@ -120,7 +120,7 @@ AP_DECLARE(void) ap_regfree(ap_regex_t *preg)
|
||||
* Compile a regular expression *
|
||||
*************************************************/
|
||||
|
||||
-static int default_cflags = AP_REG_DOLLAR_ENDONLY;
|
||||
+static int default_cflags = AP_REG_DEFAULT;
|
||||
|
||||
AP_DECLARE(int) ap_regcomp_get_default_cflags(void)
|
||||
{
|
||||
@@ -168,7 +168,8 @@ AP_DECLARE(int) ap_regcomp(ap_regex_t * preg, const char *pattern, int cflags)
|
||||
int errcode = 0;
|
||||
int options = PCRE_DUPNAMES;
|
||||
|
||||
- cflags |= default_cflags;
|
||||
+ if ((cflags & AP_REG_NO_DEFAULT) == 0)
|
||||
+ cflags |= default_cflags;
|
||||
if ((cflags & AP_REG_ICASE) != 0)
|
||||
options |= PCRE_CASELESS;
|
||||
if ((cflags & AP_REG_NEWLINE) != 0)
|
||||
diff --git a/server/util_regex.c b/server/util_regex.c
|
||||
index 2a30d68..5405f8d 100644
|
||||
--- a/server/util_regex.c
|
||||
+++ b/server/util_regex.c
|
||||
@@ -94,6 +94,7 @@ AP_DECLARE(ap_rxplus_t*) ap_rxplus_compile(apr_pool_t *pool,
|
||||
}
|
||||
|
||||
/* anything after the current delimiter is flags */
|
||||
+ ret->flags = ap_regcomp_get_default_cflags() & AP_REG_DOLLAR_ENDONLY;
|
||||
while (*++endp) {
|
||||
switch (*endp) {
|
||||
case 'i': ret->flags |= AP_REG_ICASE; break;
|
||||
@@ -106,7 +107,7 @@ AP_DECLARE(ap_rxplus_t*) ap_rxplus_compile(apr_pool_t *pool,
|
||||
default: break; /* we should probably be stricter here */
|
||||
}
|
||||
}
|
||||
- if (ap_regcomp(&ret->rx, rxstr, ret->flags) == 0) {
|
||||
+ if (ap_regcomp(&ret->rx, rxstr, AP_REG_NO_DEFAULT | ret->flags) == 0) {
|
||||
apr_pool_cleanup_register(pool, &ret->rx, rxplus_cleanup,
|
||||
apr_pool_cleanup_null);
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
--- a/modules/proxy/mod_proxy_uwsgi.c 2020/07/24 09:31:46 1880250
|
||||
+++ b/modules/proxy/mod_proxy_uwsgi.c 2020/07/24 09:35:25 1880251
|
||||
@@ -136,7 +136,7 @@
|
||||
int j;
|
||||
|
||||
apr_size_t headerlen = 4;
|
||||
- apr_uint16_t pktsize, keylen, vallen;
|
||||
+ apr_size_t pktsize, keylen, vallen;
|
||||
const char *script_name;
|
||||
const char *path_info;
|
||||
const char *auth;
|
||||
@@ -178,6 +178,15 @@
|
||||
headerlen += 2 + strlen(env[j].key) + 2 + strlen(env[j].val);
|
||||
}
|
||||
|
||||
+ pktsize = headerlen - 4;
|
||||
+ if (pktsize > APR_UINT16_MAX) {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10259)
|
||||
+ "can't send headers to %s:%u: packet size too "
|
||||
+ "large (%" APR_SIZE_T_FMT ")",
|
||||
+ conn->hostname, conn->port, pktsize);
|
||||
+ return HTTP_INTERNAL_SERVER_ERROR;
|
||||
+ }
|
||||
+
|
||||
ptr = buf = apr_palloc(r->pool, headerlen);
|
||||
|
||||
ptr += 4;
|
||||
@@ -196,8 +205,6 @@
|
||||
ptr += vallen;
|
||||
}
|
||||
|
||||
- pktsize = headerlen - 4;
|
||||
-
|
||||
buf[0] = 0;
|
||||
buf[1] = (apr_byte_t) (pktsize & 0xff);
|
||||
buf[2] = (apr_byte_t) ((pktsize >> 8) & 0xff);
|
@ -1,12 +0,0 @@
|
||||
diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c
|
||||
index 5786ea8..7da9bde 100644
|
||||
--- a/modules/proxy/mod_proxy_http.c
|
||||
+++ b/modules/proxy/mod_proxy_http.c
|
||||
@@ -637,7 +637,6 @@ static int ap_proxy_http_prefetch(proxy_http_req_t *req,
|
||||
"chunked body with Content-Length (C-L ignored)",
|
||||
c->client_ip, c->remote_host ? c->remote_host: "");
|
||||
req->old_cl_val = NULL;
|
||||
- origin->keepalive = AP_CONN_CLOSE;
|
||||
p_conn->close = 1;
|
||||
}
|
||||
|
@ -1,68 +0,0 @@
|
||||
--- a/modules/proxy/mod_proxy_ftp.c 2020/02/07 17:01:07 1873744
|
||||
+++ b/modules/proxy/mod_proxy_ftp.c 2020/02/07 17:04:45 1873745
|
||||
@@ -218,7 +218,7 @@
|
||||
* (EBCDIC) machines either.
|
||||
*/
|
||||
static apr_status_t ftp_string_read(conn_rec *c, apr_bucket_brigade *bb,
|
||||
- char *buff, apr_size_t bufflen, int *eos)
|
||||
+ char *buff, apr_size_t bufflen, int *eos, apr_size_t *outlen)
|
||||
{
|
||||
apr_bucket *e;
|
||||
apr_status_t rv;
|
||||
@@ -230,6 +230,7 @@
|
||||
/* start with an empty string */
|
||||
buff[0] = 0;
|
||||
*eos = 0;
|
||||
+ *outlen = 0;
|
||||
|
||||
/* loop through each brigade */
|
||||
while (!found) {
|
||||
@@ -273,6 +274,7 @@
|
||||
if (len > 0) {
|
||||
memcpy(pos, response, len);
|
||||
pos += len;
|
||||
+ *outlen += len;
|
||||
}
|
||||
}
|
||||
apr_bucket_delete(e);
|
||||
@@ -385,28 +387,36 @@
|
||||
char buff[5];
|
||||
char *mb = msgbuf, *me = &msgbuf[msglen];
|
||||
apr_status_t rv;
|
||||
+ apr_size_t nread;
|
||||
+
|
||||
int eos;
|
||||
|
||||
- if (APR_SUCCESS != (rv = ftp_string_read(ftp_ctrl, bb, response, sizeof(response), &eos))) {
|
||||
+ if (APR_SUCCESS != (rv = ftp_string_read(ftp_ctrl, bb, response, sizeof(response), &eos, &nread))) {
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, APLOGNO(03233)
|
||||
"<%s", response);
|
||||
*/
|
||||
+ if (nread < 4) {
|
||||
+ ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, APLOGNO(10229) "Malformed FTP response '%s'", response);
|
||||
+ *mb = '\0';
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
if (!apr_isdigit(response[0]) || !apr_isdigit(response[1]) ||
|
||||
- !apr_isdigit(response[2]) || (response[3] != ' ' && response[3] != '-'))
|
||||
+ !apr_isdigit(response[2]) || (response[3] != ' ' && response[3] != '-'))
|
||||
status = 0;
|
||||
else
|
||||
status = 100 * response[0] + 10 * response[1] + response[2] - 111 * '0';
|
||||
|
||||
mb = apr_cpystrn(mb, response + 4, me - mb);
|
||||
|
||||
- if (response[3] == '-') {
|
||||
+ if (response[3] == '-') { /* multi-line reply "123-foo\nbar\n123 baz" */
|
||||
memcpy(buff, response, 3);
|
||||
buff[3] = ' ';
|
||||
do {
|
||||
- if (APR_SUCCESS != (rv = ftp_string_read(ftp_ctrl, bb, response, sizeof(response), &eos))) {
|
||||
+ if (APR_SUCCESS != (rv = ftp_string_read(ftp_ctrl, bb, response, sizeof(response), &eos, &nread))) {
|
||||
return -1;
|
||||
}
|
||||
mb = apr_cpystrn(mb, response + (' ' == response[0] ? 1 : 4), me - mb);
|
@ -1,21 +0,0 @@
|
||||
diff --git a/modules/aaa/mod_auth_digest.c b/modules/aaa/mod_auth_digest.c
|
||||
index b760941..0825b1b 100644
|
||||
--- a/modules/aaa/mod_auth_digest.c
|
||||
+++ b/modules/aaa/mod_auth_digest.c
|
||||
@@ -1422,9 +1422,14 @@ static int check_nonce(request_rec *r, digest_header_rec *resp,
|
||||
time_rec nonce_time;
|
||||
char tmp, hash[NONCE_HASH_LEN+1];
|
||||
|
||||
- if (strlen(resp->nonce) != NONCE_LEN) {
|
||||
+ /* Since the time part of the nonce is a base64 encoding of an
|
||||
+ * apr_time_t (8 bytes), it should end with a '=', fail early otherwise.
|
||||
+ */
|
||||
+ if (strlen(resp->nonce) != NONCE_LEN
|
||||
+ || resp->nonce[NONCE_TIME_LEN - 1] != '=') {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01775)
|
||||
- "invalid nonce %s received - length is not %d",
|
||||
+ "invalid nonce '%s' received - length is not %d "
|
||||
+ "or time encoding is incorrect",
|
||||
resp->nonce, NONCE_LEN);
|
||||
note_digest_auth_failure(r, conf, resp, 1);
|
||||
return HTTP_UNAUTHORIZED;
|
@ -1,14 +0,0 @@
|
||||
diff --git a/modules/session/mod_session.c b/modules/session/mod_session.c
|
||||
index 7ee477c..049255d 100644
|
||||
--- a/modules/session/mod_session.c
|
||||
+++ b/modules/session/mod_session.c
|
||||
@@ -404,8 +404,8 @@ static apr_status_t session_identity_decode(request_rec * r, session_rec * z)
|
||||
char *plast = NULL;
|
||||
const char *psep = "=";
|
||||
char *key = apr_strtok(pair, psep, &plast);
|
||||
- char *val = apr_strtok(NULL, psep, &plast);
|
||||
if (key && *key) {
|
||||
+ char *val = apr_strtok(NULL, sep, &plast);
|
||||
if (!val || !*val) {
|
||||
apr_table_unset(z->entries, key);
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
diff --git a/modules/session/mod_session.c b/modules/session/mod_session.c
|
||||
index 049255d..af70f6b 100644
|
||||
--- a/modules/session/mod_session.c
|
||||
+++ b/modules/session/mod_session.c
|
||||
@@ -317,7 +317,7 @@ static apr_status_t ap_session_set(request_rec * r, session_rec * z,
|
||||
static int identity_count(void *v, const char *key, const char *val)
|
||||
{
|
||||
int *count = v;
|
||||
- *count += strlen(key) * 3 + strlen(val) * 3 + 1;
|
||||
+ *count += strlen(key) * 3 + strlen(val) * 3 + 2;
|
||||
return 1;
|
||||
}
|
||||
|
@ -1,44 +0,0 @@
|
||||
diff --git a/server/request.c b/server/request.c
|
||||
index d5c558a..18625af 100644
|
||||
--- a/server/request.c
|
||||
+++ b/server/request.c
|
||||
@@ -1419,7 +1419,20 @@ AP_DECLARE(int) ap_location_walk(request_rec *r)
|
||||
|
||||
cache = prep_walk_cache(AP_NOTE_LOCATION_WALK, r);
|
||||
cached = (cache->cached != NULL);
|
||||
- entry_uri = r->uri;
|
||||
+
|
||||
+ /*
|
||||
+ * When merge_slashes is set to AP_CORE_CONFIG_OFF the slashes in r->uri
|
||||
+ * have not been merged. But for Location walks we always go with merged
|
||||
+ * slashes no matter what merge_slashes is set to.
|
||||
+ */
|
||||
+ if (sconf->merge_slashes != AP_CORE_CONFIG_OFF) {
|
||||
+ entry_uri = r->uri;
|
||||
+ }
|
||||
+ else {
|
||||
+ char *uri = apr_pstrdup(r->pool, r->uri);
|
||||
+ ap_no2slash(uri);
|
||||
+ entry_uri = uri;
|
||||
+ }
|
||||
|
||||
/* If we have an cache->cached location that matches r->uri,
|
||||
* and the vhost's list of locations hasn't changed, we can skip
|
||||
@@ -1486,7 +1499,7 @@ AP_DECLARE(int) ap_location_walk(request_rec *r)
|
||||
pmatch = apr_palloc(rxpool, nmatch*sizeof(ap_regmatch_t));
|
||||
}
|
||||
|
||||
- if (ap_regexec(entry_core->r, entry_uri, nmatch, pmatch, 0)) {
|
||||
+ if (ap_regexec(entry_core->r, r->uri, nmatch, pmatch, 0)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1496,7 +1509,7 @@ AP_DECLARE(int) ap_location_walk(request_rec *r)
|
||||
apr_table_setn(r->subprocess_env,
|
||||
((const char **)entry_core->refs->elts)[i],
|
||||
apr_pstrndup(r->pool,
|
||||
- entry_uri + pmatch[i].rm_so,
|
||||
+ r->uri + pmatch[i].rm_so,
|
||||
pmatch[i].rm_eo - pmatch[i].rm_so));
|
||||
}
|
||||
}
|
@ -1,706 +0,0 @@
|
||||
diff --git a/include/http_core.h b/include/http_core.h
|
||||
index 8e10988..3ba8069 100644
|
||||
--- a/include/http_core.h
|
||||
+++ b/include/http_core.h
|
||||
@@ -741,6 +741,7 @@ typedef struct {
|
||||
#define AP_HTTP_METHODS_REGISTERED 2
|
||||
char http_methods;
|
||||
unsigned int merge_slashes;
|
||||
+ unsigned int strict_host_check;
|
||||
} core_server_config;
|
||||
|
||||
/* for AddOutputFiltersByType in core.c */
|
||||
@@ -769,6 +770,11 @@ AP_DECLARE(void) ap_set_server_protocol(server_rec* s, const char* proto);
|
||||
typedef struct core_output_filter_ctx core_output_filter_ctx_t;
|
||||
typedef struct core_filter_ctx core_ctx_t;
|
||||
|
||||
+struct core_filter_ctx {
|
||||
+ apr_bucket_brigade *b;
|
||||
+ apr_bucket_brigade *tmpbb;
|
||||
+};
|
||||
+
|
||||
typedef struct core_net_rec {
|
||||
/** Connection to the client */
|
||||
apr_socket_t *client_socket;
|
||||
diff --git a/include/http_protocol.h b/include/http_protocol.h
|
||||
index 11c7b2d..e7abdd9 100644
|
||||
--- a/include/http_protocol.h
|
||||
+++ b/include/http_protocol.h
|
||||
@@ -53,6 +53,13 @@ AP_DECLARE_DATA extern ap_filter_rec_t *ap_old_write_func;
|
||||
* or control the ones that eventually do.
|
||||
*/
|
||||
|
||||
+/**
|
||||
+ * Read an empty request and set reasonable defaults.
|
||||
+ * @param c The current connection
|
||||
+ * @return The new request_rec
|
||||
+ */
|
||||
+AP_DECLARE(request_rec *) ap_create_request(conn_rec *c);
|
||||
+
|
||||
/**
|
||||
* Read a request and fill in the fields.
|
||||
* @param c The current connection
|
||||
@@ -60,6 +67,20 @@ AP_DECLARE_DATA extern ap_filter_rec_t *ap_old_write_func;
|
||||
*/
|
||||
request_rec *ap_read_request(conn_rec *c);
|
||||
|
||||
+/**
|
||||
+ * Parse and validate the request line.
|
||||
+ * @param r The current request
|
||||
+ * @return 1 on success, 0 on failure
|
||||
+ */
|
||||
+AP_DECLARE(int) ap_parse_request_line(request_rec *r);
|
||||
+
|
||||
+/**
|
||||
+ * Validate the request header and select vhost.
|
||||
+ * @param r The current request
|
||||
+ * @return 1 on success, 0 on failure
|
||||
+ */
|
||||
+AP_DECLARE(int) ap_check_request_header(request_rec *r);
|
||||
+
|
||||
/**
|
||||
* Read the mime-encoded headers.
|
||||
* @param r The current request
|
||||
diff --git a/include/http_vhost.h b/include/http_vhost.h
|
||||
index 473c9c7..d2d9c97 100644
|
||||
--- a/include/http_vhost.h
|
||||
+++ b/include/http_vhost.h
|
||||
@@ -99,6 +99,19 @@ AP_DECLARE(void) ap_update_vhost_given_ip(conn_rec *conn);
|
||||
*/
|
||||
AP_DECLARE(void) ap_update_vhost_from_headers(request_rec *r);
|
||||
|
||||
+/**
|
||||
+ * Updates r->server with the best name-based virtual host match, within
|
||||
+ * the chain of matching virtual hosts selected by ap_update_vhost_given_ip.
|
||||
+ * @param r The current request
|
||||
+ * @param require_match 1 to return an HTTP error if the requested hostname is
|
||||
+ * not explicitly matched to a VirtualHost.
|
||||
+ * @return return HTTP_OK unless require_match was specified and the requested
|
||||
+ * hostname did not match any ServerName, ServerAlias, or VirtualHost
|
||||
+ * address-spec.
|
||||
+ */
|
||||
+AP_DECLARE(int) ap_update_vhost_from_headers_ex(request_rec *r, int require_match);
|
||||
+
|
||||
+
|
||||
/**
|
||||
* Match the host in the header with the hostname of the server for this
|
||||
* request.
|
||||
diff --git a/server/core.c b/server/core.c
|
||||
index 84e80f2..23abf57 100644
|
||||
--- a/server/core.c
|
||||
+++ b/server/core.c
|
||||
@@ -498,6 +498,8 @@ static void *create_core_server_config(apr_pool_t *a, server_rec *s)
|
||||
conf->protocols = apr_array_make(a, 5, sizeof(const char *));
|
||||
conf->protocols_honor_order = -1;
|
||||
|
||||
+ conf->strict_host_check= AP_CORE_CONFIG_UNSET;
|
||||
+
|
||||
return (void *)conf;
|
||||
}
|
||||
|
||||
@@ -565,6 +567,12 @@ static void *merge_core_server_configs(apr_pool_t *p, void *basev, void *virtv)
|
||||
|
||||
AP_CORE_MERGE_FLAG(merge_slashes, conf, base, virt);
|
||||
|
||||
+ conf->strict_host_check = (virt->strict_host_check != AP_CORE_CONFIG_UNSET)
|
||||
+ ? virt->strict_host_check
|
||||
+ : base->strict_host_check;
|
||||
+
|
||||
+ AP_CORE_MERGE_FLAG(strict_host_check, conf, base, virt);
|
||||
+
|
||||
return conf;
|
||||
}
|
||||
|
||||
@@ -4546,7 +4554,10 @@ AP_INIT_TAKE2("CGIVar", set_cgi_var, NULL, OR_FILEINFO,
|
||||
AP_INIT_FLAG("QualifyRedirectURL", set_qualify_redirect_url, NULL, OR_FILEINFO,
|
||||
"Controls whether HTTP authorization headers, normally hidden, will "
|
||||
"be passed to scripts"),
|
||||
-
|
||||
+AP_INIT_FLAG("StrictHostCheck", set_core_server_flag,
|
||||
+ (void *)APR_OFFSETOF(core_server_config, strict_host_check),
|
||||
+ RSRC_CONF,
|
||||
+ "Controls whether a hostname match is required"),
|
||||
AP_INIT_TAKE1("ForceType", ap_set_string_slot_lower,
|
||||
(void *)APR_OFFSETOF(core_dir_config, mime_type), OR_FILEINFO,
|
||||
"a mime type that overrides other configured type"),
|
||||
@@ -5581,4 +5592,3 @@ AP_DECLARE_MODULE(core) = {
|
||||
core_cmds, /* command apr_table_t */
|
||||
register_hooks /* register hooks */
|
||||
};
|
||||
-
|
||||
diff --git a/server/core_filters.c b/server/core_filters.c
|
||||
index a6c2bd6..e08801f 100644
|
||||
--- a/server/core_filters.c
|
||||
+++ b/server/core_filters.c
|
||||
@@ -84,11 +84,6 @@ struct core_output_filter_ctx {
|
||||
apr_size_t bytes_written;
|
||||
};
|
||||
|
||||
-struct core_filter_ctx {
|
||||
- apr_bucket_brigade *b;
|
||||
- apr_bucket_brigade *tmpbb;
|
||||
-};
|
||||
-
|
||||
|
||||
apr_status_t ap_core_input_filter(ap_filter_t *f, apr_bucket_brigade *b,
|
||||
ap_input_mode_t mode, apr_read_type_e block,
|
||||
diff --git a/server/protocol.c b/server/protocol.c
|
||||
index 8d1fdd2..430d91e 100644
|
||||
--- a/server/protocol.c
|
||||
+++ b/server/protocol.c
|
||||
@@ -609,8 +609,15 @@ AP_CORE_DECLARE(void) ap_parse_uri(request_rec *r, const char *uri)
|
||||
}
|
||||
|
||||
r->args = r->parsed_uri.query;
|
||||
- r->uri = r->parsed_uri.path ? r->parsed_uri.path
|
||||
- : apr_pstrdup(r->pool, "/");
|
||||
+ if (r->parsed_uri.path) {
|
||||
+ r->uri = r->parsed_uri.path;
|
||||
+ }
|
||||
+ else if (r->method_number == M_OPTIONS) {
|
||||
+ r->uri = apr_pstrdup(r->pool, "*");
|
||||
+ }
|
||||
+ else {
|
||||
+ r->uri = apr_pstrdup(r->pool, "/");
|
||||
+ }
|
||||
|
||||
#if defined(OS2) || defined(WIN32)
|
||||
/* Handle path translations for OS/2 and plug security hole.
|
||||
@@ -645,13 +652,6 @@ static int field_name_len(const char *field)
|
||||
|
||||
static int read_request_line(request_rec *r, apr_bucket_brigade *bb)
|
||||
{
|
||||
- enum {
|
||||
- rrl_none, rrl_badmethod, rrl_badwhitespace, rrl_excesswhitespace,
|
||||
- rrl_missinguri, rrl_baduri, rrl_badprotocol, rrl_trailingtext,
|
||||
- rrl_badmethod09, rrl_reject09
|
||||
- } deferred_error = rrl_none;
|
||||
- char *ll;
|
||||
- char *uri;
|
||||
apr_size_t len;
|
||||
int num_blank_lines = DEFAULT_LIMIT_BLANK_LINES;
|
||||
core_server_config *conf = ap_get_core_module_config(r->server->module_config);
|
||||
@@ -711,6 +711,20 @@ static int read_request_line(request_rec *r, apr_bucket_brigade *bb)
|
||||
}
|
||||
|
||||
r->request_time = apr_time_now();
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+AP_DECLARE(int) ap_parse_request_line(request_rec *r)
|
||||
+{
|
||||
+ core_server_config *conf = ap_get_core_module_config(r->server->module_config);
|
||||
+ int strict = (conf->http_conformance != AP_HTTP_CONFORMANCE_UNSAFE);
|
||||
+ enum {
|
||||
+ rrl_none, rrl_badmethod, rrl_badwhitespace, rrl_excesswhitespace,
|
||||
+ rrl_missinguri, rrl_baduri, rrl_badprotocol, rrl_trailingtext,
|
||||
+ rrl_badmethod09, rrl_reject09
|
||||
+ } deferred_error = rrl_none;
|
||||
+ apr_size_t len = 0;
|
||||
+ char *uri, *ll;
|
||||
|
||||
r->method = r->the_request;
|
||||
|
||||
@@ -742,7 +756,6 @@ static int read_request_line(request_rec *r, apr_bucket_brigade *bb)
|
||||
if (deferred_error == rrl_none)
|
||||
deferred_error = rrl_missinguri;
|
||||
r->protocol = uri = "";
|
||||
- len = 0;
|
||||
goto rrl_done;
|
||||
}
|
||||
else if (strict && ll[0] && apr_isspace(ll[1])
|
||||
@@ -773,7 +786,6 @@ static int read_request_line(request_rec *r, apr_bucket_brigade *bb)
|
||||
/* Verify URI terminated with a single SP, or mark as specific error */
|
||||
if (!ll) {
|
||||
r->protocol = "";
|
||||
- len = 0;
|
||||
goto rrl_done;
|
||||
}
|
||||
else if (strict && ll[0] && apr_isspace(ll[1])
|
||||
@@ -866,6 +878,14 @@ rrl_done:
|
||||
r->header_only = 1;
|
||||
|
||||
ap_parse_uri(r, uri);
|
||||
+ if (r->status == HTTP_OK
|
||||
+ && (r->parsed_uri.path != NULL)
|
||||
+ && (r->parsed_uri.path[0] != '/')
|
||||
+ && (r->method_number != M_OPTIONS
|
||||
+ || strcmp(r->parsed_uri.path, "*") != 0)) {
|
||||
+ /* Invalid request-target per RFC 7230 section 5.3 */
|
||||
+ r->status = HTTP_BAD_REQUEST;
|
||||
+ }
|
||||
|
||||
/* With the request understood, we can consider HTTP/0.9 specific errors */
|
||||
if (r->proto_num == HTTP_VERSION(0, 9) && deferred_error == rrl_none) {
|
||||
@@ -973,6 +993,79 @@ rrl_failed:
|
||||
return 0;
|
||||
}
|
||||
|
||||
+AP_DECLARE(int) ap_check_request_header(request_rec *r)
|
||||
+{
|
||||
+ core_server_config *conf;
|
||||
+ int strict_host_check;
|
||||
+ const char *expect;
|
||||
+ int access_status;
|
||||
+
|
||||
+ conf = ap_get_core_module_config(r->server->module_config);
|
||||
+
|
||||
+ /* update what we think the virtual host is based on the headers we've
|
||||
+ * now read. may update status.
|
||||
+ */
|
||||
+ strict_host_check = (conf->strict_host_check == AP_CORE_CONFIG_ON);
|
||||
+ access_status = ap_update_vhost_from_headers_ex(r, strict_host_check);
|
||||
+ if (strict_host_check && access_status != HTTP_OK) {
|
||||
+ if (r->server == ap_server_conf) {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(10156)
|
||||
+ "Requested hostname '%s' did not match any ServerName/ServerAlias "
|
||||
+ "in the global server configuration ", r->hostname);
|
||||
+ }
|
||||
+ else {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(10157)
|
||||
+ "Requested hostname '%s' did not match any ServerName/ServerAlias "
|
||||
+ "in the matching virtual host (default vhost for "
|
||||
+ "current connection is %s:%u)",
|
||||
+ r->hostname, r->server->defn_name, r->server->defn_line_number);
|
||||
+ }
|
||||
+ r->status = access_status;
|
||||
+ }
|
||||
+ if (r->status != HTTP_OK) {
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ if ((!r->hostname && (r->proto_num >= HTTP_VERSION(1, 1)))
|
||||
+ || ((r->proto_num == HTTP_VERSION(1, 1))
|
||||
+ && !apr_table_get(r->headers_in, "Host"))) {
|
||||
+ /*
|
||||
+ * Client sent us an HTTP/1.1 or later request without telling us the
|
||||
+ * hostname, either with a full URL or a Host: header. We therefore
|
||||
+ * need to (as per the 1.1 spec) send an error. As a special case,
|
||||
+ * HTTP/1.1 mentions twice (S9, S14.23) that a request MUST contain
|
||||
+ * a Host: header, and the server MUST respond with 400 if it doesn't.
|
||||
+ */
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00569)
|
||||
+ "client sent HTTP/1.1 request without hostname "
|
||||
+ "(see RFC2616 section 14.23): %s", r->uri);
|
||||
+ r->status = HTTP_BAD_REQUEST;
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ if (((expect = apr_table_get(r->headers_in, "Expect")) != NULL)
|
||||
+ && (expect[0] != '\0')) {
|
||||
+ /*
|
||||
+ * The Expect header field was added to HTTP/1.1 after RFC 2068
|
||||
+ * as a means to signal when a 100 response is desired and,
|
||||
+ * unfortunately, to signal a poor man's mandatory extension that
|
||||
+ * the server must understand or return 417 Expectation Failed.
|
||||
+ */
|
||||
+ if (ap_cstr_casecmp(expect, "100-continue") == 0) {
|
||||
+ r->expecting_100 = 1;
|
||||
+ }
|
||||
+ else {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00570)
|
||||
+ "client sent an unrecognized expectation value "
|
||||
+ "of Expect: %s", expect);
|
||||
+ r->status = HTTP_EXPECTATION_FAILED;
|
||||
+ return 0;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
static int table_do_fn_check_lengths(void *r_, const char *key,
|
||||
const char *value)
|
||||
{
|
||||
@@ -1256,16 +1349,10 @@ AP_DECLARE(void) ap_get_mime_headers(request_rec *r)
|
||||
apr_brigade_destroy(tmp_bb);
|
||||
}
|
||||
|
||||
-request_rec *ap_read_request(conn_rec *conn)
|
||||
+AP_DECLARE(request_rec *) ap_create_request(conn_rec *conn)
|
||||
{
|
||||
request_rec *r;
|
||||
apr_pool_t *p;
|
||||
- const char *expect;
|
||||
- int access_status;
|
||||
- apr_bucket_brigade *tmp_bb;
|
||||
- apr_socket_t *csd;
|
||||
- apr_interval_time_t cur_timeout;
|
||||
-
|
||||
|
||||
apr_pool_create(&p, conn->pool);
|
||||
apr_pool_tag(p, "request");
|
||||
@@ -1304,6 +1391,7 @@ request_rec *ap_read_request(conn_rec *conn)
|
||||
r->read_body = REQUEST_NO_BODY;
|
||||
|
||||
r->status = HTTP_OK; /* Until further notice */
|
||||
+ r->header_only = 0;
|
||||
r->the_request = NULL;
|
||||
|
||||
/* Begin by presuming any module can make its own path_info assumptions,
|
||||
@@ -1314,12 +1402,33 @@ request_rec *ap_read_request(conn_rec *conn)
|
||||
r->useragent_addr = conn->client_addr;
|
||||
r->useragent_ip = conn->client_ip;
|
||||
|
||||
+ return r;
|
||||
+}
|
||||
+
|
||||
+/* Apply the server's timeout/config to the connection/request. */
|
||||
+static void apply_server_config(request_rec *r)
|
||||
+{
|
||||
+ apr_socket_t *csd;
|
||||
+
|
||||
+ csd = ap_get_conn_socket(r->connection);
|
||||
+ apr_socket_timeout_set(csd, r->server->timeout);
|
||||
+
|
||||
+ r->per_dir_config = r->server->lookup_defaults;
|
||||
+}
|
||||
+
|
||||
+request_rec *ap_read_request(conn_rec *conn)
|
||||
+{
|
||||
+ int access_status;
|
||||
+ apr_bucket_brigade *tmp_bb;
|
||||
+
|
||||
+ request_rec *r = ap_create_request(conn);
|
||||
tmp_bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
|
||||
|
||||
ap_run_pre_read_request(r, conn);
|
||||
|
||||
/* Get the request... */
|
||||
- if (!read_request_line(r, tmp_bb)) {
|
||||
+ if (!read_request_line(r, tmp_bb) || !ap_parse_request_line(r)) {
|
||||
+ apr_brigade_cleanup(tmp_bb);
|
||||
switch (r->status) {
|
||||
case HTTP_REQUEST_URI_TOO_LARGE:
|
||||
case HTTP_BAD_REQUEST:
|
||||
@@ -1335,49 +1444,38 @@ request_rec *ap_read_request(conn_rec *conn)
|
||||
"request failed: malformed request line");
|
||||
}
|
||||
access_status = r->status;
|
||||
- r->status = HTTP_OK;
|
||||
- ap_die(access_status, r);
|
||||
- ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r);
|
||||
- ap_run_log_transaction(r);
|
||||
- r = NULL;
|
||||
- apr_brigade_destroy(tmp_bb);
|
||||
- goto traceout;
|
||||
+ goto die_unusable_input;
|
||||
+
|
||||
case HTTP_REQUEST_TIME_OUT:
|
||||
+ /* Just log, no further action on this connection. */
|
||||
ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, NULL);
|
||||
if (!r->connection->keepalives)
|
||||
ap_run_log_transaction(r);
|
||||
- apr_brigade_destroy(tmp_bb);
|
||||
- goto traceout;
|
||||
- default:
|
||||
- apr_brigade_destroy(tmp_bb);
|
||||
- r = NULL;
|
||||
- goto traceout;
|
||||
+ break;
|
||||
}
|
||||
+ /* Not worth dying with. */
|
||||
+ conn->keepalive = AP_CONN_CLOSE;
|
||||
+ apr_pool_destroy(r->pool);
|
||||
+ goto ignore;
|
||||
}
|
||||
+ apr_brigade_cleanup(tmp_bb);
|
||||
|
||||
/* We may have been in keep_alive_timeout mode, so toggle back
|
||||
* to the normal timeout mode as we fetch the header lines,
|
||||
* as necessary.
|
||||
*/
|
||||
- csd = ap_get_conn_socket(conn);
|
||||
- apr_socket_timeout_get(csd, &cur_timeout);
|
||||
- if (cur_timeout != conn->base_server->timeout) {
|
||||
- apr_socket_timeout_set(csd, conn->base_server->timeout);
|
||||
- cur_timeout = conn->base_server->timeout;
|
||||
- }
|
||||
+ apply_server_config(r);
|
||||
|
||||
if (!r->assbackwards) {
|
||||
const char *tenc;
|
||||
|
||||
ap_get_mime_headers_core(r, tmp_bb);
|
||||
+ apr_brigade_cleanup(tmp_bb);
|
||||
if (r->status != HTTP_OK) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00567)
|
||||
"request failed: error reading the headers");
|
||||
- ap_send_error_response(r, 0);
|
||||
- ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r);
|
||||
- ap_run_log_transaction(r);
|
||||
- apr_brigade_destroy(tmp_bb);
|
||||
- goto traceout;
|
||||
+ access_status = r->status;
|
||||
+ goto die_unusable_input;
|
||||
}
|
||||
|
||||
tenc = apr_table_get(r->headers_in, "Transfer-Encoding");
|
||||
@@ -1393,13 +1491,8 @@ request_rec *ap_read_request(conn_rec *conn)
|
||||
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02539)
|
||||
"client sent unknown Transfer-Encoding "
|
||||
"(%s): %s", tenc, r->uri);
|
||||
- r->status = HTTP_BAD_REQUEST;
|
||||
- conn->keepalive = AP_CONN_CLOSE;
|
||||
- ap_send_error_response(r, 0);
|
||||
- ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r);
|
||||
- ap_run_log_transaction(r);
|
||||
- apr_brigade_destroy(tmp_bb);
|
||||
- goto traceout;
|
||||
+ access_status = HTTP_BAD_REQUEST;
|
||||
+ goto die_unusable_input;
|
||||
}
|
||||
|
||||
/* http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-23
|
||||
@@ -1412,88 +1505,81 @@ request_rec *ap_read_request(conn_rec *conn)
|
||||
}
|
||||
}
|
||||
|
||||
- apr_brigade_destroy(tmp_bb);
|
||||
-
|
||||
- /* update what we think the virtual host is based on the headers we've
|
||||
- * now read. may update status.
|
||||
- */
|
||||
- ap_update_vhost_from_headers(r);
|
||||
- access_status = r->status;
|
||||
-
|
||||
- /* Toggle to the Host:-based vhost's timeout mode to fetch the
|
||||
- * request body and send the response body, if needed.
|
||||
- */
|
||||
- if (cur_timeout != r->server->timeout) {
|
||||
- apr_socket_timeout_set(csd, r->server->timeout);
|
||||
- cur_timeout = r->server->timeout;
|
||||
- }
|
||||
-
|
||||
- /* we may have switched to another server */
|
||||
- r->per_dir_config = r->server->lookup_defaults;
|
||||
-
|
||||
- if ((!r->hostname && (r->proto_num >= HTTP_VERSION(1, 1)))
|
||||
- || ((r->proto_num == HTTP_VERSION(1, 1))
|
||||
- && !apr_table_get(r->headers_in, "Host"))) {
|
||||
- /*
|
||||
- * Client sent us an HTTP/1.1 or later request without telling us the
|
||||
- * hostname, either with a full URL or a Host: header. We therefore
|
||||
- * need to (as per the 1.1 spec) send an error. As a special case,
|
||||
- * HTTP/1.1 mentions twice (S9, S14.23) that a request MUST contain
|
||||
- * a Host: header, and the server MUST respond with 400 if it doesn't.
|
||||
- */
|
||||
- access_status = HTTP_BAD_REQUEST;
|
||||
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00569)
|
||||
- "client sent HTTP/1.1 request without hostname "
|
||||
- "(see RFC2616 section 14.23): %s", r->uri);
|
||||
- }
|
||||
-
|
||||
/*
|
||||
* Add the HTTP_IN filter here to ensure that ap_discard_request_body
|
||||
* called by ap_die and by ap_send_error_response works correctly on
|
||||
* status codes that do not cause the connection to be dropped and
|
||||
* in situations where the connection should be kept alive.
|
||||
*/
|
||||
-
|
||||
ap_add_input_filter_handle(ap_http_input_filter_handle,
|
||||
NULL, r, r->connection);
|
||||
|
||||
- if (access_status != HTTP_OK
|
||||
- || (access_status = ap_run_post_read_request(r))) {
|
||||
- ap_die(access_status, r);
|
||||
- ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r);
|
||||
- ap_run_log_transaction(r);
|
||||
- r = NULL;
|
||||
- goto traceout;
|
||||
+ /* Validate Host/Expect headers and select vhost. */
|
||||
+ if (!ap_check_request_header(r)) {
|
||||
+ /* we may have switched to another server still */
|
||||
+ apply_server_config(r);
|
||||
+ access_status = r->status;
|
||||
+ goto die_before_hooks;
|
||||
}
|
||||
|
||||
- if (((expect = apr_table_get(r->headers_in, "Expect")) != NULL)
|
||||
- && (expect[0] != '\0')) {
|
||||
- /*
|
||||
- * The Expect header field was added to HTTP/1.1 after RFC 2068
|
||||
- * as a means to signal when a 100 response is desired and,
|
||||
- * unfortunately, to signal a poor man's mandatory extension that
|
||||
- * the server must understand or return 417 Expectation Failed.
|
||||
- */
|
||||
- if (strcasecmp(expect, "100-continue") == 0) {
|
||||
- r->expecting_100 = 1;
|
||||
- }
|
||||
- else {
|
||||
- r->status = HTTP_EXPECTATION_FAILED;
|
||||
- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00570)
|
||||
- "client sent an unrecognized expectation value of "
|
||||
- "Expect: %s", expect);
|
||||
- ap_send_error_response(r, 0);
|
||||
- ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r);
|
||||
- ap_run_log_transaction(r);
|
||||
- goto traceout;
|
||||
- }
|
||||
+ /* we may have switched to another server */
|
||||
+ apply_server_config(r);
|
||||
+
|
||||
+ if ((access_status = ap_run_post_read_request(r))) {
|
||||
+ goto die;
|
||||
}
|
||||
|
||||
- AP_READ_REQUEST_SUCCESS((uintptr_t)r, (char *)r->method, (char *)r->uri, (char *)r->server->defn_name, r->status);
|
||||
+ AP_READ_REQUEST_SUCCESS((uintptr_t)r, (char *)r->method,
|
||||
+ (char *)r->uri, (char *)r->server->defn_name,
|
||||
+ r->status);
|
||||
+
|
||||
return r;
|
||||
- traceout:
|
||||
+
|
||||
+ /* Everything falls through on failure */
|
||||
+
|
||||
+die_unusable_input:
|
||||
+ /* Input filters are in an undeterminate state, cleanup (including
|
||||
+ * CORE_IN's socket) such that any further attempt to read is EOF.
|
||||
+ */
|
||||
+ {
|
||||
+ ap_filter_t *f = conn->input_filters;
|
||||
+ while (f) {
|
||||
+ if (f->frec == ap_core_input_filter_handle) {
|
||||
+ core_net_rec *net = f->ctx;
|
||||
+ apr_brigade_cleanup(net->in_ctx->b);
|
||||
+ break;
|
||||
+ }
|
||||
+ ap_remove_input_filter(f);
|
||||
+ f = f->next;
|
||||
+ }
|
||||
+ conn->input_filters = r->input_filters = f;
|
||||
+ conn->keepalive = AP_CONN_CLOSE;
|
||||
+ }
|
||||
+
|
||||
+die_before_hooks:
|
||||
+ /* First call to ap_die() (non recursive) */
|
||||
+ r->status = HTTP_OK;
|
||||
+
|
||||
+die:
|
||||
+ ap_die(access_status, r);
|
||||
+
|
||||
+ /* ap_die() sent the response through the output filters, we must now
|
||||
+ * end the request with an EOR bucket for stream/pipeline accounting.
|
||||
+ */
|
||||
+ {
|
||||
+ apr_bucket_brigade *eor_bb;
|
||||
+ eor_bb = apr_brigade_create(conn->pool, conn->bucket_alloc);
|
||||
+ APR_BRIGADE_INSERT_TAIL(eor_bb,
|
||||
+ ap_bucket_eor_create(conn->bucket_alloc, r));
|
||||
+ ap_pass_brigade(conn->output_filters, eor_bb);
|
||||
+ apr_brigade_cleanup(eor_bb);
|
||||
+ }
|
||||
+
|
||||
+ignore:
|
||||
+ r = NULL;
|
||||
+
|
||||
AP_READ_REQUEST_FAILURE((uintptr_t)r);
|
||||
- return r;
|
||||
+ return NULL;
|
||||
}
|
||||
|
||||
/* if a request with a body creates a subrequest, remove original request's
|
||||
diff --git a/server/vhost.c b/server/vhost.c
|
||||
index b23b2dd..6e233b5 100644
|
||||
--- a/server/vhost.c
|
||||
+++ b/server/vhost.c
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "http_vhost.h"
|
||||
#include "http_protocol.h"
|
||||
#include "http_core.h"
|
||||
+#include "http_main.h"
|
||||
|
||||
#if APR_HAVE_ARPA_INET_H
|
||||
#include <arpa/inet.h>
|
||||
@@ -973,7 +974,13 @@ AP_DECLARE(int) ap_matches_request_vhost(request_rec *r, const char *host,
|
||||
}
|
||||
|
||||
|
||||
-static void check_hostalias(request_rec *r)
|
||||
+/*
|
||||
+ * Updates r->server from ServerName/ServerAlias. Per the interaction
|
||||
+ * of ip and name-based vhosts, it only looks in the best match from the
|
||||
+ * connection-level ip-based matching.
|
||||
+ * Returns HTTP_BAD_REQUEST if there was no match.
|
||||
+ */
|
||||
+static int update_server_from_aliases(request_rec *r)
|
||||
{
|
||||
/*
|
||||
* Even if the request has a Host: header containing a port we ignore
|
||||
@@ -1050,11 +1057,18 @@ static void check_hostalias(request_rec *r)
|
||||
goto found;
|
||||
}
|
||||
|
||||
- return;
|
||||
+ if (!r->connection->vhost_lookup_data) {
|
||||
+ if (matches_aliases(r->server, host)) {
|
||||
+ s = r->server;
|
||||
+ goto found;
|
||||
+ }
|
||||
+ }
|
||||
+ return HTTP_BAD_REQUEST;
|
||||
|
||||
found:
|
||||
/* s is the first matching server, we're done */
|
||||
r->server = s;
|
||||
+ return HTTP_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -1071,7 +1085,7 @@ static void check_serverpath(request_rec *r)
|
||||
* This is in conjunction with the ServerPath code in http_core, so we
|
||||
* get the right host attached to a non- Host-sending request.
|
||||
*
|
||||
- * See the comment in check_hostalias about how each vhost can be
|
||||
+ * See the comment in update_server_from_aliases about how each vhost can be
|
||||
* listed multiple times.
|
||||
*/
|
||||
|
||||
@@ -1134,11 +1148,17 @@ static APR_INLINE const char *construct_host_header(request_rec *r,
|
||||
}
|
||||
|
||||
AP_DECLARE(void) ap_update_vhost_from_headers(request_rec *r)
|
||||
+{
|
||||
+ ap_update_vhost_from_headers_ex(r, 0);
|
||||
+}
|
||||
+
|
||||
+AP_DECLARE(int) ap_update_vhost_from_headers_ex(request_rec *r, int require_match)
|
||||
{
|
||||
core_server_config *conf = ap_get_core_module_config(r->server->module_config);
|
||||
const char *host_header = apr_table_get(r->headers_in, "Host");
|
||||
int is_v6literal = 0;
|
||||
int have_hostname_from_url = 0;
|
||||
+ int rc = HTTP_OK;
|
||||
|
||||
if (r->hostname) {
|
||||
/*
|
||||
@@ -1151,8 +1171,8 @@ AP_DECLARE(void) ap_update_vhost_from_headers(request_rec *r)
|
||||
else if (host_header != NULL) {
|
||||
is_v6literal = fix_hostname(r, host_header, conf->http_conformance);
|
||||
}
|
||||
- if (r->status != HTTP_OK)
|
||||
- return;
|
||||
+ if (!require_match && r->status != HTTP_OK)
|
||||
+ return HTTP_OK;
|
||||
|
||||
if (conf->http_conformance != AP_HTTP_CONFORMANCE_UNSAFE) {
|
||||
/*
|
||||
@@ -1173,10 +1193,16 @@ AP_DECLARE(void) ap_update_vhost_from_headers(request_rec *r)
|
||||
/* check if we tucked away a name_chain */
|
||||
if (r->connection->vhost_lookup_data) {
|
||||
if (r->hostname)
|
||||
- check_hostalias(r);
|
||||
+ rc = update_server_from_aliases(r);
|
||||
else
|
||||
check_serverpath(r);
|
||||
}
|
||||
+ else if (require_match && r->hostname) {
|
||||
+ /* check the base server config */
|
||||
+ rc = update_server_from_aliases(r);
|
||||
+ }
|
||||
+
|
||||
+ return rc;
|
||||
}
|
||||
|
||||
/**
|
@ -1,13 +0,0 @@
|
||||
diff --git a/server/scoreboard.c b/server/scoreboard.c
|
||||
index 23e3d70..7b01bdf 100644
|
||||
--- a/server/scoreboard.c
|
||||
+++ b/server/scoreboard.c
|
||||
@@ -376,7 +376,7 @@ AP_DECLARE(void) ap_increment_counts(ap_sb_handle_t *sb, request_rec *r)
|
||||
if (pfn_ap_logio_get_last_bytes != NULL) {
|
||||
bytes = pfn_ap_logio_get_last_bytes(r->connection);
|
||||
}
|
||||
- else if (r->method_number == M_GET && r->method[0] == 'H') {
|
||||
+ else if (r->method_number == M_GET && r->method && r->method[0] == 'H') {
|
||||
bytes = 0;
|
||||
}
|
||||
else {
|
@ -1,45 +0,0 @@
|
||||
diff --git a/modules/proxy/mod_proxy_uwsgi.c b/modules/proxy/mod_proxy_uwsgi.c
|
||||
index 792d35e..9dcbed1 100644
|
||||
--- a/modules/proxy/mod_proxy_uwsgi.c
|
||||
+++ b/modules/proxy/mod_proxy_uwsgi.c
|
||||
@@ -453,11 +453,8 @@ static int uwsgi_handler(request_rec *r, proxy_worker * worker,
|
||||
const char *proxyname, apr_port_t proxyport)
|
||||
{
|
||||
int status;
|
||||
- int delta = 0;
|
||||
- int decode_status;
|
||||
proxy_conn_rec *backend = NULL;
|
||||
apr_pool_t *p = r->pool;
|
||||
- size_t w_len;
|
||||
char server_portstr[32];
|
||||
char *u_path_info;
|
||||
apr_uri_t *uri;
|
||||
@@ -469,23 +466,14 @@ static int uwsgi_handler(request_rec *r, proxy_worker * worker,
|
||||
|
||||
uri = apr_palloc(r->pool, sizeof(*uri));
|
||||
|
||||
- /* ADD PATH_INFO */
|
||||
-#if AP_MODULE_MAGIC_AT_LEAST(20111130,0)
|
||||
- w_len = strlen(worker->s->name);
|
||||
-#else
|
||||
- w_len = strlen(worker->name);
|
||||
-#endif
|
||||
- u_path_info = r->filename + 6 + w_len;
|
||||
- if (u_path_info[0] != '/') {
|
||||
- delta = 1;
|
||||
- }
|
||||
- decode_status = ap_unescape_url(url + w_len - delta);
|
||||
- if (decode_status) {
|
||||
+ /* ADD PATH_INFO (unescaped) */
|
||||
+ u_path_info = ap_strchr(url + sizeof(UWSGI_SCHEME) + 2, '/');
|
||||
+ if (!u_path_info || ap_unescape_url(u_path_info) != OK) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10100)
|
||||
- "unable to decode uri: %s", url + w_len - delta);
|
||||
+ "unable to decode uwsgi uri: %s", url);
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
- apr_table_add(r->subprocess_env, "PATH_INFO", url + w_len - delta);
|
||||
+ apr_table_add(r->subprocess_env, "PATH_INFO", u_path_info);
|
||||
|
||||
|
||||
/* Create space for state information */
|
@ -1,21 +0,0 @@
|
||||
diff --git a/server/util.c b/server/util.c
|
||||
index e0c558c..2a5dd04 100644
|
||||
--- a/server/util.c
|
||||
+++ b/server/util.c
|
||||
@@ -2460,13 +2460,12 @@ AP_DECLARE(char *) ap_escape_quotes(apr_pool_t *p, const char *instring)
|
||||
* in front of every " that doesn't already have one.
|
||||
*/
|
||||
while (*inchr != '\0') {
|
||||
- if ((*inchr == '\\') && (inchr[1] != '\0')) {
|
||||
- *outchr++ = *inchr++;
|
||||
- *outchr++ = *inchr++;
|
||||
- }
|
||||
if (*inchr == '"') {
|
||||
*outchr++ = '\\';
|
||||
}
|
||||
+ if ((*inchr == '\\') && (inchr[1] != '\0')) {
|
||||
+ *outchr++ = *inchr++;
|
||||
+ }
|
||||
if (*inchr != '\0') {
|
||||
*outchr++ = *inchr++;
|
||||
}
|
@ -1,126 +0,0 @@
|
||||
diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c
|
||||
index fb897a9..38dbb24 100644
|
||||
--- a/modules/mappers/mod_rewrite.c
|
||||
+++ b/modules/mappers/mod_rewrite.c
|
||||
@@ -619,6 +619,13 @@ static unsigned is_absolute_uri(char *uri, int *supportsqs)
|
||||
return 6;
|
||||
}
|
||||
break;
|
||||
+
|
||||
+ case 'u':
|
||||
+ case 'U':
|
||||
+ if (!ap_cstr_casecmpn(uri, "nix:", 4)) { /* unix: */
|
||||
+ *sqs = 1;
|
||||
+ return (uri[4] == '/' && uri[5] == '/') ? 7 : 5;
|
||||
+ }
|
||||
}
|
||||
|
||||
return 0;
|
||||
diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c
|
||||
index f383996..6a9ef55 100644
|
||||
--- a/modules/proxy/mod_proxy.c
|
||||
+++ b/modules/proxy/mod_proxy.c
|
||||
@@ -1717,7 +1717,8 @@ PROXY_DECLARE(const char *) ap_proxy_de_socketfy(apr_pool_t *p, const char *url)
|
||||
* the UDS path... ignore it
|
||||
*/
|
||||
if (!strncasecmp(url, "unix:", 5) &&
|
||||
- ((ptr = ap_strchr_c(url, '|')) != NULL)) {
|
||||
+ ((ptr = ap_strchr_c(url + 5, '|')) != NULL)) {
|
||||
+
|
||||
/* move past the 'unix:...|' UDS path info */
|
||||
const char *ret, *c;
|
||||
|
||||
diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c
|
||||
index 7714b6c..3dd570c 100644
|
||||
--- a/modules/proxy/proxy_util.c
|
||||
+++ b/modules/proxy/proxy_util.c
|
||||
@@ -2084,33 +2084,45 @@ static int ap_proxy_retry_worker(const char *proxy_function, proxy_worker *worke
|
||||
* were passed a UDS url (eg: from mod_proxy) and adjust uds_path
|
||||
* as required.
|
||||
*/
|
||||
-static void fix_uds_filename(request_rec *r, char **url)
|
||||
+static int fix_uds_filename(request_rec *r, char **url)
|
||||
{
|
||||
- char *ptr, *ptr2;
|
||||
- if (!r || !r->filename) return;
|
||||
+ char *uds_url = r->filename + 6, *origin_url;
|
||||
|
||||
if (!strncmp(r->filename, "proxy:", 6) &&
|
||||
- (ptr2 = ap_strcasestr(r->filename, "unix:")) &&
|
||||
- (ptr = ap_strchr(ptr2, '|'))) {
|
||||
+ !ap_cstr_casecmpn(uds_url, "unix:", 5) &&
|
||||
+ (origin_url = ap_strchr(uds_url + 5, '|'))) {
|
||||
+ char *uds_path = NULL;
|
||||
+ apr_size_t url_len;
|
||||
apr_uri_t urisock;
|
||||
apr_status_t rv;
|
||||
- *ptr = '\0';
|
||||
- rv = apr_uri_parse(r->pool, ptr2, &urisock);
|
||||
- if (rv == APR_SUCCESS) {
|
||||
- char *rurl = ptr+1;
|
||||
- char *sockpath = ap_runtime_dir_relative(r->pool, urisock.path);
|
||||
- apr_table_setn(r->notes, "uds_path", sockpath);
|
||||
- *url = apr_pstrdup(r->pool, rurl); /* so we get the scheme for the uds */
|
||||
- /* r->filename starts w/ "proxy:", so add after that */
|
||||
- memmove(r->filename+6, rurl, strlen(rurl)+1);
|
||||
- ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
|
||||
- "*: rewrite of url due to UDS(%s): %s (%s)",
|
||||
- sockpath, *url, r->filename);
|
||||
- }
|
||||
- else {
|
||||
- *ptr = '|';
|
||||
- }
|
||||
- }
|
||||
+
|
||||
+ *origin_url = '\0';
|
||||
+ rv = apr_uri_parse(r->pool, uds_url, &urisock);
|
||||
+ *origin_url++ = '|';
|
||||
+
|
||||
+ if (rv == APR_SUCCESS && urisock.path && (!urisock.hostname
|
||||
+ || !urisock.hostname[0])) {
|
||||
+ uds_path = ap_runtime_dir_relative(r->pool, urisock.path);
|
||||
+ }
|
||||
+
|
||||
+ if (!uds_path) {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10292)
|
||||
+ "Invalid proxy UDS filename (%s)", r->filename);
|
||||
+ return 0;
|
||||
+ }
|
||||
+ apr_table_setn(r->notes, "uds_path", uds_path);
|
||||
+
|
||||
+ /* Remove the UDS path from *url and r->filename */
|
||||
+ url_len = strlen(origin_url);
|
||||
+ *url = apr_pstrmemdup(r->pool, origin_url, url_len);
|
||||
+ memcpy(uds_url, *url, url_len + 1);
|
||||
+
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
|
||||
+ "*: rewrite of url due to UDS(%s): %s (%s)",
|
||||
+ uds_path, *url, r->filename);
|
||||
+ }
|
||||
+
|
||||
+ return 1;
|
||||
}
|
||||
|
||||
PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker,
|
||||
@@ -2128,7 +2140,9 @@ PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker,
|
||||
"%s: found worker %s for %s",
|
||||
(*worker)->s->scheme, (*worker)->s->name, *url);
|
||||
*balancer = NULL;
|
||||
- fix_uds_filename(r, url);
|
||||
+ if (!fix_uds_filename(r, url)) {
|
||||
+ return HTTP_INTERNAL_SERVER_ERROR;
|
||||
+ }
|
||||
access_status = OK;
|
||||
}
|
||||
else if (r->proxyreq == PROXYREQ_PROXY) {
|
||||
@@ -2159,7 +2173,9 @@ PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker,
|
||||
* regarding the Connection header in the request.
|
||||
*/
|
||||
apr_table_setn(r->subprocess_env, "proxy-nokeepalive", "1");
|
||||
- fix_uds_filename(r, url);
|
||||
+ if (!fix_uds_filename(r, url)) {
|
||||
+ return HTTP_INTERNAL_SERVER_ERROR;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
}
|
@ -1,315 +0,0 @@
|
||||
diff --git a/include/http_protocol.h b/include/http_protocol.h
|
||||
index e7abdd9..e1572dc 100644
|
||||
--- a/include/http_protocol.h
|
||||
+++ b/include/http_protocol.h
|
||||
@@ -96,6 +96,13 @@ AP_DECLARE(void) ap_get_mime_headers(request_rec *r);
|
||||
AP_DECLARE(void) ap_get_mime_headers_core(request_rec *r,
|
||||
apr_bucket_brigade *bb);
|
||||
|
||||
+/**
|
||||
+ * Run post_read_request hook and validate.
|
||||
+ * @param r The current request
|
||||
+ * @return OK or HTTP_...
|
||||
+ */
|
||||
+AP_DECLARE(int) ap_post_read_request(request_rec *r);
|
||||
+
|
||||
/* Finish up stuff after a request */
|
||||
|
||||
/**
|
||||
diff --git a/modules/http/http_request.c b/modules/http/http_request.c
|
||||
index 9e7c4db..e873aab 100644
|
||||
--- a/modules/http/http_request.c
|
||||
+++ b/modules/http/http_request.c
|
||||
@@ -681,7 +681,7 @@ static request_rec *internal_internal_redirect(const char *new_uri,
|
||||
* to do their thing on internal redirects as well. Perhaps this is a
|
||||
* misnamed function.
|
||||
*/
|
||||
- if ((access_status = ap_run_post_read_request(new))) {
|
||||
+ if ((access_status = ap_post_read_request(new))) {
|
||||
ap_die(access_status, new);
|
||||
return NULL;
|
||||
}
|
||||
diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c
|
||||
index 6a9ef55..a6df1b8 100644
|
||||
--- a/modules/proxy/mod_proxy.c
|
||||
+++ b/modules/proxy/mod_proxy.c
|
||||
@@ -584,11 +584,12 @@ static int proxy_detect(request_rec *r)
|
||||
|
||||
if (conf->req && r->parsed_uri.scheme) {
|
||||
/* but it might be something vhosted */
|
||||
- if (!(r->parsed_uri.hostname
|
||||
- && !strcasecmp(r->parsed_uri.scheme, ap_http_scheme(r))
|
||||
- && ap_matches_request_vhost(r, r->parsed_uri.hostname,
|
||||
- (apr_port_t)(r->parsed_uri.port_str ? r->parsed_uri.port
|
||||
- : ap_default_port(r))))) {
|
||||
+ if (!r->parsed_uri.hostname
|
||||
+ || ap_cstr_casecmp(r->parsed_uri.scheme, ap_http_scheme(r)) != 0
|
||||
+ || !ap_matches_request_vhost(r, r->parsed_uri.hostname,
|
||||
+ (apr_port_t)(r->parsed_uri.port_str
|
||||
+ ? r->parsed_uri.port
|
||||
+ : ap_default_port(r)))) {
|
||||
r->proxyreq = PROXYREQ_PROXY;
|
||||
r->uri = r->unparsed_uri;
|
||||
r->filename = apr_pstrcat(r->pool, "proxy:", r->uri, NULL);
|
||||
@@ -1750,6 +1751,7 @@ static const char *
|
||||
struct proxy_alias *new;
|
||||
char *f = cmd->path;
|
||||
char *r = NULL;
|
||||
+ const char *real;
|
||||
char *word;
|
||||
apr_table_t *params = apr_table_make(cmd->pool, 5);
|
||||
const apr_array_header_t *arr;
|
||||
@@ -1815,6 +1817,10 @@ static const char *
|
||||
if (r == NULL) {
|
||||
return "ProxyPass|ProxyPassMatch needs a path when not defined in a location";
|
||||
}
|
||||
+ if (!(real = ap_proxy_de_socketfy(cmd->temp_pool, r))) {
|
||||
+ return "ProxyPass|ProxyPassMatch uses an invalid \"unix:\" URL";
|
||||
+ }
|
||||
+
|
||||
|
||||
/* if per directory, save away the single alias */
|
||||
if (cmd->path) {
|
||||
@@ -1831,7 +1837,7 @@ static const char *
|
||||
}
|
||||
|
||||
new->fake = apr_pstrdup(cmd->pool, f);
|
||||
- new->real = apr_pstrdup(cmd->pool, ap_proxy_de_socketfy(cmd->pool, r));
|
||||
+ new->real = apr_pstrdup(cmd->pool, real);
|
||||
new->flags = flags;
|
||||
if (use_regex) {
|
||||
new->regex = ap_pregcomp(cmd->pool, f, AP_REG_EXTENDED);
|
||||
@@ -2316,6 +2322,7 @@ static const char *add_member(cmd_parms *cmd, void *dummy, const char *arg)
|
||||
proxy_worker *worker;
|
||||
char *path = cmd->path;
|
||||
char *name = NULL;
|
||||
+ const char *real;
|
||||
char *word;
|
||||
apr_table_t *params = apr_table_make(cmd->pool, 5);
|
||||
const apr_array_header_t *arr;
|
||||
@@ -2356,6 +2363,9 @@ static const char *add_member(cmd_parms *cmd, void *dummy, const char *arg)
|
||||
return "BalancerMember must define balancer name when outside <Proxy > section";
|
||||
if (!name)
|
||||
return "BalancerMember must define remote proxy server";
|
||||
+ if (!(real = ap_proxy_de_socketfy(cmd->temp_pool, name))) {
|
||||
+ return "BalancerMember uses an invalid \"unix:\" URL";
|
||||
+ }
|
||||
|
||||
ap_str_tolower(path); /* lowercase scheme://hostname */
|
||||
|
||||
@@ -2368,7 +2378,7 @@ static const char *add_member(cmd_parms *cmd, void *dummy, const char *arg)
|
||||
}
|
||||
|
||||
/* Try to find existing worker */
|
||||
- worker = ap_proxy_get_worker(cmd->temp_pool, balancer, conf, ap_proxy_de_socketfy(cmd->temp_pool, name));
|
||||
+ worker = ap_proxy_get_worker(cmd->temp_pool, balancer, conf, real);
|
||||
if (!worker) {
|
||||
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, APLOGNO(01147)
|
||||
"Defining worker '%s' for balancer '%s'",
|
||||
@@ -2457,7 +2467,13 @@ static const char *
|
||||
}
|
||||
}
|
||||
else {
|
||||
- worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, ap_proxy_de_socketfy(cmd->temp_pool, name));
|
||||
+ const char *real;
|
||||
+
|
||||
+ if (!(real = ap_proxy_de_socketfy(cmd->temp_pool, name))) {
|
||||
+ return "ProxySet uses an invalid \"unix:\" URL";
|
||||
+ }
|
||||
+
|
||||
+ worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, real);
|
||||
if (!worker) {
|
||||
if (in_proxy_section) {
|
||||
err = ap_proxy_define_worker(cmd->pool, &worker, NULL,
|
||||
@@ -2599,8 +2615,14 @@ static const char *proxysection(cmd_parms *cmd, void *mconfig, const char *arg)
|
||||
}
|
||||
}
|
||||
else {
|
||||
+ const char *real;
|
||||
+
|
||||
+ if (!(real = ap_proxy_de_socketfy(cmd->temp_pool, conf->p))) {
|
||||
+ return "<Proxy/ProxyMatch > uses an invalid \"unix:\" URL";
|
||||
+ }
|
||||
+
|
||||
worker = ap_proxy_get_worker(cmd->temp_pool, NULL, sconf,
|
||||
- ap_proxy_de_socketfy(cmd->temp_pool, (char*)conf->p));
|
||||
+ real);
|
||||
if (!worker) {
|
||||
err = ap_proxy_define_worker(cmd->pool, &worker, NULL,
|
||||
sconf, conf->p, 0);
|
||||
diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h
|
||||
index fbbd508..dca6f69 100644
|
||||
--- a/modules/proxy/mod_proxy.h
|
||||
+++ b/modules/proxy/mod_proxy.h
|
||||
@@ -713,6 +713,8 @@ typedef __declspec(dllimport) const char *
|
||||
proxy_dir_conf *, const char *);
|
||||
#endif
|
||||
|
||||
+#define AP_PROXY_WORKER_NO_UDS (1u << 3)
|
||||
+
|
||||
|
||||
/* Connection pool API */
|
||||
/**
|
||||
@@ -725,6 +727,24 @@ typedef __declspec(dllimport) const char *
|
||||
PROXY_DECLARE(char *) ap_proxy_worker_name(apr_pool_t *p,
|
||||
proxy_worker *worker);
|
||||
|
||||
+
|
||||
+/**
|
||||
+ * Get the worker from proxy configuration, looking for either PREFIXED or
|
||||
+ * MATCHED or both types of workers according to given mask
|
||||
+ * @param p memory pool used for finding worker
|
||||
+ * @param balancer the balancer that the worker belongs to
|
||||
+ * @param conf current proxy server configuration
|
||||
+ * @param url url to find the worker from
|
||||
+ * @param mask bitmask of AP_PROXY_WORKER_IS_*
|
||||
+ * @return proxy_worker or NULL if not found
|
||||
+ */
|
||||
+PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker_ex(apr_pool_t *p,
|
||||
+ proxy_balancer *balancer,
|
||||
+ proxy_server_conf *conf,
|
||||
+ const char *url,
|
||||
+ unsigned int mask);
|
||||
+
|
||||
+
|
||||
/**
|
||||
* Get the worker from proxy configuration
|
||||
* @param p memory pool used for finding worker
|
||||
@@ -737,6 +757,8 @@ PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p,
|
||||
proxy_balancer *balancer,
|
||||
proxy_server_conf *conf,
|
||||
const char *url);
|
||||
+
|
||||
+
|
||||
/**
|
||||
* Define and Allocate space for the worker to proxy configuration
|
||||
* @param p memory pool to allocate worker from
|
||||
diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c
|
||||
index 032e0c4..3d5b220 100644
|
||||
--- a/modules/proxy/proxy_util.c
|
||||
+++ b/modules/proxy/proxy_util.c
|
||||
@@ -1643,10 +1643,11 @@ PROXY_DECLARE(char *) ap_proxy_worker_name(apr_pool_t *p,
|
||||
return apr_pstrcat(p, "unix:", worker->s->uds_path, "|", worker->s->name, NULL);
|
||||
}
|
||||
|
||||
-PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p,
|
||||
- proxy_balancer *balancer,
|
||||
- proxy_server_conf *conf,
|
||||
- const char *url)
|
||||
+PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker_ex(apr_pool_t *p,
|
||||
+ proxy_balancer *balancer,
|
||||
+ proxy_server_conf *conf,
|
||||
+ const char *url,
|
||||
+ unsigned int mask)
|
||||
{
|
||||
proxy_worker *worker;
|
||||
proxy_worker *max_worker = NULL;
|
||||
@@ -1662,7 +1663,12 @@ PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
- url = ap_proxy_de_socketfy(p, url);
|
||||
+ if (!(mask & AP_PROXY_WORKER_NO_UDS)) {
|
||||
+ url = ap_proxy_de_socketfy(p, url);
|
||||
+ if (!url) {
|
||||
+ return NULL;
|
||||
+ }
|
||||
+ }
|
||||
|
||||
c = ap_strchr_c(url, ':');
|
||||
if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0') {
|
||||
@@ -1727,6 +1733,14 @@ PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p,
|
||||
return max_worker;
|
||||
}
|
||||
|
||||
+PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p,
|
||||
+ proxy_balancer *balancer,
|
||||
+ proxy_server_conf *conf,
|
||||
+ const char *url)
|
||||
+{
|
||||
+ return ap_proxy_get_worker_ex(p, balancer, conf, url, 0);
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* To create a worker from scratch first we define the
|
||||
* specifics of the worker; this is all local data.
|
||||
@@ -2134,22 +2148,22 @@ PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker,
|
||||
|
||||
access_status = proxy_run_pre_request(worker, balancer, r, conf, url);
|
||||
if (access_status == DECLINED && *balancer == NULL) {
|
||||
- *worker = ap_proxy_get_worker(r->pool, NULL, conf, *url);
|
||||
+ const int forward = (r->proxyreq == PROXYREQ_PROXY);
|
||||
+ *worker = ap_proxy_get_worker_ex(r->pool, NULL, conf, *url,
|
||||
+ forward ? AP_PROXY_WORKER_NO_UDS : 0);
|
||||
if (*worker) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
|
||||
"%s: found worker %s for %s",
|
||||
(*worker)->s->scheme, (*worker)->s->name, *url);
|
||||
- *balancer = NULL;
|
||||
- if (!fix_uds_filename(r, url)) {
|
||||
+ if (!forward && !fix_uds_filename(r, url)) {
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
access_status = OK;
|
||||
}
|
||||
- else if (r->proxyreq == PROXYREQ_PROXY) {
|
||||
+ else if (forward) {
|
||||
if (conf->forward) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
|
||||
"*: found forward proxy worker for %s", *url);
|
||||
- *balancer = NULL;
|
||||
*worker = conf->forward;
|
||||
access_status = OK;
|
||||
/*
|
||||
@@ -2163,8 +2177,8 @@ PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker,
|
||||
else if (r->proxyreq == PROXYREQ_REVERSE) {
|
||||
if (conf->reverse) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
|
||||
- "*: using default reverse proxy worker for %s (no keepalive)", *url);
|
||||
- *balancer = NULL;
|
||||
+ "*: using default reverse proxy worker for %s "
|
||||
+ "(no keepalive)", *url);
|
||||
*worker = conf->reverse;
|
||||
access_status = OK;
|
||||
/*
|
||||
diff --git a/server/protocol.c b/server/protocol.c
|
||||
index 430d91e..a2aa081 100644
|
||||
--- a/server/protocol.c
|
||||
+++ b/server/protocol.c
|
||||
@@ -1525,7 +1525,7 @@ request_rec *ap_read_request(conn_rec *conn)
|
||||
/* we may have switched to another server */
|
||||
apply_server_config(r);
|
||||
|
||||
- if ((access_status = ap_run_post_read_request(r))) {
|
||||
+ if ((access_status = ap_post_read_request(r))) {
|
||||
goto die;
|
||||
}
|
||||
|
||||
@@ -1582,6 +1582,27 @@ ignore:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+AP_DECLARE(int) ap_post_read_request(request_rec *r)
|
||||
+{
|
||||
+ int status;
|
||||
+
|
||||
+ if ((status = ap_run_post_read_request(r))) {
|
||||
+ return status;
|
||||
+ }
|
||||
+
|
||||
+ /* Enforce http(s) only scheme for non-forward-proxy requests */
|
||||
+ if (!r->proxyreq
|
||||
+ && r->parsed_uri.scheme
|
||||
+ && (ap_cstr_casecmpn(r->parsed_uri.scheme, "http", 4) != 0
|
||||
+ || (r->parsed_uri.scheme[4] != '\0'
|
||||
+ && (apr_tolower(r->parsed_uri.scheme[4]) != 's'
|
||||
+ || r->parsed_uri.scheme[5] != '\0')))) {
|
||||
+ return HTTP_BAD_REQUEST;
|
||||
+ }
|
||||
+
|
||||
+ return OK;
|
||||
+}
|
||||
+
|
||||
/* if a request with a body creates a subrequest, remove original request's
|
||||
* input headers which pertain to the body which has already been read.
|
||||
* out-of-line helper function for ap_set_sub_req_protocol.
|
@ -1,12 +0,0 @@
|
||||
diff --git a/modules/lua/lua_request.c b/modules/lua/lua_request.c
|
||||
index 77a88b4..1d8be2e 100644
|
||||
--- a/modules/lua/lua_request.c
|
||||
+++ b/modules/lua/lua_request.c
|
||||
@@ -376,6 +376,7 @@ static int req_parsebody(lua_State *L)
|
||||
if (end == NULL) break;
|
||||
key = (char *) apr_pcalloc(r->pool, 256);
|
||||
filename = (char *) apr_pcalloc(r->pool, 256);
|
||||
+ if (end - crlf <= 8) break;
|
||||
vlen = end - crlf - 8;
|
||||
buffer = (char *) apr_pcalloc(r->pool, vlen+1);
|
||||
memcpy(buffer, crlf + 4, vlen);
|
@ -1,70 +0,0 @@
|
||||
--- a/modules/lua/lua_request.c 2022/03/07 14:48:54 1898693
|
||||
+++ b/modules/lua/lua_request.c 2022/03/07 14:51:19 1898694
|
||||
@@ -235,14 +235,16 @@
|
||||
{
|
||||
int rc = OK;
|
||||
|
||||
+ *rbuf = NULL;
|
||||
+ *size = 0;
|
||||
+
|
||||
if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR))) {
|
||||
return (rc);
|
||||
}
|
||||
if (ap_should_client_block(r)) {
|
||||
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
- char argsbuffer[HUGE_STRING_LEN];
|
||||
- apr_off_t rsize, len_read, rpos = 0;
|
||||
+ apr_off_t len_read, rpos = 0;
|
||||
apr_off_t length = r->remaining;
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
|
||||
@@ -250,18 +252,18 @@
|
||||
return APR_EINCOMPLETE; /* Only room for incomplete data chunk :( */
|
||||
}
|
||||
*rbuf = (const char *) apr_pcalloc(r->pool, (apr_size_t) (length + 1));
|
||||
- *size = length;
|
||||
- while ((len_read = ap_get_client_block(r, argsbuffer, sizeof(argsbuffer))) > 0) {
|
||||
- if ((rpos + len_read) > length) {
|
||||
- rsize = length - rpos;
|
||||
- }
|
||||
- else {
|
||||
- rsize = len_read;
|
||||
- }
|
||||
-
|
||||
- memcpy((char *) *rbuf + rpos, argsbuffer, (size_t) rsize);
|
||||
- rpos += rsize;
|
||||
+ while ((rpos < length)
|
||||
+ && (len_read = ap_get_client_block(r, (char *) *rbuf + rpos,
|
||||
+ length - rpos)) > 0) {
|
||||
+ rpos += len_read;
|
||||
}
|
||||
+ if (len_read < 0) {
|
||||
+ return APR_EINCOMPLETE;
|
||||
+ }
|
||||
+ *size = rpos;
|
||||
+ }
|
||||
+ else {
|
||||
+ rc = DONE;
|
||||
}
|
||||
|
||||
return (rc);
|
||||
@@ -278,6 +280,8 @@
|
||||
{
|
||||
apr_status_t rc = OK;
|
||||
|
||||
+ *size = 0;
|
||||
+
|
||||
if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR)))
|
||||
return rc;
|
||||
if (ap_should_client_block(r)) {
|
||||
@@ -303,6 +307,9 @@
|
||||
rpos += rsize;
|
||||
}
|
||||
}
|
||||
+ else {
|
||||
+ rc = DONE;
|
||||
+ }
|
||||
|
||||
return rc;
|
||||
}
|
@ -1,154 +0,0 @@
|
||||
diff --git a/modules/http/http_filters.c b/modules/http/http_filters.c
|
||||
index 9828cdf..6bedcac 100644
|
||||
--- a/modules/http/http_filters.c
|
||||
+++ b/modules/http/http_filters.c
|
||||
@@ -1605,9 +1605,9 @@ AP_DECLARE(int) ap_map_http_request_error(apr_status_t rv, int status)
|
||||
*/
|
||||
AP_DECLARE(int) ap_discard_request_body(request_rec *r)
|
||||
{
|
||||
+ int rc = OK;
|
||||
+ conn_rec *c = r->connection;
|
||||
apr_bucket_brigade *bb;
|
||||
- int seen_eos;
|
||||
- apr_status_t rv;
|
||||
|
||||
/* Sometimes we'll get in a state where the input handling has
|
||||
* detected an error where we want to drop the connection, so if
|
||||
@@ -1616,54 +1616,57 @@ AP_DECLARE(int) ap_discard_request_body(request_rec *r)
|
||||
*
|
||||
* This function is also a no-op on a subrequest.
|
||||
*/
|
||||
- if (r->main || r->connection->keepalive == AP_CONN_CLOSE ||
|
||||
- ap_status_drops_connection(r->status)) {
|
||||
+ if (r->main || c->keepalive == AP_CONN_CLOSE) {
|
||||
+ return OK;
|
||||
+ }
|
||||
+ if (ap_status_drops_connection(r->status)) {
|
||||
+ c->keepalive = AP_CONN_CLOSE;
|
||||
return OK;
|
||||
}
|
||||
|
||||
bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
|
||||
- seen_eos = 0;
|
||||
- do {
|
||||
- apr_bucket *bucket;
|
||||
+ for (;;) {
|
||||
+ apr_status_t rv;
|
||||
|
||||
rv = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES,
|
||||
APR_BLOCK_READ, HUGE_STRING_LEN);
|
||||
-
|
||||
if (rv != APR_SUCCESS) {
|
||||
- apr_brigade_destroy(bb);
|
||||
- return ap_map_http_request_error(rv, HTTP_BAD_REQUEST);
|
||||
+ rc = ap_map_http_request_error(rv, HTTP_BAD_REQUEST);
|
||||
+ goto cleanup;
|
||||
}
|
||||
|
||||
- for (bucket = APR_BRIGADE_FIRST(bb);
|
||||
- bucket != APR_BRIGADE_SENTINEL(bb);
|
||||
- bucket = APR_BUCKET_NEXT(bucket))
|
||||
- {
|
||||
- const char *data;
|
||||
- apr_size_t len;
|
||||
+ while (!APR_BRIGADE_EMPTY(bb)) {
|
||||
+ apr_bucket *b = APR_BRIGADE_FIRST(bb);
|
||||
|
||||
- if (APR_BUCKET_IS_EOS(bucket)) {
|
||||
- seen_eos = 1;
|
||||
- break;
|
||||
+ if (APR_BUCKET_IS_EOS(b)) {
|
||||
+ goto cleanup;
|
||||
}
|
||||
|
||||
- /* These are metadata buckets. */
|
||||
- if (bucket->length == 0) {
|
||||
- continue;
|
||||
- }
|
||||
-
|
||||
- /* We MUST read because in case we have an unknown-length
|
||||
- * bucket or one that morphs, we want to exhaust it.
|
||||
+ /* There is no need to read empty or metadata buckets or
|
||||
+ * buckets of known length, but we MUST read buckets of
|
||||
+ * unknown length in order to exhaust them.
|
||||
*/
|
||||
- rv = apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);
|
||||
+ if (b->length == (apr_size_t)-1) {
|
||||
+ apr_size_t len;
|
||||
+ const char *data;
|
||||
+
|
||||
+ rv = apr_bucket_read(b, &data, &len, APR_BLOCK_READ);
|
||||
if (rv != APR_SUCCESS) {
|
||||
- apr_brigade_destroy(bb);
|
||||
- return HTTP_BAD_REQUEST;
|
||||
+ rc = HTTP_BAD_REQUEST;
|
||||
+ goto cleanup;
|
||||
}
|
||||
}
|
||||
- apr_brigade_cleanup(bb);
|
||||
- } while (!seen_eos);
|
||||
|
||||
- return OK;
|
||||
+ apr_bucket_delete(b);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+cleanup:
|
||||
+ apr_brigade_cleanup(bb);
|
||||
+ if (rc != OK) {
|
||||
+ c->keepalive = AP_CONN_CLOSE;
|
||||
+ }
|
||||
+ return rc;
|
||||
}
|
||||
|
||||
/* Here we deal with getting the request message body from the client.
|
||||
diff --git a/server/protocol.c b/server/protocol.c
|
||||
index a2aa081..a554970 100644
|
||||
--- a/server/protocol.c
|
||||
+++ b/server/protocol.c
|
||||
@@ -1666,23 +1666,29 @@ AP_DECLARE(void) ap_set_sub_req_protocol(request_rec *rnew,
|
||||
rnew->main = (request_rec *) r;
|
||||
}
|
||||
|
||||
-static void end_output_stream(request_rec *r)
|
||||
+static void end_output_stream(request_rec *r, int status)
|
||||
{
|
||||
conn_rec *c = r->connection;
|
||||
apr_bucket_brigade *bb;
|
||||
apr_bucket *b;
|
||||
|
||||
bb = apr_brigade_create(r->pool, c->bucket_alloc);
|
||||
+ if (status != OK) {
|
||||
+ b = ap_bucket_error_create(status, NULL, r->pool, c->bucket_alloc);
|
||||
+ APR_BRIGADE_INSERT_TAIL(bb, b);
|
||||
+ }
|
||||
b = apr_bucket_eos_create(c->bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(bb, b);
|
||||
+
|
||||
ap_pass_brigade(r->output_filters, bb);
|
||||
+ apr_brigade_cleanup(bb);
|
||||
}
|
||||
|
||||
AP_DECLARE(void) ap_finalize_sub_req_protocol(request_rec *sub)
|
||||
{
|
||||
/* tell the filter chain there is no more content coming */
|
||||
if (!sub->eos_sent) {
|
||||
- end_output_stream(sub);
|
||||
+ end_output_stream(sub, OK);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1693,11 +1699,11 @@ AP_DECLARE(void) ap_finalize_sub_req_protocol(request_rec *sub)
|
||||
*/
|
||||
AP_DECLARE(void) ap_finalize_request_protocol(request_rec *r)
|
||||
{
|
||||
- (void) ap_discard_request_body(r);
|
||||
+ int status = ap_discard_request_body(r);
|
||||
|
||||
/* tell the filter chain there is no more content coming */
|
||||
if (!r->eos_sent) {
|
||||
- end_output_stream(r);
|
||||
+ end_output_stream(r, status);
|
||||
}
|
||||
}
|
||||
|
@ -1,103 +0,0 @@
|
||||
diff --git a/docs/manual/mod/core.html.en b/docs/manual/mod/core.html.en
|
||||
index 20d1e5a..e1ec8d0 100644
|
||||
--- a/docs/manual/mod/core.html.en
|
||||
+++ b/docs/manual/mod/core.html.en
|
||||
@@ -2935,12 +2935,19 @@ from the client</td></tr>
|
||||
<tr><th><a href="directive-dict.html#Status">Status:</a></th><td>Core</td></tr>
|
||||
<tr><th><a href="directive-dict.html#Module">Module:</a></th><td>core</td></tr>
|
||||
</table>
|
||||
- <p>Limit (in bytes) on maximum size of an XML-based request
|
||||
- body. A value of <code>0</code> will disable any checking.</p>
|
||||
+ <p>Limit (in bytes) on the maximum size of an XML-based request
|
||||
+ body. A value of <code>0</code> will apply a hard limit (depending on
|
||||
+ 32bit vs 64bit system) allowing for XML escaping within the bounds of
|
||||
+ the system addressable memory, but it exists for compatibility only
|
||||
+ and is not recommended since it does not account for memory consumed
|
||||
+ elsewhere or concurrent requests, which might result in an overall
|
||||
+ system out-of-memory.
|
||||
+ </p>
|
||||
|
||||
<p>Example:</p>
|
||||
|
||||
- <pre class="prettyprint lang-config">LimitXMLRequestBody 0</pre>
|
||||
+ <pre class="prettyprint lang-config"># Limit of 1 MiB
|
||||
+ LimitXMLRequestBody 1073741824</pre>
|
||||
|
||||
|
||||
|
||||
diff --git a/server/core.c b/server/core.c
|
||||
index e32613d..8abfa65 100644
|
||||
--- a/server/core.c
|
||||
+++ b/server/core.c
|
||||
@@ -70,6 +70,8 @@
|
||||
/* LimitXMLRequestBody handling */
|
||||
#define AP_LIMIT_UNSET ((long) -1)
|
||||
#define AP_DEFAULT_LIMIT_XML_BODY ((apr_size_t)1000000)
|
||||
+/* Hard limit for ap_escape_html2() */
|
||||
+#define AP_MAX_LIMIT_XML_BODY ((apr_size_t)(APR_SIZE_MAX / 6 - 1))
|
||||
|
||||
#define AP_MIN_SENDFILE_BYTES (256)
|
||||
|
||||
@@ -3689,6 +3691,11 @@ static const char *set_limit_xml_req_body(cmd_parms *cmd, void *conf_,
|
||||
if (conf->limit_xml_body < 0)
|
||||
return "LimitXMLRequestBody requires a non-negative integer.";
|
||||
|
||||
+ /* zero is AP_MAX_LIMIT_XML_BODY (implicitly) */
|
||||
+ if ((apr_size_t)conf->limit_xml_body > AP_MAX_LIMIT_XML_BODY)
|
||||
+ return apr_psprintf(cmd->pool, "LimitXMLRequestBody must not exceed "
|
||||
+ "%" APR_SIZE_T_FMT, AP_MAX_LIMIT_XML_BODY);
|
||||
+
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -3777,6 +3784,8 @@ AP_DECLARE(apr_size_t) ap_get_limit_xml_body(const request_rec *r)
|
||||
conf = ap_get_core_module_config(r->per_dir_config);
|
||||
if (conf->limit_xml_body == AP_LIMIT_UNSET)
|
||||
return AP_DEFAULT_LIMIT_XML_BODY;
|
||||
+ if (conf->limit_xml_body == 0)
|
||||
+ return AP_MAX_LIMIT_XML_BODY;
|
||||
|
||||
return (apr_size_t)conf->limit_xml_body;
|
||||
}
|
||||
diff --git a/server/util.c b/server/util.c
|
||||
index 2a5dd04..eefdafa 100644
|
||||
--- a/server/util.c
|
||||
+++ b/server/util.c
|
||||
@@ -2037,11 +2037,14 @@ AP_DECLARE(char *) ap_escape_urlencoded(apr_pool_t *p, const char *buffer)
|
||||
|
||||
AP_DECLARE(char *) ap_escape_html2(apr_pool_t *p, const char *s, int toasc)
|
||||
{
|
||||
- int i, j;
|
||||
+ apr_size_t i, j;
|
||||
char *x;
|
||||
|
||||
/* first, count the number of extra characters */
|
||||
- for (i = 0, j = 0; s[i] != '\0'; i++)
|
||||
+ for (i = 0, j = 0; s[i] != '\0'; i++) {
|
||||
+ if (i + j > APR_SIZE_MAX - 6) {
|
||||
+ abort();
|
||||
+ }
|
||||
if (s[i] == '<' || s[i] == '>')
|
||||
j += 3;
|
||||
else if (s[i] == '&')
|
||||
@@ -2050,6 +2053,7 @@ AP_DECLARE(char *) ap_escape_html2(apr_pool_t *p, const char *s, int toasc)
|
||||
j += 5;
|
||||
else if (toasc && !apr_isascii(s[i]))
|
||||
j += 5;
|
||||
+ }
|
||||
|
||||
if (j == 0)
|
||||
return apr_pstrmemdup(p, s, i);
|
||||
diff --git a/server/util_xml.c b/server/util_xml.c
|
||||
index 4845194..22806fa 100644
|
||||
--- a/server/util_xml.c
|
||||
+++ b/server/util_xml.c
|
||||
@@ -85,7 +85,7 @@ AP_DECLARE(int) ap_xml_parse_input(request_rec * r, apr_xml_doc **pdoc)
|
||||
}
|
||||
|
||||
total_read += len;
|
||||
- if (limit_xml_body && total_read > limit_xml_body) {
|
||||
+ if (total_read > limit_xml_body) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00539)
|
||||
"XML request body is larger than the configured "
|
||||
"limit of %lu", (unsigned long)limit_xml_body);
|
@ -1,377 +0,0 @@
|
||||
diff --git a/modules/filters/libsed.h b/modules/filters/libsed.h
|
||||
index 76cbc0c..0256b1e 100644
|
||||
--- a/modules/filters/libsed.h
|
||||
+++ b/modules/filters/libsed.h
|
||||
@@ -60,7 +60,7 @@ struct sed_label_s {
|
||||
};
|
||||
|
||||
typedef apr_status_t (sed_err_fn_t)(void *data, const char *error);
|
||||
-typedef apr_status_t (sed_write_fn_t)(void *ctx, char *buf, int sz);
|
||||
+typedef apr_status_t (sed_write_fn_t)(void *ctx, char *buf, apr_size_t sz);
|
||||
|
||||
typedef struct sed_commands_s sed_commands_t;
|
||||
#define NWFILES 11 /* 10 plus one for standard output */
|
||||
@@ -69,7 +69,7 @@ struct sed_commands_s {
|
||||
sed_err_fn_t *errfn;
|
||||
void *data;
|
||||
|
||||
- unsigned lsize;
|
||||
+ apr_size_t lsize;
|
||||
char *linebuf;
|
||||
char *lbend;
|
||||
const char *saveq;
|
||||
@@ -116,15 +116,15 @@ struct sed_eval_s {
|
||||
apr_int64_t lnum;
|
||||
void *fout;
|
||||
|
||||
- unsigned lsize;
|
||||
+ apr_size_t lsize;
|
||||
char *linebuf;
|
||||
char *lspend;
|
||||
|
||||
- unsigned hsize;
|
||||
+ apr_size_t hsize;
|
||||
char *holdbuf;
|
||||
char *hspend;
|
||||
|
||||
- unsigned gsize;
|
||||
+ apr_size_t gsize;
|
||||
char *genbuf;
|
||||
char *lcomend;
|
||||
|
||||
@@ -160,7 +160,7 @@ apr_status_t sed_init_eval(sed_eval_t *eval, sed_commands_t *commands,
|
||||
sed_err_fn_t *errfn, void *data,
|
||||
sed_write_fn_t *writefn, apr_pool_t *p);
|
||||
apr_status_t sed_reset_eval(sed_eval_t *eval, sed_commands_t *commands, sed_err_fn_t *errfn, void *data);
|
||||
-apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, int bufsz, void *fout);
|
||||
+apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, apr_size_t bufsz, void *fout);
|
||||
apr_status_t sed_eval_file(sed_eval_t *eval, apr_file_t *fin, void *fout);
|
||||
apr_status_t sed_finalize_eval(sed_eval_t *eval, void *f);
|
||||
void sed_destroy_eval(sed_eval_t *eval);
|
||||
diff --git a/modules/filters/mod_sed.c b/modules/filters/mod_sed.c
|
||||
index 346c210..8595e41 100644
|
||||
--- a/modules/filters/mod_sed.c
|
||||
+++ b/modules/filters/mod_sed.c
|
||||
@@ -51,7 +51,7 @@ typedef struct sed_filter_ctxt
|
||||
apr_bucket_brigade *bbinp;
|
||||
char *outbuf;
|
||||
char *curoutbuf;
|
||||
- int bufsize;
|
||||
+ apr_size_t bufsize;
|
||||
apr_pool_t *tpool;
|
||||
int numbuckets;
|
||||
} sed_filter_ctxt;
|
||||
@@ -100,7 +100,7 @@ static void alloc_outbuf(sed_filter_ctxt* ctx)
|
||||
/* append_bucket
|
||||
* Allocate a new bucket from buf and sz and append to ctx->bb
|
||||
*/
|
||||
-static apr_status_t append_bucket(sed_filter_ctxt* ctx, char* buf, int sz)
|
||||
+static apr_status_t append_bucket(sed_filter_ctxt* ctx, char* buf, apr_size_t sz)
|
||||
{
|
||||
apr_status_t status = APR_SUCCESS;
|
||||
apr_bucket *b;
|
||||
@@ -133,7 +133,7 @@ static apr_status_t append_bucket(sed_filter_ctxt* ctx, char* buf, int sz)
|
||||
*/
|
||||
static apr_status_t flush_output_buffer(sed_filter_ctxt *ctx)
|
||||
{
|
||||
- int size = ctx->curoutbuf - ctx->outbuf;
|
||||
+ apr_size_t size = ctx->curoutbuf - ctx->outbuf;
|
||||
char *out;
|
||||
apr_status_t status = APR_SUCCESS;
|
||||
if ((ctx->outbuf == NULL) || (size <=0))
|
||||
@@ -147,12 +147,12 @@ static apr_status_t flush_output_buffer(sed_filter_ctxt *ctx)
|
||||
/* This is a call back function. When libsed wants to generate the output,
|
||||
* this function will be invoked.
|
||||
*/
|
||||
-static apr_status_t sed_write_output(void *dummy, char *buf, int sz)
|
||||
+static apr_status_t sed_write_output(void *dummy, char *buf, apr_size_t sz)
|
||||
{
|
||||
/* dummy is basically filter context. Context is passed during invocation
|
||||
* of sed_eval_buffer
|
||||
*/
|
||||
- int remainbytes = 0;
|
||||
+ apr_size_t remainbytes = 0;
|
||||
apr_status_t status = APR_SUCCESS;
|
||||
sed_filter_ctxt *ctx = (sed_filter_ctxt *) dummy;
|
||||
if (ctx->outbuf == NULL) {
|
||||
@@ -168,21 +168,29 @@ static apr_status_t sed_write_output(void *dummy, char *buf, int sz)
|
||||
}
|
||||
/* buffer is now full */
|
||||
status = append_bucket(ctx, ctx->outbuf, ctx->bufsize);
|
||||
- /* old buffer is now used so allocate new buffer */
|
||||
- alloc_outbuf(ctx);
|
||||
- /* if size is bigger than the allocated buffer directly add to output
|
||||
- * brigade */
|
||||
- if ((status == APR_SUCCESS) && (sz >= ctx->bufsize)) {
|
||||
- char* newbuf = apr_pmemdup(ctx->tpool, buf, sz);
|
||||
- status = append_bucket(ctx, newbuf, sz);
|
||||
- /* pool might get clear after append_bucket */
|
||||
- if (ctx->outbuf == NULL) {
|
||||
+ if (status == APR_SUCCESS) {
|
||||
+ /* if size is bigger than the allocated buffer directly add to output
|
||||
+ * brigade */
|
||||
+ if (sz >= ctx->bufsize) {
|
||||
+ char* newbuf = apr_pmemdup(ctx->tpool, buf, sz);
|
||||
+ status = append_bucket(ctx, newbuf, sz);
|
||||
+ if (status == APR_SUCCESS) {
|
||||
+ /* old buffer is now used so allocate new buffer */
|
||||
+ alloc_outbuf(ctx);
|
||||
+ }
|
||||
+ else {
|
||||
+ clear_ctxpool(ctx);
|
||||
+ }
|
||||
+ }
|
||||
+ else {
|
||||
+ /* old buffer is now used so allocate new buffer */
|
||||
alloc_outbuf(ctx);
|
||||
+ memcpy(ctx->curoutbuf, buf, sz);
|
||||
+ ctx->curoutbuf += sz;
|
||||
}
|
||||
}
|
||||
else {
|
||||
- memcpy(ctx->curoutbuf, buf, sz);
|
||||
- ctx->curoutbuf += sz;
|
||||
+ clear_ctxpool(ctx);
|
||||
}
|
||||
}
|
||||
else {
|
||||
diff --git a/modules/filters/sed1.c b/modules/filters/sed1.c
|
||||
index be03506..67a8d06 100644
|
||||
--- a/modules/filters/sed1.c
|
||||
+++ b/modules/filters/sed1.c
|
||||
@@ -71,7 +71,7 @@ static apr_status_t dosub(sed_eval_t *eval, char *rhsbuf, int n,
|
||||
static char *place(sed_eval_t *eval, char *asp, char *al1, char *al2);
|
||||
static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc,
|
||||
step_vars_storage *step_vars);
|
||||
-static apr_status_t wline(sed_eval_t *eval, char *buf, int sz);
|
||||
+static apr_status_t wline(sed_eval_t *eval, char *buf, apr_size_t sz);
|
||||
static apr_status_t arout(sed_eval_t *eval);
|
||||
|
||||
static void eval_errf(sed_eval_t *eval, const char *fmt, ...)
|
||||
@@ -92,11 +92,11 @@ static void eval_errf(sed_eval_t *eval, const char *fmt, ...)
|
||||
* grow_buffer
|
||||
*/
|
||||
static void grow_buffer(apr_pool_t *pool, char **buffer,
|
||||
- char **spend, unsigned int *cursize,
|
||||
- unsigned int newsize)
|
||||
+ char **spend, apr_size_t *cursize,
|
||||
+ apr_size_t newsize)
|
||||
{
|
||||
char* newbuffer = NULL;
|
||||
- int spendsize = 0;
|
||||
+ apr_size_t spendsize = 0;
|
||||
if (*cursize >= newsize)
|
||||
return;
|
||||
/* Avoid number of times realloc is called. It could cause huge memory
|
||||
@@ -124,7 +124,7 @@ static void grow_buffer(apr_pool_t *pool, char **buffer,
|
||||
/*
|
||||
* grow_line_buffer
|
||||
*/
|
||||
-static void grow_line_buffer(sed_eval_t *eval, int newsize)
|
||||
+static void grow_line_buffer(sed_eval_t *eval, apr_size_t newsize)
|
||||
{
|
||||
grow_buffer(eval->pool, &eval->linebuf, &eval->lspend,
|
||||
&eval->lsize, newsize);
|
||||
@@ -133,7 +133,7 @@ static void grow_line_buffer(sed_eval_t *eval, int newsize)
|
||||
/*
|
||||
* grow_hold_buffer
|
||||
*/
|
||||
-static void grow_hold_buffer(sed_eval_t *eval, int newsize)
|
||||
+static void grow_hold_buffer(sed_eval_t *eval, apr_size_t newsize)
|
||||
{
|
||||
grow_buffer(eval->pool, &eval->holdbuf, &eval->hspend,
|
||||
&eval->hsize, newsize);
|
||||
@@ -142,7 +142,7 @@ static void grow_hold_buffer(sed_eval_t *eval, int newsize)
|
||||
/*
|
||||
* grow_gen_buffer
|
||||
*/
|
||||
-static void grow_gen_buffer(sed_eval_t *eval, int newsize,
|
||||
+static void grow_gen_buffer(sed_eval_t *eval, apr_size_t newsize,
|
||||
char **gspend)
|
||||
{
|
||||
if (gspend == NULL) {
|
||||
@@ -156,9 +156,9 @@ static void grow_gen_buffer(sed_eval_t *eval, int newsize,
|
||||
/*
|
||||
* appendmem_to_linebuf
|
||||
*/
|
||||
-static void appendmem_to_linebuf(sed_eval_t *eval, const char* sz, int len)
|
||||
+static void appendmem_to_linebuf(sed_eval_t *eval, const char* sz, apr_size_t len)
|
||||
{
|
||||
- unsigned int reqsize = (eval->lspend - eval->linebuf) + len;
|
||||
+ apr_size_t reqsize = (eval->lspend - eval->linebuf) + len;
|
||||
if (eval->lsize < reqsize) {
|
||||
grow_line_buffer(eval, reqsize);
|
||||
}
|
||||
@@ -169,21 +169,36 @@ static void appendmem_to_linebuf(sed_eval_t *eval, const char* sz, int len)
|
||||
/*
|
||||
* append_to_linebuf
|
||||
*/
|
||||
-static void append_to_linebuf(sed_eval_t *eval, const char* sz)
|
||||
+static void append_to_linebuf(sed_eval_t *eval, const char* sz,
|
||||
+ step_vars_storage *step_vars)
|
||||
{
|
||||
- int len = strlen(sz);
|
||||
+ apr_size_t len = strlen(sz);
|
||||
+ char *old_linebuf = eval->linebuf;
|
||||
/* Copy string including null character */
|
||||
appendmem_to_linebuf(eval, sz, len + 1);
|
||||
--eval->lspend; /* lspend will now point to NULL character */
|
||||
+ /* Sync step_vars after a possible linebuf expansion */
|
||||
+ if (step_vars && old_linebuf != eval->linebuf) {
|
||||
+ if (step_vars->loc1) {
|
||||
+ step_vars->loc1 = step_vars->loc1 - old_linebuf + eval->linebuf;
|
||||
+ }
|
||||
+ if (step_vars->loc2) {
|
||||
+ step_vars->loc2 = step_vars->loc2 - old_linebuf + eval->linebuf;
|
||||
+ }
|
||||
+ if (step_vars->locs) {
|
||||
+ step_vars->locs = step_vars->locs - old_linebuf + eval->linebuf;
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
|
||||
/*
|
||||
* copy_to_linebuf
|
||||
*/
|
||||
-static void copy_to_linebuf(sed_eval_t *eval, const char* sz)
|
||||
+static void copy_to_linebuf(sed_eval_t *eval, const char* sz,
|
||||
+ step_vars_storage *step_vars)
|
||||
{
|
||||
eval->lspend = eval->linebuf;
|
||||
- append_to_linebuf(eval, sz);
|
||||
+ append_to_linebuf(eval, sz, step_vars);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -191,8 +206,8 @@ static void copy_to_linebuf(sed_eval_t *eval, const char* sz)
|
||||
*/
|
||||
static void append_to_holdbuf(sed_eval_t *eval, const char* sz)
|
||||
{
|
||||
- int len = strlen(sz);
|
||||
- unsigned int reqsize = (eval->hspend - eval->holdbuf) + len + 1;
|
||||
+ apr_size_t len = strlen(sz);
|
||||
+ apr_size_t reqsize = (eval->hspend - eval->holdbuf) + len + 1;
|
||||
if (eval->hsize <= reqsize) {
|
||||
grow_hold_buffer(eval, reqsize);
|
||||
}
|
||||
@@ -215,8 +230,8 @@ static void copy_to_holdbuf(sed_eval_t *eval, const char* sz)
|
||||
*/
|
||||
static void append_to_genbuf(sed_eval_t *eval, const char* sz, char **gspend)
|
||||
{
|
||||
- int len = strlen(sz);
|
||||
- unsigned int reqsize = (*gspend - eval->genbuf) + len + 1;
|
||||
+ apr_size_t len = strlen(sz);
|
||||
+ apr_size_t reqsize = (*gspend - eval->genbuf) + len + 1;
|
||||
if (eval->gsize < reqsize) {
|
||||
grow_gen_buffer(eval, reqsize, gspend);
|
||||
}
|
||||
@@ -230,8 +245,8 @@ static void append_to_genbuf(sed_eval_t *eval, const char* sz, char **gspend)
|
||||
*/
|
||||
static void copy_to_genbuf(sed_eval_t *eval, const char* sz)
|
||||
{
|
||||
- int len = strlen(sz);
|
||||
- unsigned int reqsize = len + 1;
|
||||
+ apr_size_t len = strlen(sz);
|
||||
+ apr_size_t reqsize = len + 1;
|
||||
if (eval->gsize < reqsize) {
|
||||
grow_gen_buffer(eval, reqsize, NULL);
|
||||
}
|
||||
@@ -353,7 +368,7 @@ apr_status_t sed_eval_file(sed_eval_t *eval, apr_file_t *fin, void *fout)
|
||||
/*
|
||||
* sed_eval_buffer
|
||||
*/
|
||||
-apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, int bufsz, void *fout)
|
||||
+apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, apr_size_t bufsz, void *fout)
|
||||
{
|
||||
apr_status_t rv;
|
||||
|
||||
@@ -383,7 +398,7 @@ apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, int bufsz, void
|
||||
|
||||
while (bufsz) {
|
||||
char *n;
|
||||
- int llen;
|
||||
+ apr_size_t llen;
|
||||
|
||||
n = memchr(buf, '\n', bufsz);
|
||||
if (n == NULL)
|
||||
@@ -442,7 +457,7 @@ apr_status_t sed_finalize_eval(sed_eval_t *eval, void *fout)
|
||||
* buffer is not a newline.
|
||||
*/
|
||||
/* Assure space for NULL */
|
||||
- append_to_linebuf(eval, "");
|
||||
+ append_to_linebuf(eval, "", NULL);
|
||||
}
|
||||
|
||||
*eval->lspend = '\0';
|
||||
@@ -666,7 +681,7 @@ static apr_status_t dosub(sed_eval_t *eval, char *rhsbuf, int n,
|
||||
lp = step_vars->loc2;
|
||||
step_vars->loc2 = sp - eval->genbuf + eval->linebuf;
|
||||
append_to_genbuf(eval, lp, &sp);
|
||||
- copy_to_linebuf(eval, eval->genbuf);
|
||||
+ copy_to_linebuf(eval, eval->genbuf, step_vars);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -676,8 +691,8 @@ static apr_status_t dosub(sed_eval_t *eval, char *rhsbuf, int n,
|
||||
static char *place(sed_eval_t *eval, char *asp, char *al1, char *al2)
|
||||
{
|
||||
char *sp = asp;
|
||||
- int n = al2 - al1;
|
||||
- unsigned int reqsize = (sp - eval->genbuf) + n + 1;
|
||||
+ apr_size_t n = al2 - al1;
|
||||
+ apr_size_t reqsize = (sp - eval->genbuf) + n + 1;
|
||||
|
||||
if (eval->gsize < reqsize) {
|
||||
grow_gen_buffer(eval, reqsize, &sp);
|
||||
@@ -735,7 +750,7 @@ static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc,
|
||||
}
|
||||
|
||||
p1++;
|
||||
- copy_to_linebuf(eval, p1);
|
||||
+ copy_to_linebuf(eval, p1, step_vars);
|
||||
eval->jflag++;
|
||||
break;
|
||||
|
||||
@@ -745,12 +760,12 @@ static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc,
|
||||
break;
|
||||
|
||||
case GCOM:
|
||||
- copy_to_linebuf(eval, eval->holdbuf);
|
||||
+ copy_to_linebuf(eval, eval->holdbuf, step_vars);
|
||||
break;
|
||||
|
||||
case CGCOM:
|
||||
- append_to_linebuf(eval, "\n");
|
||||
- append_to_linebuf(eval, eval->holdbuf);
|
||||
+ append_to_linebuf(eval, "\n", step_vars);
|
||||
+ append_to_linebuf(eval, eval->holdbuf, step_vars);
|
||||
break;
|
||||
|
||||
case HCOM:
|
||||
@@ -881,7 +896,7 @@ static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc,
|
||||
if (rv != APR_SUCCESS)
|
||||
return rv;
|
||||
}
|
||||
- append_to_linebuf(eval, "\n");
|
||||
+ append_to_linebuf(eval, "\n", step_vars);
|
||||
eval->pending = ipc->next;
|
||||
break;
|
||||
|
||||
@@ -956,7 +971,7 @@ static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc,
|
||||
|
||||
case XCOM:
|
||||
copy_to_genbuf(eval, eval->linebuf);
|
||||
- copy_to_linebuf(eval, eval->holdbuf);
|
||||
+ copy_to_linebuf(eval, eval->holdbuf, step_vars);
|
||||
copy_to_holdbuf(eval, eval->genbuf);
|
||||
break;
|
||||
|
||||
@@ -1013,7 +1028,7 @@ static apr_status_t arout(sed_eval_t *eval)
|
||||
/*
|
||||
* wline
|
||||
*/
|
||||
-static apr_status_t wline(sed_eval_t *eval, char *buf, int sz)
|
||||
+static apr_status_t wline(sed_eval_t *eval, char *buf, apr_size_t sz)
|
||||
{
|
||||
apr_status_t rv = APR_SUCCESS;
|
||||
rv = eval->writefn(eval->fout, buf, sz);
|
@ -1,26 +0,0 @@
|
||||
diff --git a/modules/proxy/mod_proxy_ajp.c b/modules/proxy/mod_proxy_ajp.c
|
||||
index 6faabea..058b03f 100644
|
||||
--- a/modules/proxy/mod_proxy_ajp.c
|
||||
+++ b/modules/proxy/mod_proxy_ajp.c
|
||||
@@ -249,9 +249,18 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r,
|
||||
/* read the first bloc of data */
|
||||
input_brigade = apr_brigade_create(p, r->connection->bucket_alloc);
|
||||
tenc = apr_table_get(r->headers_in, "Transfer-Encoding");
|
||||
- if (tenc && (strcasecmp(tenc, "chunked") == 0)) {
|
||||
- /* The AJP protocol does not want body data yet */
|
||||
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00870) "request is chunked");
|
||||
+ if (tenc) {
|
||||
+ if (ap_cstr_casecmp(tenc, "chunked") == 0) {
|
||||
+ /* The AJP protocol does not want body data yet */
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00870)
|
||||
+ "request is chunked");
|
||||
+ }
|
||||
+ else {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10396)
|
||||
+ "%s Transfer-Encoding is not supported",
|
||||
+ tenc);
|
||||
+ return HTTP_INTERNAL_SERVER_ERROR;
|
||||
+ }
|
||||
} else {
|
||||
/* Get client provided Content-Length header */
|
||||
content_length = get_content_length(r);
|
@ -1,47 +0,0 @@
|
||||
diff --git a/include/http_protocol.h b/include/http_protocol.h
|
||||
index e1572dc..8ed77ac 100644
|
||||
--- a/include/http_protocol.h
|
||||
+++ b/include/http_protocol.h
|
||||
@@ -439,7 +439,27 @@ AP_DECLARE(int) ap_rwrite(const void *buf, int nbyte, request_rec *r);
|
||||
*/
|
||||
static APR_INLINE int ap_rputs(const char *str, request_rec *r)
|
||||
{
|
||||
- return ap_rwrite(str, (int)strlen(str), r);
|
||||
+ apr_size_t len;
|
||||
+
|
||||
+ len = strlen(str);
|
||||
+
|
||||
+ for (;;) {
|
||||
+ if (len <= INT_MAX) {
|
||||
+ return ap_rwrite(str, (int)len, r);
|
||||
+ }
|
||||
+ else {
|
||||
+ int rc;
|
||||
+
|
||||
+ rc = ap_rwrite(str, INT_MAX, r);
|
||||
+ if (rc < 0) {
|
||||
+ return rc;
|
||||
+ }
|
||||
+ else {
|
||||
+ str += INT_MAX;
|
||||
+ len -= INT_MAX;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
|
||||
/**
|
||||
diff --git a/server/protocol.c b/server/protocol.c
|
||||
index a554970..ea461a2 100644
|
||||
--- a/server/protocol.c
|
||||
+++ b/server/protocol.c
|
||||
@@ -2107,6 +2107,9 @@ AP_DECLARE(int) ap_rputc(int c, request_rec *r)
|
||||
|
||||
AP_DECLARE(int) ap_rwrite(const void *buf, int nbyte, request_rec *r)
|
||||
{
|
||||
+ if (nbyte < 0)
|
||||
+ return -1;
|
||||
+
|
||||
if (r->connection->aborted)
|
||||
return -1;
|
||||
|
@ -1,22 +0,0 @@
|
||||
diff --git a/server/util.c b/server/util.c
|
||||
index eefdafa..45051b7 100644
|
||||
--- a/server/util.c
|
||||
+++ b/server/util.c
|
||||
@@ -186,7 +186,7 @@ AP_DECLARE(char *) ap_ht_time(apr_pool_t *p, apr_time_t t, const char *fmt,
|
||||
*/
|
||||
AP_DECLARE(int) ap_strcmp_match(const char *str, const char *expected)
|
||||
{
|
||||
- int x, y;
|
||||
+ apr_size_t x, y;
|
||||
|
||||
for (x = 0, y = 0; expected[y]; ++y, ++x) {
|
||||
if ((!str[x]) && (expected[y] != '*'))
|
||||
@@ -210,7 +210,7 @@ AP_DECLARE(int) ap_strcmp_match(const char *str, const char *expected)
|
||||
|
||||
AP_DECLARE(int) ap_strcasecmp_match(const char *str, const char *expected)
|
||||
{
|
||||
- int x, y;
|
||||
+ apr_size_t x, y;
|
||||
|
||||
for (x = 0, y = 0; expected[y]; ++y, ++x) {
|
||||
if (!str[x] && expected[y] != '*')
|
@ -1,90 +0,0 @@
|
||||
diff --git a/docs/manual/mod/core.html.en b/docs/manual/mod/core.html.en
|
||||
index e1ec8d0..833fa7b 100644
|
||||
--- a/docs/manual/mod/core.html.en
|
||||
+++ b/docs/manual/mod/core.html.en
|
||||
@@ -2748,16 +2748,16 @@ subrequests</td></tr>
|
||||
<tr><th><a href="directive-dict.html#Description">Description:</a></th><td>Restricts the total size of the HTTP request body sent
|
||||
from the client</td></tr>
|
||||
<tr><th><a href="directive-dict.html#Syntax">Syntax:</a></th><td><code>LimitRequestBody <var>bytes</var></code></td></tr>
|
||||
-<tr><th><a href="directive-dict.html#Default">Default:</a></th><td><code>LimitRequestBody 0</code></td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Default">Default:</a></th><td><code>LimitRequestBody 1073741824</code></td></tr>
|
||||
<tr><th><a href="directive-dict.html#Context">Context:</a></th><td>server config, virtual host, directory, .htaccess</td></tr>
|
||||
<tr><th><a href="directive-dict.html#Override">Override:</a></th><td>All</td></tr>
|
||||
<tr><th><a href="directive-dict.html#Status">Status:</a></th><td>Core</td></tr>
|
||||
<tr><th><a href="directive-dict.html#Module">Module:</a></th><td>core</td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Compatibility">Compatibility:</a></th><td>In Apache HTTP Server 2.4.53 and earlier, the default value
|
||||
+ was 0 (unlimited)</td></tr>
|
||||
</table>
|
||||
- <p>This directive specifies the number of <var>bytes</var> from 0
|
||||
- (meaning unlimited) to 2147483647 (2GB) that are allowed in a
|
||||
- request body. See the note below for the limited applicability
|
||||
- to proxy requests.</p>
|
||||
+ <p>This directive specifies the number of <var>bytes</var>
|
||||
+ that are allowed in a request body. A value of <var>0</var> means unlimited.</p>
|
||||
|
||||
<p>The <code class="directive">LimitRequestBody</code> directive allows
|
||||
the user to set a limit on the allowed size of an HTTP request
|
||||
@@ -2783,12 +2783,6 @@ from the client</td></tr>
|
||||
|
||||
<pre class="prettyprint lang-config">LimitRequestBody 102400</pre>
|
||||
|
||||
-
|
||||
- <div class="note"><p>For a full description of how this directive is interpreted by
|
||||
- proxy requests, see the <code class="module"><a href="../mod/mod_proxy.html">mod_proxy</a></code> documentation.</p>
|
||||
- </div>
|
||||
-
|
||||
-
|
||||
</div>
|
||||
<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
|
||||
<div class="directive-section"><h2><a name="LimitRequestFields" id="LimitRequestFields">LimitRequestFields</a> <a name="limitrequestfields" id="limitrequestfields">Directive</a></h2>
|
||||
diff --git a/docs/manual/mod/mod_proxy.html.en b/docs/manual/mod/mod_proxy.html.en
|
||||
index 2cc6ace..c9e4634 100644
|
||||
--- a/docs/manual/mod/mod_proxy.html.en
|
||||
+++ b/docs/manual/mod/mod_proxy.html.en
|
||||
@@ -459,9 +459,6 @@ ProxyPass "/examples" "http://backend.example.com/examples" timeout=10</pre>
|
||||
Content-Length header, but the server is configured to filter incoming
|
||||
request bodies.</p>
|
||||
|
||||
- <p><code class="directive"><a href="../mod/core.html#limitrequestbody">LimitRequestBody</a></code> only applies to
|
||||
- request bodies that the server will spool to disk</p>
|
||||
-
|
||||
</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
|
||||
<div class="section">
|
||||
<h2><a name="x-headers" id="x-headers">Reverse Proxy Request Headers</a></h2>
|
||||
diff --git a/modules/http/http_filters.c b/modules/http/http_filters.c
|
||||
index 6bedcac..393343a 100644
|
||||
--- a/modules/http/http_filters.c
|
||||
+++ b/modules/http/http_filters.c
|
||||
@@ -1710,6 +1710,7 @@ AP_DECLARE(int) ap_setup_client_block(request_rec *r, int read_policy)
|
||||
{
|
||||
const char *tenc = apr_table_get(r->headers_in, "Transfer-Encoding");
|
||||
const char *lenp = apr_table_get(r->headers_in, "Content-Length");
|
||||
+ apr_off_t limit_req_body = ap_get_limit_req_body(r);
|
||||
|
||||
r->read_body = read_policy;
|
||||
r->read_chunked = 0;
|
||||
@@ -1748,6 +1749,11 @@ AP_DECLARE(int) ap_setup_client_block(request_rec *r, int read_policy)
|
||||
return HTTP_REQUEST_ENTITY_TOO_LARGE;
|
||||
}
|
||||
|
||||
+ if (limit_req_body > 0 && (r->remaining > limit_req_body)) {
|
||||
+ /* will be logged when the body is discarded */
|
||||
+ return HTTP_REQUEST_ENTITY_TOO_LARGE;
|
||||
+ }
|
||||
+
|
||||
#ifdef AP_DEBUG
|
||||
{
|
||||
/* Make sure ap_getline() didn't leave any droppings. */
|
||||
diff --git a/server/core.c b/server/core.c
|
||||
index a0bfaad..6556f20 100644
|
||||
--- a/server/core.c
|
||||
+++ b/server/core.c
|
||||
@@ -65,7 +65,7 @@
|
||||
|
||||
/* LimitRequestBody handling */
|
||||
#define AP_LIMIT_REQ_BODY_UNSET ((apr_off_t) -1)
|
||||
-#define AP_DEFAULT_LIMIT_REQ_BODY ((apr_off_t) 0)
|
||||
+#define AP_DEFAULT_LIMIT_REQ_BODY ((apr_off_t) 1<<30) /* 1GB */
|
||||
|
||||
/* LimitXMLRequestBody handling */
|
||||
#define AP_LIMIT_UNSET ((long) -1)
|
@ -1,541 +0,0 @@
|
||||
diff --git a/modules/filters/mod_sed.c b/modules/filters/mod_sed.c
|
||||
index 8595e41..9b99a6b 100644
|
||||
--- a/modules/filters/mod_sed.c
|
||||
+++ b/modules/filters/mod_sed.c
|
||||
@@ -59,7 +59,7 @@ typedef struct sed_filter_ctxt
|
||||
module AP_MODULE_DECLARE_DATA sed_module;
|
||||
|
||||
/* This function will be call back from libsed functions if there is any error
|
||||
- * happend during execution of sed scripts
|
||||
+ * happened during execution of sed scripts
|
||||
*/
|
||||
static apr_status_t log_sed_errf(void *data, const char *error)
|
||||
{
|
||||
@@ -276,7 +276,7 @@ static apr_status_t sed_response_filter(ap_filter_t *f,
|
||||
apr_bucket_brigade *bb)
|
||||
{
|
||||
apr_bucket *b;
|
||||
- apr_status_t status;
|
||||
+ apr_status_t status = APR_SUCCESS;
|
||||
sed_config *cfg = ap_get_module_config(f->r->per_dir_config,
|
||||
&sed_module);
|
||||
sed_filter_ctxt *ctx = f->ctx;
|
||||
@@ -301,9 +301,9 @@ static apr_status_t sed_response_filter(ap_filter_t *f,
|
||||
return status;
|
||||
ctx = f->ctx;
|
||||
apr_table_unset(f->r->headers_out, "Content-Length");
|
||||
- }
|
||||
|
||||
- ctx->bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);
|
||||
+ ctx->bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);
|
||||
+ }
|
||||
|
||||
/* Here is the main logic. Iterate through all the buckets, read the
|
||||
* content of the bucket, call sed_eval_buffer on the data.
|
||||
@@ -325,63 +325,52 @@ static apr_status_t sed_response_filter(ap_filter_t *f,
|
||||
* in sed's internal buffer which can't be flushed until new line
|
||||
* character is arrived.
|
||||
*/
|
||||
- for (b = APR_BRIGADE_FIRST(bb); b != APR_BRIGADE_SENTINEL(bb);) {
|
||||
- const char *buf = NULL;
|
||||
- apr_size_t bytes = 0;
|
||||
+ while (!APR_BRIGADE_EMPTY(bb)) {
|
||||
+ b = APR_BRIGADE_FIRST(bb);
|
||||
if (APR_BUCKET_IS_EOS(b)) {
|
||||
- apr_bucket *b1 = APR_BUCKET_NEXT(b);
|
||||
/* Now clean up the internal sed buffer */
|
||||
sed_finalize_eval(&ctx->eval, ctx);
|
||||
status = flush_output_buffer(ctx);
|
||||
if (status != APR_SUCCESS) {
|
||||
- clear_ctxpool(ctx);
|
||||
- return status;
|
||||
+ break;
|
||||
}
|
||||
+ /* Move the eos bucket to ctx->bb brigade */
|
||||
APR_BUCKET_REMOVE(b);
|
||||
- /* Insert the eos bucket to ctx->bb brigade */
|
||||
APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
|
||||
- b = b1;
|
||||
}
|
||||
else if (APR_BUCKET_IS_FLUSH(b)) {
|
||||
- apr_bucket *b1 = APR_BUCKET_NEXT(b);
|
||||
- APR_BUCKET_REMOVE(b);
|
||||
status = flush_output_buffer(ctx);
|
||||
if (status != APR_SUCCESS) {
|
||||
- clear_ctxpool(ctx);
|
||||
- return status;
|
||||
+ break;
|
||||
}
|
||||
+ /* Move the flush bucket to ctx->bb brigade */
|
||||
+ APR_BUCKET_REMOVE(b);
|
||||
APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
|
||||
- b = b1;
|
||||
- }
|
||||
- else if (APR_BUCKET_IS_METADATA(b)) {
|
||||
- b = APR_BUCKET_NEXT(b);
|
||||
}
|
||||
- else if (apr_bucket_read(b, &buf, &bytes, APR_BLOCK_READ)
|
||||
- == APR_SUCCESS) {
|
||||
- apr_bucket *b1 = APR_BUCKET_NEXT(b);
|
||||
- status = sed_eval_buffer(&ctx->eval, buf, bytes, ctx);
|
||||
- if (status != APR_SUCCESS) {
|
||||
- clear_ctxpool(ctx);
|
||||
- return status;
|
||||
+ else {
|
||||
+ if (!APR_BUCKET_IS_METADATA(b)) {
|
||||
+ const char *buf = NULL;
|
||||
+ apr_size_t bytes = 0;
|
||||
+
|
||||
+ status = apr_bucket_read(b, &buf, &bytes, APR_BLOCK_READ);
|
||||
+ if (status == APR_SUCCESS) {
|
||||
+ status = sed_eval_buffer(&ctx->eval, buf, bytes, ctx);
|
||||
+ }
|
||||
+ if (status != APR_SUCCESS) {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, status, f->r, APLOGNO(10394) "error evaluating sed on output");
|
||||
+ break;
|
||||
+ }
|
||||
}
|
||||
- APR_BUCKET_REMOVE(b);
|
||||
apr_bucket_delete(b);
|
||||
- b = b1;
|
||||
- }
|
||||
- else {
|
||||
- apr_bucket *b1 = APR_BUCKET_NEXT(b);
|
||||
- APR_BUCKET_REMOVE(b);
|
||||
- b = b1;
|
||||
}
|
||||
}
|
||||
- apr_brigade_cleanup(bb);
|
||||
- status = flush_output_buffer(ctx);
|
||||
- if (status != APR_SUCCESS) {
|
||||
- clear_ctxpool(ctx);
|
||||
- return status;
|
||||
+ if (status == APR_SUCCESS) {
|
||||
+ status = flush_output_buffer(ctx);
|
||||
}
|
||||
if (!APR_BRIGADE_EMPTY(ctx->bb)) {
|
||||
- status = ap_pass_brigade(f->next, ctx->bb);
|
||||
+ if (status == APR_SUCCESS) {
|
||||
+ status = ap_pass_brigade(f->next, ctx->bb);
|
||||
+ }
|
||||
apr_brigade_cleanup(ctx->bb);
|
||||
}
|
||||
clear_ctxpool(ctx);
|
||||
@@ -432,7 +421,7 @@ static apr_status_t sed_request_filter(ap_filter_t *f,
|
||||
* the buckets in bbinp and read the data from buckets and invoke
|
||||
* sed_eval_buffer on the data. libsed will generate its output using
|
||||
* sed_write_output which will add data in ctx->bb. Do it until it have
|
||||
- * atleast one bucket in ctx->bb. At the end of data eos bucket
|
||||
+ * at least one bucket in ctx->bb. At the end of data eos bucket
|
||||
* should be there.
|
||||
*
|
||||
* Once eos bucket is seen, then invoke sed_finalize_eval to clear the
|
||||
@@ -474,8 +463,10 @@ static apr_status_t sed_request_filter(ap_filter_t *f,
|
||||
if (apr_bucket_read(b, &buf, &bytes, APR_BLOCK_READ)
|
||||
== APR_SUCCESS) {
|
||||
status = sed_eval_buffer(&ctx->eval, buf, bytes, ctx);
|
||||
- if (status != APR_SUCCESS)
|
||||
+ if (status != APR_SUCCESS) {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, status, f->r, APLOGNO(10395) "error evaluating sed on input");
|
||||
return status;
|
||||
+ }
|
||||
flush_output_buffer(ctx);
|
||||
}
|
||||
}
|
||||
diff --git a/modules/filters/sed1.c b/modules/filters/sed1.c
|
||||
index 67a8d06..047f49b 100644
|
||||
--- a/modules/filters/sed1.c
|
||||
+++ b/modules/filters/sed1.c
|
||||
@@ -87,18 +87,20 @@ static void eval_errf(sed_eval_t *eval, const char *fmt, ...)
|
||||
}
|
||||
|
||||
#define INIT_BUF_SIZE 1024
|
||||
+#define MAX_BUF_SIZE 1024*8192
|
||||
|
||||
/*
|
||||
* grow_buffer
|
||||
*/
|
||||
-static void grow_buffer(apr_pool_t *pool, char **buffer,
|
||||
+static apr_status_t grow_buffer(apr_pool_t *pool, char **buffer,
|
||||
char **spend, apr_size_t *cursize,
|
||||
apr_size_t newsize)
|
||||
{
|
||||
char* newbuffer = NULL;
|
||||
apr_size_t spendsize = 0;
|
||||
- if (*cursize >= newsize)
|
||||
- return;
|
||||
+ if (*cursize >= newsize) {
|
||||
+ return APR_SUCCESS;
|
||||
+ }
|
||||
/* Avoid number of times realloc is called. It could cause huge memory
|
||||
* requirement if line size is huge e.g 2 MB */
|
||||
if (newsize < *cursize * 2) {
|
||||
@@ -107,6 +109,9 @@ static void grow_buffer(apr_pool_t *pool, char **buffer,
|
||||
|
||||
/* Align it to 4 KB boundary */
|
||||
newsize = (newsize + ((1 << 12) - 1)) & ~((1 << 12) - 1);
|
||||
+ if (newsize > MAX_BUF_SIZE) {
|
||||
+ return APR_ENOMEM;
|
||||
+ }
|
||||
newbuffer = apr_pcalloc(pool, newsize);
|
||||
if (*spend && *buffer && (*cursize > 0)) {
|
||||
spendsize = *spend - *buffer;
|
||||
@@ -119,63 +124,77 @@ static void grow_buffer(apr_pool_t *pool, char **buffer,
|
||||
if (spend != buffer) {
|
||||
*spend = *buffer + spendsize;
|
||||
}
|
||||
+ return APR_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* grow_line_buffer
|
||||
*/
|
||||
-static void grow_line_buffer(sed_eval_t *eval, apr_size_t newsize)
|
||||
+static apr_status_t grow_line_buffer(sed_eval_t *eval, apr_size_t newsize)
|
||||
{
|
||||
- grow_buffer(eval->pool, &eval->linebuf, &eval->lspend,
|
||||
+ return grow_buffer(eval->pool, &eval->linebuf, &eval->lspend,
|
||||
&eval->lsize, newsize);
|
||||
}
|
||||
|
||||
/*
|
||||
* grow_hold_buffer
|
||||
*/
|
||||
-static void grow_hold_buffer(sed_eval_t *eval, apr_size_t newsize)
|
||||
+static apr_status_t grow_hold_buffer(sed_eval_t *eval, apr_size_t newsize)
|
||||
{
|
||||
- grow_buffer(eval->pool, &eval->holdbuf, &eval->hspend,
|
||||
+ return grow_buffer(eval->pool, &eval->holdbuf, &eval->hspend,
|
||||
&eval->hsize, newsize);
|
||||
}
|
||||
|
||||
/*
|
||||
* grow_gen_buffer
|
||||
*/
|
||||
-static void grow_gen_buffer(sed_eval_t *eval, apr_size_t newsize,
|
||||
+static apr_status_t grow_gen_buffer(sed_eval_t *eval, apr_size_t newsize,
|
||||
char **gspend)
|
||||
{
|
||||
+ apr_status_t rc = 0;
|
||||
if (gspend == NULL) {
|
||||
gspend = &eval->genbuf;
|
||||
}
|
||||
- grow_buffer(eval->pool, &eval->genbuf, gspend,
|
||||
- &eval->gsize, newsize);
|
||||
- eval->lcomend = &eval->genbuf[71];
|
||||
+ rc = grow_buffer(eval->pool, &eval->genbuf, gspend,
|
||||
+ &eval->gsize, newsize);
|
||||
+ if (rc == APR_SUCCESS) {
|
||||
+ eval->lcomend = &eval->genbuf[71];
|
||||
+ }
|
||||
+ return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* appendmem_to_linebuf
|
||||
*/
|
||||
-static void appendmem_to_linebuf(sed_eval_t *eval, const char* sz, apr_size_t len)
|
||||
+static apr_status_t appendmem_to_linebuf(sed_eval_t *eval, const char* sz, apr_size_t len)
|
||||
{
|
||||
+ apr_status_t rc = 0;
|
||||
apr_size_t reqsize = (eval->lspend - eval->linebuf) + len;
|
||||
if (eval->lsize < reqsize) {
|
||||
- grow_line_buffer(eval, reqsize);
|
||||
+ rc = grow_line_buffer(eval, reqsize);
|
||||
+ if (rc != APR_SUCCESS) {
|
||||
+ return rc;
|
||||
+ }
|
||||
}
|
||||
memcpy(eval->lspend, sz, len);
|
||||
eval->lspend += len;
|
||||
+ return APR_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* append_to_linebuf
|
||||
*/
|
||||
-static void append_to_linebuf(sed_eval_t *eval, const char* sz,
|
||||
+static apr_status_t append_to_linebuf(sed_eval_t *eval, const char* sz,
|
||||
step_vars_storage *step_vars)
|
||||
{
|
||||
apr_size_t len = strlen(sz);
|
||||
char *old_linebuf = eval->linebuf;
|
||||
+ apr_status_t rc = 0;
|
||||
/* Copy string including null character */
|
||||
- appendmem_to_linebuf(eval, sz, len + 1);
|
||||
+ rc = appendmem_to_linebuf(eval, sz, len + 1);
|
||||
+ if (rc != APR_SUCCESS) {
|
||||
+ return rc;
|
||||
+ }
|
||||
--eval->lspend; /* lspend will now point to NULL character */
|
||||
/* Sync step_vars after a possible linebuf expansion */
|
||||
if (step_vars && old_linebuf != eval->linebuf) {
|
||||
@@ -189,68 +208,84 @@ static void append_to_linebuf(sed_eval_t *eval, const char* sz,
|
||||
step_vars->locs = step_vars->locs - old_linebuf + eval->linebuf;
|
||||
}
|
||||
}
|
||||
+ return APR_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* copy_to_linebuf
|
||||
*/
|
||||
-static void copy_to_linebuf(sed_eval_t *eval, const char* sz,
|
||||
+static apr_status_t copy_to_linebuf(sed_eval_t *eval, const char* sz,
|
||||
step_vars_storage *step_vars)
|
||||
{
|
||||
eval->lspend = eval->linebuf;
|
||||
- append_to_linebuf(eval, sz, step_vars);
|
||||
+ return append_to_linebuf(eval, sz, step_vars);
|
||||
}
|
||||
|
||||
/*
|
||||
* append_to_holdbuf
|
||||
*/
|
||||
-static void append_to_holdbuf(sed_eval_t *eval, const char* sz)
|
||||
+static apr_status_t append_to_holdbuf(sed_eval_t *eval, const char* sz)
|
||||
{
|
||||
apr_size_t len = strlen(sz);
|
||||
apr_size_t reqsize = (eval->hspend - eval->holdbuf) + len + 1;
|
||||
+ apr_status_t rc = 0;
|
||||
if (eval->hsize <= reqsize) {
|
||||
- grow_hold_buffer(eval, reqsize);
|
||||
+ rc = grow_hold_buffer(eval, reqsize);
|
||||
+ if (rc != APR_SUCCESS) {
|
||||
+ return rc;
|
||||
+ }
|
||||
}
|
||||
memcpy(eval->hspend, sz, len + 1);
|
||||
/* hspend will now point to NULL character */
|
||||
eval->hspend += len;
|
||||
+ return APR_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* copy_to_holdbuf
|
||||
*/
|
||||
-static void copy_to_holdbuf(sed_eval_t *eval, const char* sz)
|
||||
+static apr_status_t copy_to_holdbuf(sed_eval_t *eval, const char* sz)
|
||||
{
|
||||
eval->hspend = eval->holdbuf;
|
||||
- append_to_holdbuf(eval, sz);
|
||||
+ return append_to_holdbuf(eval, sz);
|
||||
}
|
||||
|
||||
/*
|
||||
* append_to_genbuf
|
||||
*/
|
||||
-static void append_to_genbuf(sed_eval_t *eval, const char* sz, char **gspend)
|
||||
+static apr_status_t append_to_genbuf(sed_eval_t *eval, const char* sz, char **gspend)
|
||||
{
|
||||
apr_size_t len = strlen(sz);
|
||||
apr_size_t reqsize = (*gspend - eval->genbuf) + len + 1;
|
||||
+ apr_status_t rc = 0;
|
||||
if (eval->gsize < reqsize) {
|
||||
- grow_gen_buffer(eval, reqsize, gspend);
|
||||
+ rc = grow_gen_buffer(eval, reqsize, gspend);
|
||||
+ if (rc != APR_SUCCESS) {
|
||||
+ return rc;
|
||||
+ }
|
||||
}
|
||||
memcpy(*gspend, sz, len + 1);
|
||||
/* *gspend will now point to NULL character */
|
||||
*gspend += len;
|
||||
+ return APR_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* copy_to_genbuf
|
||||
*/
|
||||
-static void copy_to_genbuf(sed_eval_t *eval, const char* sz)
|
||||
+static apr_status_t copy_to_genbuf(sed_eval_t *eval, const char* sz)
|
||||
{
|
||||
apr_size_t len = strlen(sz);
|
||||
apr_size_t reqsize = len + 1;
|
||||
+ apr_status_t rc = APR_SUCCESS;;
|
||||
if (eval->gsize < reqsize) {
|
||||
- grow_gen_buffer(eval, reqsize, NULL);
|
||||
+ rc = grow_gen_buffer(eval, reqsize, NULL);
|
||||
+ if (rc != APR_SUCCESS) {
|
||||
+ return rc;
|
||||
+ }
|
||||
}
|
||||
memcpy(eval->genbuf, sz, len + 1);
|
||||
+ return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -397,6 +432,7 @@ apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, apr_size_t bufsz
|
||||
}
|
||||
|
||||
while (bufsz) {
|
||||
+ apr_status_t rc = 0;
|
||||
char *n;
|
||||
apr_size_t llen;
|
||||
|
||||
@@ -411,7 +447,10 @@ apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, apr_size_t bufsz
|
||||
break;
|
||||
}
|
||||
|
||||
- appendmem_to_linebuf(eval, buf, llen + 1);
|
||||
+ rc = appendmem_to_linebuf(eval, buf, llen + 1);
|
||||
+ if (rc != APR_SUCCESS) {
|
||||
+ return rc;
|
||||
+ }
|
||||
--eval->lspend;
|
||||
/* replace new line character with NULL */
|
||||
*eval->lspend = '\0';
|
||||
@@ -426,7 +465,10 @@ apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, apr_size_t bufsz
|
||||
|
||||
/* Save the leftovers for later */
|
||||
if (bufsz) {
|
||||
- appendmem_to_linebuf(eval, buf, bufsz);
|
||||
+ apr_status_t rc = appendmem_to_linebuf(eval, buf, bufsz);
|
||||
+ if (rc != APR_SUCCESS) {
|
||||
+ return rc;
|
||||
+ }
|
||||
}
|
||||
|
||||
return APR_SUCCESS;
|
||||
@@ -448,6 +490,7 @@ apr_status_t sed_finalize_eval(sed_eval_t *eval, void *fout)
|
||||
/* Process leftovers */
|
||||
if (eval->lspend > eval->linebuf) {
|
||||
apr_status_t rv;
|
||||
+ apr_status_t rc = 0;
|
||||
|
||||
if (eval->lreadyflag) {
|
||||
eval->lreadyflag = 0;
|
||||
@@ -457,7 +500,10 @@ apr_status_t sed_finalize_eval(sed_eval_t *eval, void *fout)
|
||||
* buffer is not a newline.
|
||||
*/
|
||||
/* Assure space for NULL */
|
||||
- append_to_linebuf(eval, "", NULL);
|
||||
+ rc = append_to_linebuf(eval, "", NULL);
|
||||
+ if (rc != APR_SUCCESS) {
|
||||
+ return rc;
|
||||
+ }
|
||||
}
|
||||
|
||||
*eval->lspend = '\0';
|
||||
@@ -655,11 +701,15 @@ static apr_status_t dosub(sed_eval_t *eval, char *rhsbuf, int n,
|
||||
sp = eval->genbuf;
|
||||
rp = rhsbuf;
|
||||
sp = place(eval, sp, lp, step_vars->loc1);
|
||||
+ if (sp == NULL) {
|
||||
+ return APR_EGENERAL;
|
||||
+ }
|
||||
while ((c = *rp++) != 0) {
|
||||
if (c == '&') {
|
||||
sp = place(eval, sp, step_vars->loc1, step_vars->loc2);
|
||||
- if (sp == NULL)
|
||||
+ if (sp == NULL) {
|
||||
return APR_EGENERAL;
|
||||
+ }
|
||||
}
|
||||
else if (c == '\\') {
|
||||
c = *rp++;
|
||||
@@ -675,13 +725,19 @@ static apr_status_t dosub(sed_eval_t *eval, char *rhsbuf, int n,
|
||||
*sp++ = c;
|
||||
if (sp >= eval->genbuf + eval->gsize) {
|
||||
/* expand genbuf and set the sp appropriately */
|
||||
- grow_gen_buffer(eval, eval->gsize + 1024, &sp);
|
||||
+ rv = grow_gen_buffer(eval, eval->gsize + 1024, &sp);
|
||||
+ if (rv != APR_SUCCESS) {
|
||||
+ return rv;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
lp = step_vars->loc2;
|
||||
step_vars->loc2 = sp - eval->genbuf + eval->linebuf;
|
||||
- append_to_genbuf(eval, lp, &sp);
|
||||
- copy_to_linebuf(eval, eval->genbuf, step_vars);
|
||||
+ rv = append_to_genbuf(eval, lp, &sp);
|
||||
+ if (rv != APR_SUCCESS) {
|
||||
+ return rv;
|
||||
+ }
|
||||
+ rv = copy_to_linebuf(eval, eval->genbuf, step_vars);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -695,7 +751,10 @@ static char *place(sed_eval_t *eval, char *asp, char *al1, char *al2)
|
||||
apr_size_t reqsize = (sp - eval->genbuf) + n + 1;
|
||||
|
||||
if (eval->gsize < reqsize) {
|
||||
- grow_gen_buffer(eval, reqsize, &sp);
|
||||
+ apr_status_t rc = grow_gen_buffer(eval, reqsize, &sp);
|
||||
+ if (rc != APR_SUCCESS) {
|
||||
+ return NULL;
|
||||
+ }
|
||||
}
|
||||
memcpy(sp, al1, n);
|
||||
return sp + n;
|
||||
@@ -750,7 +809,8 @@ static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc,
|
||||
}
|
||||
|
||||
p1++;
|
||||
- copy_to_linebuf(eval, p1, step_vars);
|
||||
+ rv = copy_to_linebuf(eval, p1, step_vars);
|
||||
+ if (rv != APR_SUCCESS) return rv;
|
||||
eval->jflag++;
|
||||
break;
|
||||
|
||||
@@ -760,21 +820,27 @@ static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc,
|
||||
break;
|
||||
|
||||
case GCOM:
|
||||
- copy_to_linebuf(eval, eval->holdbuf, step_vars);
|
||||
+ rv = copy_to_linebuf(eval, eval->holdbuf, step_vars);
|
||||
+ if (rv != APR_SUCCESS) return rv;
|
||||
break;
|
||||
|
||||
case CGCOM:
|
||||
- append_to_linebuf(eval, "\n", step_vars);
|
||||
- append_to_linebuf(eval, eval->holdbuf, step_vars);
|
||||
+ rv = append_to_linebuf(eval, "\n", step_vars);
|
||||
+ if (rv != APR_SUCCESS) return rv;
|
||||
+ rv = append_to_linebuf(eval, eval->holdbuf, step_vars);
|
||||
+ if (rv != APR_SUCCESS) return rv;
|
||||
break;
|
||||
|
||||
case HCOM:
|
||||
- copy_to_holdbuf(eval, eval->linebuf);
|
||||
+ rv = copy_to_holdbuf(eval, eval->linebuf);
|
||||
+ if (rv != APR_SUCCESS) return rv;
|
||||
break;
|
||||
|
||||
case CHCOM:
|
||||
- append_to_holdbuf(eval, "\n");
|
||||
- append_to_holdbuf(eval, eval->linebuf);
|
||||
+ rv = append_to_holdbuf(eval, "\n");
|
||||
+ if (rv != APR_SUCCESS) return rv;
|
||||
+ rv = append_to_holdbuf(eval, eval->linebuf);
|
||||
+ if (rv != APR_SUCCESS) return rv;
|
||||
break;
|
||||
|
||||
case ICOM:
|
||||
@@ -896,7 +962,8 @@ static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc,
|
||||
if (rv != APR_SUCCESS)
|
||||
return rv;
|
||||
}
|
||||
- append_to_linebuf(eval, "\n", step_vars);
|
||||
+ rv = append_to_linebuf(eval, "\n", step_vars);
|
||||
+ if (rv != APR_SUCCESS) return rv;
|
||||
eval->pending = ipc->next;
|
||||
break;
|
||||
|
||||
@@ -970,9 +1037,12 @@ static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc,
|
||||
break;
|
||||
|
||||
case XCOM:
|
||||
- copy_to_genbuf(eval, eval->linebuf);
|
||||
- copy_to_linebuf(eval, eval->holdbuf, step_vars);
|
||||
- copy_to_holdbuf(eval, eval->genbuf);
|
||||
+ rv = copy_to_genbuf(eval, eval->linebuf);
|
||||
+ if (rv != APR_SUCCESS) return rv;
|
||||
+ rv = copy_to_linebuf(eval, eval->holdbuf, step_vars);
|
||||
+ if (rv != APR_SUCCESS) return rv;
|
||||
+ rv = copy_to_holdbuf(eval, eval->genbuf);
|
||||
+ if (rv != APR_SUCCESS) return rv;
|
||||
break;
|
||||
|
||||
case YCOM:
|
@ -1,233 +0,0 @@
|
||||
diff --git a/modules/lua/lua_request.c b/modules/lua/lua_request.c
|
||||
index ba63584..c1ba74a 100644
|
||||
--- a/modules/lua/lua_request.c
|
||||
+++ b/modules/lua/lua_request.c
|
||||
@@ -2193,23 +2193,20 @@ static int lua_websocket_greet(lua_State *L)
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static apr_status_t lua_websocket_readbytes(conn_rec* c, char* buffer,
|
||||
- apr_off_t len)
|
||||
+static apr_status_t lua_websocket_readbytes(conn_rec* c,
|
||||
+ apr_bucket_brigade *brigade,
|
||||
+ char* buffer, apr_off_t len)
|
||||
{
|
||||
- apr_bucket_brigade *brigade = apr_brigade_create(c->pool, c->bucket_alloc);
|
||||
+ apr_size_t delivered;
|
||||
apr_status_t rv;
|
||||
+
|
||||
rv = ap_get_brigade(c->input_filters, brigade, AP_MODE_READBYTES,
|
||||
APR_BLOCK_READ, len);
|
||||
if (rv == APR_SUCCESS) {
|
||||
- if (!APR_BRIGADE_EMPTY(brigade)) {
|
||||
- apr_bucket* bucket = APR_BRIGADE_FIRST(brigade);
|
||||
- const char* data = NULL;
|
||||
- apr_size_t data_length = 0;
|
||||
- rv = apr_bucket_read(bucket, &data, &data_length, APR_BLOCK_READ);
|
||||
- if (rv == APR_SUCCESS) {
|
||||
- memcpy(buffer, data, len);
|
||||
- }
|
||||
- apr_bucket_delete(bucket);
|
||||
+ delivered = len;
|
||||
+ rv = apr_brigade_flatten(brigade, buffer, &delivered);
|
||||
+ if ((rv == APR_SUCCESS) && (delivered < len)) {
|
||||
+ rv = APR_INCOMPLETE;
|
||||
}
|
||||
}
|
||||
apr_brigade_cleanup(brigade);
|
||||
@@ -2239,35 +2236,28 @@ static int lua_websocket_peek(lua_State *L)
|
||||
|
||||
static int lua_websocket_read(lua_State *L)
|
||||
{
|
||||
- apr_socket_t *sock;
|
||||
apr_status_t rv;
|
||||
int do_read = 1;
|
||||
int n = 0;
|
||||
- apr_size_t len = 1;
|
||||
apr_size_t plen = 0;
|
||||
unsigned short payload_short = 0;
|
||||
apr_uint64_t payload_long = 0;
|
||||
unsigned char *mask_bytes;
|
||||
char byte;
|
||||
- int plaintext;
|
||||
-
|
||||
-
|
||||
+ apr_bucket_brigade *brigade;
|
||||
+ conn_rec* c;
|
||||
+
|
||||
request_rec *r = ap_lua_check_request_rec(L, 1);
|
||||
- plaintext = ap_lua_ssl_is_https(r->connection) ? 0 : 1;
|
||||
+ c = r->connection;
|
||||
|
||||
-
|
||||
mask_bytes = apr_pcalloc(r->pool, 4);
|
||||
- sock = ap_get_conn_socket(r->connection);
|
||||
+
|
||||
+ brigade = apr_brigade_create(r->pool, c->bucket_alloc);
|
||||
|
||||
while (do_read) {
|
||||
do_read = 0;
|
||||
/* Get opcode and FIN bit */
|
||||
- if (plaintext) {
|
||||
- rv = apr_socket_recv(sock, &byte, &len);
|
||||
- }
|
||||
- else {
|
||||
- rv = lua_websocket_readbytes(r->connection, &byte, 1);
|
||||
- }
|
||||
+ rv = lua_websocket_readbytes(c, brigade, &byte, 1);
|
||||
if (rv == APR_SUCCESS) {
|
||||
unsigned char ubyte, fin, opcode, mask, payload;
|
||||
ubyte = (unsigned char)byte;
|
||||
@@ -2277,12 +2267,7 @@ static int lua_websocket_read(lua_State *L)
|
||||
opcode = ubyte & 0xf;
|
||||
|
||||
/* Get the payload length and mask bit */
|
||||
- if (plaintext) {
|
||||
- rv = apr_socket_recv(sock, &byte, &len);
|
||||
- }
|
||||
- else {
|
||||
- rv = lua_websocket_readbytes(r->connection, &byte, 1);
|
||||
- }
|
||||
+ rv = lua_websocket_readbytes(c, brigade, &byte, 1);
|
||||
if (rv == APR_SUCCESS) {
|
||||
ubyte = (unsigned char)byte;
|
||||
/* Mask is the first bit */
|
||||
@@ -2293,40 +2278,25 @@ static int lua_websocket_read(lua_State *L)
|
||||
|
||||
/* Extended payload? */
|
||||
if (payload == 126) {
|
||||
- len = 2;
|
||||
- if (plaintext) {
|
||||
- /* XXX: apr_socket_recv does not receive len bits, only up to len bits! */
|
||||
- rv = apr_socket_recv(sock, (char*) &payload_short, &len);
|
||||
- }
|
||||
- else {
|
||||
- rv = lua_websocket_readbytes(r->connection,
|
||||
- (char*) &payload_short, 2);
|
||||
- }
|
||||
- payload_short = ntohs(payload_short);
|
||||
+ rv = lua_websocket_readbytes(c, brigade,
|
||||
+ (char*) &payload_short, 2);
|
||||
|
||||
- if (rv == APR_SUCCESS) {
|
||||
- plen = payload_short;
|
||||
- }
|
||||
- else {
|
||||
+ if (rv != APR_SUCCESS) {
|
||||
return 0;
|
||||
}
|
||||
+
|
||||
+ plen = ntohs(payload_short);
|
||||
}
|
||||
/* Super duper extended payload? */
|
||||
if (payload == 127) {
|
||||
- len = 8;
|
||||
- if (plaintext) {
|
||||
- rv = apr_socket_recv(sock, (char*) &payload_long, &len);
|
||||
- }
|
||||
- else {
|
||||
- rv = lua_websocket_readbytes(r->connection,
|
||||
- (char*) &payload_long, 8);
|
||||
- }
|
||||
- if (rv == APR_SUCCESS) {
|
||||
- plen = ap_ntoh64(&payload_long);
|
||||
- }
|
||||
- else {
|
||||
+ rv = lua_websocket_readbytes(c, brigade,
|
||||
+ (char*) &payload_long, 8);
|
||||
+
|
||||
+ if (rv != APR_SUCCESS) {
|
||||
return 0;
|
||||
}
|
||||
+
|
||||
+ plen = ap_ntoh64(&payload_long);
|
||||
}
|
||||
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03210)
|
||||
"Websocket: Reading %" APR_SIZE_T_FMT " (%s) bytes, masking is %s. %s",
|
||||
@@ -2335,46 +2305,27 @@ static int lua_websocket_read(lua_State *L)
|
||||
mask ? "on" : "off",
|
||||
fin ? "This is a final frame" : "more to follow");
|
||||
if (mask) {
|
||||
- len = 4;
|
||||
- if (plaintext) {
|
||||
- rv = apr_socket_recv(sock, (char*) mask_bytes, &len);
|
||||
- }
|
||||
- else {
|
||||
- rv = lua_websocket_readbytes(r->connection,
|
||||
- (char*) mask_bytes, 4);
|
||||
- }
|
||||
+ rv = lua_websocket_readbytes(c, brigade,
|
||||
+ (char*) mask_bytes, 4);
|
||||
+
|
||||
if (rv != APR_SUCCESS) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (plen < (HUGE_STRING_LEN*1024) && plen > 0) {
|
||||
apr_size_t remaining = plen;
|
||||
- apr_size_t received;
|
||||
- apr_off_t at = 0;
|
||||
char *buffer = apr_palloc(r->pool, plen+1);
|
||||
buffer[plen] = 0;
|
||||
|
||||
- if (plaintext) {
|
||||
- while (remaining > 0) {
|
||||
- received = remaining;
|
||||
- rv = apr_socket_recv(sock, buffer+at, &received);
|
||||
- if (received > 0 ) {
|
||||
- remaining -= received;
|
||||
- at += received;
|
||||
- }
|
||||
- }
|
||||
- ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
|
||||
- "Websocket: Frame contained %" APR_OFF_T_FMT " bytes, pushed to Lua stack",
|
||||
- at);
|
||||
- }
|
||||
- else {
|
||||
- rv = lua_websocket_readbytes(r->connection, buffer,
|
||||
- remaining);
|
||||
- ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
|
||||
- "Websocket: SSL Frame contained %" APR_SIZE_T_FMT " bytes, "\
|
||||
- "pushed to Lua stack",
|
||||
- remaining);
|
||||
+ rv = lua_websocket_readbytes(c, brigade, buffer, remaining);
|
||||
+
|
||||
+ if (rv != APR_SUCCESS) {
|
||||
+ return 0;
|
||||
}
|
||||
+
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
|
||||
+ "Websocket: Frame contained %" APR_SIZE_T_FMT \
|
||||
+ " bytes, pushed to Lua stack", remaining);
|
||||
if (mask) {
|
||||
for (n = 0; n < plen; n++) {
|
||||
buffer[n] ^= mask_bytes[n%4];
|
||||
@@ -2386,14 +2337,25 @@ static int lua_websocket_read(lua_State *L)
|
||||
return 2;
|
||||
}
|
||||
|
||||
-
|
||||
/* Decide if we need to react to the opcode or not */
|
||||
if (opcode == 0x09) { /* ping */
|
||||
char frame[2];
|
||||
- plen = 2;
|
||||
+ apr_bucket *b;
|
||||
+
|
||||
frame[0] = 0x8A;
|
||||
frame[1] = 0;
|
||||
- apr_socket_send(sock, frame, &plen); /* Pong! */
|
||||
+
|
||||
+ /* Pong! */
|
||||
+ b = apr_bucket_transient_create(frame, 2, c->bucket_alloc);
|
||||
+ APR_BRIGADE_INSERT_TAIL(brigade, b);
|
||||
+
|
||||
+ rv = ap_pass_brigade(c->output_filters, brigade);
|
||||
+ apr_brigade_cleanup(brigade);
|
||||
+
|
||||
+ if (rv != APR_SUCCESS) {
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
do_read = 1;
|
||||
}
|
||||
}
|
@ -1,229 +0,0 @@
|
||||
diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c
|
||||
index efcc6ca..6626ea0 100644
|
||||
--- a/modules/proxy/proxy_util.c
|
||||
+++ b/modules/proxy/proxy_util.c
|
||||
@@ -3631,12 +3631,14 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p,
|
||||
char **old_cl_val,
|
||||
char **old_te_val)
|
||||
{
|
||||
+ int rc = OK;
|
||||
conn_rec *c = r->connection;
|
||||
int counter;
|
||||
char *buf;
|
||||
+ apr_table_t *saved_headers_in = r->headers_in;
|
||||
+ const char *saved_host = apr_table_get(saved_headers_in, "Host");
|
||||
const apr_array_header_t *headers_in_array;
|
||||
const apr_table_entry_t *headers_in;
|
||||
- apr_table_t *saved_headers_in;
|
||||
apr_bucket *e;
|
||||
int do_100_continue;
|
||||
conn_rec *origin = p_conn->connection;
|
||||
@@ -3672,6 +3674,52 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p,
|
||||
ap_xlate_proto_to_ascii(buf, strlen(buf));
|
||||
e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(header_brigade, e);
|
||||
+
|
||||
+ /*
|
||||
+ * Make a copy on r->headers_in for the request we make to the backend,
|
||||
+ * modify the copy in place according to our configuration and connection
|
||||
+ * handling, use it to fill in the forwarded headers' brigade, and finally
|
||||
+ * restore the saved/original ones in r->headers_in.
|
||||
+ *
|
||||
+ * Note: We need to take r->pool for apr_table_copy as the key / value
|
||||
+ * pairs in r->headers_in have been created out of r->pool and
|
||||
+ * p might be (and actually is) a longer living pool.
|
||||
+ * This would trigger the bad pool ancestry abort in apr_table_copy if
|
||||
+ * apr is compiled with APR_POOL_DEBUG.
|
||||
+ *
|
||||
+ * icing: if p indeed lives longer than r->pool, we should allocate
|
||||
+ * all new header values from r->pool as well and avoid leakage.
|
||||
+ */
|
||||
+ r->headers_in = apr_table_copy(r->pool, saved_headers_in);
|
||||
+
|
||||
+ /* Return the original Transfer-Encoding and/or Content-Length values
|
||||
+ * then drop the headers, they must be set by the proxy handler based
|
||||
+ * on the actual body being forwarded.
|
||||
+ */
|
||||
+ if ((*old_te_val = (char *)apr_table_get(r->headers_in,
|
||||
+ "Transfer-Encoding"))) {
|
||||
+ apr_table_unset(r->headers_in, "Transfer-Encoding");
|
||||
+ }
|
||||
+ if ((*old_cl_val = (char *)apr_table_get(r->headers_in,
|
||||
+ "Content-Length"))) {
|
||||
+ apr_table_unset(r->headers_in, "Content-Length");
|
||||
+ }
|
||||
+
|
||||
+ /* Clear out hop-by-hop request headers not to forward */
|
||||
+ if (ap_proxy_clear_connection(r, r->headers_in) < 0) {
|
||||
+ rc = HTTP_BAD_REQUEST;
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+
|
||||
+ /* RFC2616 13.5.1 says we should strip these */
|
||||
+ apr_table_unset(r->headers_in, "Keep-Alive");
|
||||
+ apr_table_unset(r->headers_in, "Upgrade");
|
||||
+ apr_table_unset(r->headers_in, "Trailer");
|
||||
+ apr_table_unset(r->headers_in, "TE");
|
||||
+
|
||||
+ /* We used to send `Host: ` always first, so let's keep it that
|
||||
+ * way. No telling which legacy backend is relying no this.
|
||||
+ */
|
||||
if (dconf->preserve_host == 0) {
|
||||
if (ap_strchr_c(uri->hostname, ':')) { /* if literal IPv6 address */
|
||||
if (uri->port_str && uri->port != DEFAULT_HTTP_PORT) {
|
||||
@@ -3693,7 +3741,7 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p,
|
||||
/* don't want to use r->hostname, as the incoming header might have a
|
||||
* port attached
|
||||
*/
|
||||
- const char* hostname = apr_table_get(r->headers_in,"Host");
|
||||
+ const char* hostname = saved_host;
|
||||
if (!hostname) {
|
||||
hostname = r->server->server_hostname;
|
||||
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01092)
|
||||
@@ -3707,21 +3755,7 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p,
|
||||
ap_xlate_proto_to_ascii(buf, strlen(buf));
|
||||
e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(header_brigade, e);
|
||||
-
|
||||
- /*
|
||||
- * Save the original headers in here and restore them when leaving, since
|
||||
- * we will apply proxy purpose only modifications (eg. clearing hop-by-hop
|
||||
- * headers, add Via or X-Forwarded-* or Expect...), whereas the originals
|
||||
- * will be needed later to prepare the correct response and logging.
|
||||
- *
|
||||
- * Note: We need to take r->pool for apr_table_copy as the key / value
|
||||
- * pairs in r->headers_in have been created out of r->pool and
|
||||
- * p might be (and actually is) a longer living pool.
|
||||
- * This would trigger the bad pool ancestry abort in apr_table_copy if
|
||||
- * apr is compiled with APR_POOL_DEBUG.
|
||||
- */
|
||||
- saved_headers_in = r->headers_in;
|
||||
- r->headers_in = apr_table_copy(r->pool, saved_headers_in);
|
||||
+ apr_table_unset(r->headers_in, "Host");
|
||||
|
||||
/* handle Via */
|
||||
if (conf->viaopt == via_block) {
|
||||
@@ -3788,8 +3822,6 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p,
|
||||
*/
|
||||
if (dconf->add_forwarded_headers) {
|
||||
if (PROXYREQ_REVERSE == r->proxyreq) {
|
||||
- const char *buf;
|
||||
-
|
||||
/* Add X-Forwarded-For: so that the upstream has a chance to
|
||||
* determine, where the original request came from.
|
||||
*/
|
||||
@@ -3799,8 +3831,9 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p,
|
||||
/* Add X-Forwarded-Host: so that upstream knows what the
|
||||
* original request hostname was.
|
||||
*/
|
||||
- if ((buf = apr_table_get(r->headers_in, "Host"))) {
|
||||
- apr_table_mergen(r->headers_in, "X-Forwarded-Host", buf);
|
||||
+ if (saved_host) {
|
||||
+ apr_table_mergen(r->headers_in, "X-Forwarded-Host",
|
||||
+ saved_host);
|
||||
}
|
||||
|
||||
/* Add X-Forwarded-Server: so that upstream knows what the
|
||||
@@ -3812,10 +3845,27 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p,
|
||||
}
|
||||
}
|
||||
|
||||
+ /* Do we want to strip Proxy-Authorization ?
|
||||
+ * If we haven't used it, then NO
|
||||
+ * If we have used it then MAYBE: RFC2616 says we MAY propagate it.
|
||||
+ * So let's make it configurable by env.
|
||||
+ */
|
||||
+ if (r->user != NULL /* we've authenticated */
|
||||
+ && !apr_table_get(r->subprocess_env, "Proxy-Chain-Auth")) {
|
||||
+ apr_table_unset(r->headers_in, "Proxy-Authorization");
|
||||
+ }
|
||||
+
|
||||
+ /* for sub-requests, ignore freshness/expiry headers */
|
||||
+ if (r->main) {
|
||||
+ apr_table_unset(r->headers_in, "If-Match");
|
||||
+ apr_table_unset(r->headers_in, "If-Modified-Since");
|
||||
+ apr_table_unset(r->headers_in, "If-Range");
|
||||
+ apr_table_unset(r->headers_in, "If-Unmodified-Since");
|
||||
+ apr_table_unset(r->headers_in, "If-None-Match");
|
||||
+ }
|
||||
+
|
||||
+ /* run hook to fixup the request we are about to send */
|
||||
proxy_run_fixups(r);
|
||||
- if (ap_proxy_clear_connection(r, r->headers_in) < 0) {
|
||||
- return HTTP_BAD_REQUEST;
|
||||
- }
|
||||
|
||||
creds = apr_table_get(r->notes, "proxy-basic-creds");
|
||||
if (creds) {
|
||||
@@ -3827,55 +3877,8 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p,
|
||||
headers_in = (const apr_table_entry_t *) headers_in_array->elts;
|
||||
for (counter = 0; counter < headers_in_array->nelts; counter++) {
|
||||
if (headers_in[counter].key == NULL
|
||||
- || headers_in[counter].val == NULL
|
||||
-
|
||||
- /* Already sent */
|
||||
- || !strcasecmp(headers_in[counter].key, "Host")
|
||||
-
|
||||
- /* Clear out hop-by-hop request headers not to send
|
||||
- * RFC2616 13.5.1 says we should strip these headers
|
||||
- */
|
||||
- || !strcasecmp(headers_in[counter].key, "Keep-Alive")
|
||||
- || !strcasecmp(headers_in[counter].key, "TE")
|
||||
- || !strcasecmp(headers_in[counter].key, "Trailer")
|
||||
- || !strcasecmp(headers_in[counter].key, "Upgrade")
|
||||
-
|
||||
- ) {
|
||||
- continue;
|
||||
- }
|
||||
- /* Do we want to strip Proxy-Authorization ?
|
||||
- * If we haven't used it, then NO
|
||||
- * If we have used it then MAYBE: RFC2616 says we MAY propagate it.
|
||||
- * So let's make it configurable by env.
|
||||
- */
|
||||
- if (!strcasecmp(headers_in[counter].key,"Proxy-Authorization")) {
|
||||
- if (r->user != NULL) { /* we've authenticated */
|
||||
- if (!apr_table_get(r->subprocess_env, "Proxy-Chain-Auth")) {
|
||||
- continue;
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- /* Skip Transfer-Encoding and Content-Length for now.
|
||||
- */
|
||||
- if (!strcasecmp(headers_in[counter].key, "Transfer-Encoding")) {
|
||||
- *old_te_val = headers_in[counter].val;
|
||||
- continue;
|
||||
- }
|
||||
- if (!strcasecmp(headers_in[counter].key, "Content-Length")) {
|
||||
- *old_cl_val = headers_in[counter].val;
|
||||
- continue;
|
||||
- }
|
||||
-
|
||||
- /* for sub-requests, ignore freshness/expiry headers */
|
||||
- if (r->main) {
|
||||
- if ( !strcasecmp(headers_in[counter].key, "If-Match")
|
||||
- || !strcasecmp(headers_in[counter].key, "If-Modified-Since")
|
||||
- || !strcasecmp(headers_in[counter].key, "If-Range")
|
||||
- || !strcasecmp(headers_in[counter].key, "If-Unmodified-Since")
|
||||
- || !strcasecmp(headers_in[counter].key, "If-None-Match")) {
|
||||
- continue;
|
||||
- }
|
||||
+ || headers_in[counter].val == NULL) {
|
||||
+ continue;
|
||||
}
|
||||
|
||||
buf = apr_pstrcat(p, headers_in[counter].key, ": ",
|
||||
@@ -3886,11 +3889,9 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p,
|
||||
APR_BRIGADE_INSERT_TAIL(header_brigade, e);
|
||||
}
|
||||
|
||||
- /* Restore the original headers in (see comment above),
|
||||
- * we won't modify them anymore.
|
||||
- */
|
||||
+cleanup:
|
||||
r->headers_in = saved_headers_in;
|
||||
- return OK;
|
||||
+ return rc;
|
||||
}
|
||||
|
||||
PROXY_DECLARE(int) ap_proxy_prefetch_input(request_rec *r,
|
@ -1,23 +0,0 @@
|
||||
From 5efc9507c487c37dfe2a279a4a0335cad701cd5f Mon Sep 17 00:00:00 2001
|
||||
From: Eric Covener <covener@apache.org>
|
||||
Date: Tue, 10 Jan 2023 13:19:07 +0000
|
||||
Subject: [PATCH] cleanup on error
|
||||
|
||||
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1906540 13f79535-47bb-0310-9956-ffa450edef68
|
||||
---
|
||||
modules/proxy/mod_proxy_ajp.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/modules/proxy/mod_proxy_ajp.c b/modules/proxy/mod_proxy_ajp.c
|
||||
index 9cd7adbcbbf..07f37392d88 100644
|
||||
--- a/modules/proxy/mod_proxy_ajp.c
|
||||
+++ b/modules/proxy/mod_proxy_ajp.c
|
||||
@@ -255,6 +255,8 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r,
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10396)
|
||||
"%s Transfer-Encoding is not supported",
|
||||
tenc);
|
||||
+ /* We had a failure: Close connection to backend */
|
||||
+ conn->close = 1;
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
} else {
|
@ -1,129 +0,0 @@
|
||||
From 8b6d55f6a047acf62675e32606b037f5eea8ccc7 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Covener <covener@apache.org>
|
||||
Date: Tue, 10 Jan 2023 13:20:09 +0000
|
||||
Subject: [PATCH] Merge r1906539 from trunk:
|
||||
|
||||
fail on bad header
|
||||
|
||||
Submitted By: covener
|
||||
Reviewed By: covener, rpluem, gbechis
|
||||
|
||||
|
||||
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1906541 13f79535-47bb-0310-9956-ffa450edef68
|
||||
---
|
||||
modules/proxy/mod_proxy_http.c | 46 ++++++++++++++++++++--------------
|
||||
server/protocol.c | 2 ++
|
||||
2 files changed, 29 insertions(+), 19 deletions(-)
|
||||
|
||||
diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c
|
||||
index d74ae054ac9..ec4e7fb06b5 100644
|
||||
--- a/modules/proxy/mod_proxy_http.c
|
||||
+++ b/modules/proxy/mod_proxy_http.c
|
||||
@@ -788,7 +788,7 @@ static void process_proxy_header(request_rec *r, proxy_dir_conf *c,
|
||||
* any sense at all, since we depend on buffer still containing
|
||||
* what was read by ap_getline() upon return.
|
||||
*/
|
||||
-static void ap_proxy_read_headers(request_rec *r, request_rec *rr,
|
||||
+static apr_status_t ap_proxy_read_headers(request_rec *r, request_rec *rr,
|
||||
char *buffer, int size,
|
||||
conn_rec *c, int *pread_len)
|
||||
{
|
||||
@@ -820,19 +820,26 @@ static void ap_proxy_read_headers(request_rec *r, request_rec *rr,
|
||||
rc = ap_proxygetline(tmp_bb, buffer, size, rr,
|
||||
AP_GETLINE_FOLD | AP_GETLINE_NOSPC_EOL, &len);
|
||||
|
||||
- if (len <= 0)
|
||||
- break;
|
||||
|
||||
- if (APR_STATUS_IS_ENOSPC(rc)) {
|
||||
- /* The header could not fit in the provided buffer, warn.
|
||||
- * XXX: falls through with the truncated header, 5xx instead?
|
||||
- */
|
||||
- int trunc = (len > 128 ? 128 : len) / 2;
|
||||
- ap_log_rerror(APLOG_MARK, APLOG_WARNING, rc, r, APLOGNO(10124)
|
||||
- "header size is over the limit allowed by "
|
||||
- "ResponseFieldSize (%d bytes). "
|
||||
- "Bad response header: '%.*s[...]%s'",
|
||||
- size, trunc, buffer, buffer + len - trunc);
|
||||
+ if (rc != APR_SUCCESS) {
|
||||
+ if (APR_STATUS_IS_ENOSPC(rc)) {
|
||||
+ int trunc = (len > 128 ? 128 : len) / 2;
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, rc, r, APLOGNO(10124)
|
||||
+ "header size is over the limit allowed by "
|
||||
+ "ResponseFieldSize (%d bytes). "
|
||||
+ "Bad response header: '%.*s[...]%s'",
|
||||
+ size, trunc, buffer, buffer + len - trunc);
|
||||
+ }
|
||||
+ else {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, rc, r, APLOGNO(10404)
|
||||
+ "Error reading headers from backend");
|
||||
+ }
|
||||
+ r->headers_out = NULL;
|
||||
+ return rc;
|
||||
+ }
|
||||
+
|
||||
+ if (len <= 0) {
|
||||
+ break;
|
||||
}
|
||||
else {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_TRACE4, 0, r, "%s", buffer);
|
||||
@@ -855,7 +862,7 @@ static void ap_proxy_read_headers(request_rec *r, request_rec *rr,
|
||||
if (psc->badopt == bad_error) {
|
||||
/* Nope, it wasn't even an extra HTTP header. Give up. */
|
||||
r->headers_out = NULL;
|
||||
- return;
|
||||
+ return APR_EINVAL;
|
||||
}
|
||||
else if (psc->badopt == bad_body) {
|
||||
/* if we've already started loading headers_out, then
|
||||
@@ -869,13 +876,13 @@ static void ap_proxy_read_headers(request_rec *r, request_rec *rr,
|
||||
"in headers returned by %s (%s)",
|
||||
r->uri, r->method);
|
||||
*pread_len = len;
|
||||
- return;
|
||||
+ return APR_SUCCESS;
|
||||
}
|
||||
else {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01099)
|
||||
"No HTTP headers returned by %s (%s)",
|
||||
r->uri, r->method);
|
||||
- return;
|
||||
+ return APR_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -905,6 +912,7 @@ static void ap_proxy_read_headers(request_rec *r, request_rec *rr,
|
||||
process_proxy_header(r, dconf, buffer, value);
|
||||
saw_headers = 1;
|
||||
}
|
||||
+ return APR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -1218,10 +1226,10 @@ int ap_proxy_http_process_response(proxy_http_req_t *req)
|
||||
"Set-Cookie", NULL);
|
||||
|
||||
/* shove the headers direct into r->headers_out */
|
||||
- ap_proxy_read_headers(r, backend->r, buffer, response_field_size,
|
||||
- origin, &pread_len);
|
||||
+ rc = ap_proxy_read_headers(r, backend->r, buffer, response_field_size,
|
||||
+ origin, &pread_len);
|
||||
|
||||
- if (r->headers_out == NULL) {
|
||||
+ if (rc != APR_SUCCESS || r->headers_out == NULL) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01106)
|
||||
"bad HTTP/%d.%d header returned by %s (%s)",
|
||||
major, minor, r->uri, r->method);
|
||||
diff --git a/server/protocol.c b/server/protocol.c
|
||||
index 7adc7f75c10..6f9540ad1de 100644
|
||||
--- a/server/protocol.c
|
||||
+++ b/server/protocol.c
|
||||
@@ -508,6 +508,8 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n,
|
||||
/* PR#43039: We shouldn't accept NULL bytes within the line */
|
||||
bytes_handled = strlen(*s);
|
||||
if (bytes_handled < *read) {
|
||||
+ ap_log_data(APLOG_MARK, APLOG_DEBUG, ap_server_conf,
|
||||
+ "NULL bytes in header", *s, *read, 0);
|
||||
*read = bytes_handled;
|
||||
if (rv == APR_SUCCESS) {
|
||||
rv = APR_EINVAL;
|
@ -1,586 +0,0 @@
|
||||
diff --git a/docs/manual/mod/mod_rewrite.html.en b/docs/manual/mod/mod_rewrite.html.en
|
||||
index 815ec72..2b8ed35 100644
|
||||
--- a/docs/manual/mod/mod_rewrite.html.en
|
||||
+++ b/docs/manual/mod/mod_rewrite.html.en
|
||||
@@ -1265,7 +1265,17 @@ cannot use <code>$N</code> in the substitution string!
|
||||
<td>B</td>
|
||||
<td>Escape non-alphanumeric characters in backreferences <em>before</em>
|
||||
applying the transformation. <em><a href="../rewrite/flags.html#flag_b">details ...</a></em></td>
|
||||
- </tr>
|
||||
+ </tr>
|
||||
+<tr class="odd">
|
||||
+ <td>BCTLS</td>
|
||||
+ <td>Like [B], but only escape control characters and spaces.
|
||||
+ <em><a href="../rewrite/flags.html#flag_bctls">details ...</a></em></td>
|
||||
+</tr>
|
||||
+ <tr>
|
||||
+ <td>BNE</td>
|
||||
+ <td>Characters of [B] or [BCTLS] which should <strong>not</strong> be escaped.
|
||||
+ <em><a href="../rewrite/flags.html#flag_bne">details ...</a></em></td>
|
||||
+ </tr>
|
||||
<tr class="odd">
|
||||
<td>backrefnoplus|BNP</td>
|
||||
<td>If backreferences are being escaped, spaces should be escaped to
|
||||
diff --git a/docs/manual/rewrite/flags.html.en b/docs/manual/rewrite/flags.html.en
|
||||
index 80d0759..734809a 100644
|
||||
--- a/docs/manual/rewrite/flags.html.en
|
||||
+++ b/docs/manual/rewrite/flags.html.en
|
||||
@@ -85,10 +85,6 @@ of how you might use them.</p>
|
||||
<h2><a name="flag_b" id="flag_b">B (escape backreferences)</a></h2>
|
||||
<p>The [B] flag instructs <code class="directive"><a href="../mod/mod_rewrite.html#rewriterule">RewriteRule</a></code> to escape non-alphanumeric
|
||||
characters before applying the transformation.</p>
|
||||
-<p>In 2.4.26 and later, you can limit the escaping to specific characters
|
||||
-in backreferences by listing them: <code>[B=#?;]</code>. Note: The space
|
||||
-character can be used in the list of characters to escape, but it cannot be
|
||||
-the last character in the list.</p>
|
||||
|
||||
<p><code>mod_rewrite</code> has to unescape URLs before mapping them,
|
||||
so backreferences are unescaped at the time they are applied.
|
||||
@@ -120,6 +116,20 @@ when the backend may break if presented with an unescaped URL.</p>
|
||||
|
||||
<p>An alternative to this flag is using a <code class="directive"><a href="../mod/mod_rewrite.html#rewritecond">RewriteCond</a></code> to capture against %{THE_REQUEST} which will capture
|
||||
strings in the encoded form.</p>
|
||||
+
|
||||
+<p>In 2.4.26 and later, you can limit the escaping to specific characters
|
||||
+in backreferences by listing them: <code>[B=#?;]</code>. Note: The space
|
||||
+character can be used in the list of characters to escape, but you must quote
|
||||
+the entire third argument of <code class="directive"><a href="../mod/mod_rewrite.html#rewriterule">RewriteRule</a></code>
|
||||
+and the space must not be the last character in the list.</p>
|
||||
+
|
||||
+<pre class="prettyprint lang-config"># Escape spaces and question marks. The quotes around the final argument
|
||||
+# are required when a space is included.
|
||||
+RewriteRule "^search/(.*)$" "/search.php?term=$1" "[B= ?]"</pre>
|
||||
+
|
||||
+<p>To limit the characters escaped this way, see <a href="#flag_bne">#flag_bne</a>
|
||||
+and <a href="#flag_bctls">#flag_bctls</a></p>
|
||||
+
|
||||
</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
|
||||
<div class="section">
|
||||
<h2><a name="flag_bnp" id="flag_bnp">BNP|backrefnoplus (don't escape space to +)</a></h2>
|
||||
diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c
|
||||
index 38dbb24..b71c67c 100644
|
||||
--- a/modules/mappers/mod_rewrite.c
|
||||
+++ b/modules/mappers/mod_rewrite.c
|
||||
@@ -101,6 +101,8 @@
|
||||
#include "mod_rewrite.h"
|
||||
#include "ap_expr.h"
|
||||
|
||||
+#include "test_char.h"
|
||||
+
|
||||
static ap_dbd_t *(*dbd_acquire)(request_rec*) = NULL;
|
||||
static void (*dbd_prepare)(server_rec*, const char*, const char*) = NULL;
|
||||
static const char* really_last_key = "rewrite_really_last";
|
||||
@@ -168,6 +170,8 @@ static const char* really_last_key = "rewrite_really_last";
|
||||
#define RULEFLAG_END (1<<17)
|
||||
#define RULEFLAG_ESCAPENOPLUS (1<<18)
|
||||
#define RULEFLAG_QSLAST (1<<19)
|
||||
+#define RULEFLAG_QSNONE (1<<20) /* programattic only */
|
||||
+#define RULEFLAG_ESCAPECTLS (1<<21)
|
||||
|
||||
/* return code of the rewrite rule
|
||||
* the result may be escaped - or not
|
||||
@@ -321,7 +325,8 @@ typedef struct {
|
||||
data_item *cookie; /* added cookies */
|
||||
int skip; /* number of next rules to skip */
|
||||
int maxrounds; /* limit on number of loops with N flag */
|
||||
- char *escapes; /* specific backref escapes */
|
||||
+ const char *escapes; /* specific backref escapes */
|
||||
+ const char *noescapes; /* specific backref chars not to escape */
|
||||
} rewriterule_entry;
|
||||
|
||||
typedef struct {
|
||||
@@ -422,7 +427,9 @@ static const char *rewritemap_mutex_type = "rewrite-map";
|
||||
/* Optional functions imported from mod_ssl when loaded: */
|
||||
static APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *rewrite_ssl_lookup = NULL;
|
||||
static APR_OPTIONAL_FN_TYPE(ssl_is_https) *rewrite_is_https = NULL;
|
||||
-static char *escape_backref(apr_pool_t *p, const char *path, const char *escapeme, int noplus);
|
||||
+static char *escape_backref(apr_pool_t *p, const char *path,
|
||||
+ const char *escapeme, const char *noescapeme,
|
||||
+ int flags);
|
||||
|
||||
/*
|
||||
* +-------------------------------------------------------+
|
||||
@@ -645,18 +652,26 @@ static APR_INLINE unsigned char *c2x(unsigned what, unsigned char prefix,
|
||||
return where;
|
||||
}
|
||||
|
||||
+
|
||||
/*
|
||||
* Escapes a backreference in a similar way as php's urlencode does.
|
||||
* Based on ap_os_escape_path in server/util.c
|
||||
*/
|
||||
-static char *escape_backref(apr_pool_t *p, const char *path, const char *escapeme, int noplus) {
|
||||
- char *copy = apr_palloc(p, 3 * strlen(path) + 3);
|
||||
+static char *escape_backref(apr_pool_t *p, const char *path,
|
||||
+ const char *escapeme, const char *noescapeme,
|
||||
+ int flags)
|
||||
+{
|
||||
+ char *copy = apr_palloc(p, 3 * strlen(path) + 1);
|
||||
const unsigned char *s = (const unsigned char *)path;
|
||||
unsigned char *d = (unsigned char *)copy;
|
||||
- unsigned c;
|
||||
+ int noplus = (flags & RULEFLAG_ESCAPENOPLUS) != 0;
|
||||
+ int ctls = (flags & RULEFLAG_ESCAPECTLS) != 0;
|
||||
+ unsigned char c;
|
||||
|
||||
while ((c = *s)) {
|
||||
- if (!escapeme) {
|
||||
+ if (((ctls ? !TEST_CHAR(c, T_VCHAR_OBSTEXT) : !escapeme)
|
||||
+ || (escapeme && ap_strchr_c(escapeme, c)))
|
||||
+ && (!noescapeme || !ap_strchr_c(noescapeme, c))) {
|
||||
if (apr_isalnum(c) || c == '_') {
|
||||
*d++ = c;
|
||||
}
|
||||
@@ -667,23 +682,8 @@ static char *escape_backref(apr_pool_t *p, const char *path, const char *escapem
|
||||
d = c2x(c, '%', d);
|
||||
}
|
||||
}
|
||||
- else {
|
||||
- const char *esc = escapeme;
|
||||
- while (*esc) {
|
||||
- if (c == *esc) {
|
||||
- if (c == ' ' && !noplus) {
|
||||
- *d++ = '+';
|
||||
- }
|
||||
- else {
|
||||
- d = c2x(c, '%', d);
|
||||
- }
|
||||
- break;
|
||||
- }
|
||||
- ++esc;
|
||||
- }
|
||||
- if (!*esc) {
|
||||
- *d++ = c;
|
||||
- }
|
||||
+ else {
|
||||
+ *d++ = c;
|
||||
}
|
||||
++s;
|
||||
}
|
||||
@@ -761,15 +761,24 @@ static char *escape_absolute_uri(apr_pool_t *p, char *uri, unsigned scheme)
|
||||
ap_escape_uri(p, cp), NULL);
|
||||
}
|
||||
|
||||
+
|
||||
/*
|
||||
* split out a QUERY_STRING part from
|
||||
* the current URI string
|
||||
*/
|
||||
-static void splitout_queryargs(request_rec *r, int qsappend, int qsdiscard,
|
||||
- int qslast)
|
||||
+static void splitout_queryargs(request_rec *r, int flags)
|
||||
{
|
||||
char *q;
|
||||
int split;
|
||||
+ int qsappend = flags & RULEFLAG_QSAPPEND;
|
||||
+ int qsdiscard = flags & RULEFLAG_QSDISCARD;
|
||||
+ int qslast = flags & RULEFLAG_QSLAST;
|
||||
+
|
||||
+ if (flags & RULEFLAG_QSNONE) {
|
||||
+ rewritelog((r, 2, NULL, "discarding query string, no parse from substitution"));
|
||||
+ r->args = NULL;
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
/* don't touch, unless it's a scheme for which a query string makes sense.
|
||||
* See RFC 1738 and RFC 2368.
|
||||
@@ -794,7 +803,7 @@ static void splitout_queryargs(request_rec *r, int qsappend, int qsdiscard,
|
||||
olduri = apr_pstrdup(r->pool, r->filename);
|
||||
*q++ = '\0';
|
||||
if (qsappend) {
|
||||
- if (*q) {
|
||||
+ if (*q) {
|
||||
r->args = apr_pstrcat(r->pool, q, "&" , r->args, NULL);
|
||||
}
|
||||
}
|
||||
@@ -802,9 +811,9 @@ static void splitout_queryargs(request_rec *r, int qsappend, int qsdiscard,
|
||||
r->args = apr_pstrdup(r->pool, q);
|
||||
}
|
||||
|
||||
- if (r->args) {
|
||||
+ if (r->args) {
|
||||
len = strlen(r->args);
|
||||
-
|
||||
+
|
||||
if (!len) {
|
||||
r->args = NULL;
|
||||
}
|
||||
@@ -2436,7 +2445,8 @@ static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry)
|
||||
/* escape the backreference */
|
||||
char *tmp2, *tmp;
|
||||
tmp = apr_pstrmemdup(pool, bri->source + bri->regmatch[n].rm_so, span);
|
||||
- tmp2 = escape_backref(pool, tmp, entry->escapes, entry->flags & RULEFLAG_ESCAPENOPLUS);
|
||||
+ tmp2 = escape_backref(pool, tmp, entry->escapes, entry->noescapes,
|
||||
+ entry->flags);
|
||||
rewritelog((ctx->r, 5, ctx->perdir, "escaping backreference '%s' to '%s'",
|
||||
tmp, tmp2));
|
||||
|
||||
@@ -2733,7 +2743,7 @@ static apr_status_t rewritelock_remove(void *data)
|
||||
* XXX: what an inclined parser. Seems we have to leave it so
|
||||
* for backwards compat. *sigh*
|
||||
*/
|
||||
-static int parseargline(char *str, char **a1, char **a2, char **a3)
|
||||
+static int parseargline(char *str, char **a1, char **a2, char **a2_end, char **a3)
|
||||
{
|
||||
char quote;
|
||||
|
||||
@@ -2784,8 +2794,10 @@ static int parseargline(char *str, char **a1, char **a2, char **a3)
|
||||
|
||||
if (!*str) {
|
||||
*a3 = NULL; /* 3rd argument is optional */
|
||||
+ *a2_end = str;
|
||||
return 0;
|
||||
}
|
||||
+ *a2_end = str;
|
||||
*str++ = '\0';
|
||||
|
||||
while (apr_isspace(*str)) {
|
||||
@@ -3323,7 +3335,7 @@ static const char *cmd_rewritecond(cmd_parms *cmd, void *in_dconf,
|
||||
rewrite_server_conf *sconf;
|
||||
rewritecond_entry *newcond;
|
||||
ap_regex_t *regexp;
|
||||
- char *a1 = NULL, *a2 = NULL, *a3 = NULL;
|
||||
+ char *a1 = NULL, *a2 = NULL, *a2_end, *a3 = NULL;
|
||||
const char *err;
|
||||
|
||||
sconf = ap_get_module_config(cmd->server->module_config, &rewrite_module);
|
||||
@@ -3341,7 +3353,7 @@ static const char *cmd_rewritecond(cmd_parms *cmd, void *in_dconf,
|
||||
* of the argument line. So we can use a1 .. a3 without
|
||||
* copying them again.
|
||||
*/
|
||||
- if (parseargline(str, &a1, &a2, &a3)) {
|
||||
+ if (parseargline(str, &a1, &a2, &a2_end, &a3)) {
|
||||
return apr_pstrcat(cmd->pool, "RewriteCond: bad argument line '", str,
|
||||
"'", NULL);
|
||||
}
|
||||
@@ -3500,13 +3512,24 @@ static const char *cmd_rewriterule_setflag(apr_pool_t *p, void *_cfg,
|
||||
case 'B':
|
||||
if (!*key || !strcasecmp(key, "ackrefescaping")) {
|
||||
cfg->flags |= RULEFLAG_ESCAPEBACKREF;
|
||||
- if (val && *val) {
|
||||
+ if (val && *val) {
|
||||
cfg->escapes = val;
|
||||
}
|
||||
}
|
||||
+ else if (!strcasecmp(key, "NE")) {
|
||||
+ if (val && *val) {
|
||||
+ cfg->noescapes = val;
|
||||
+ }
|
||||
+ else {
|
||||
+ return "flag 'BNE' wants a list of characters (i.e. [BNE=...])";
|
||||
+ }
|
||||
+ }
|
||||
else if (!strcasecmp(key, "NP") || !strcasecmp(key, "ackrefernoplus")) {
|
||||
cfg->flags |= RULEFLAG_ESCAPENOPLUS;
|
||||
}
|
||||
+ else if (!strcasecmp(key, "CTLS")) {
|
||||
+ cfg->flags |= RULEFLAG_ESCAPECTLS|RULEFLAG_ESCAPEBACKREF;
|
||||
+ }
|
||||
else {
|
||||
++error;
|
||||
}
|
||||
@@ -3749,7 +3772,7 @@ static const char *cmd_rewriterule(cmd_parms *cmd, void *in_dconf,
|
||||
rewrite_server_conf *sconf;
|
||||
rewriterule_entry *newrule;
|
||||
ap_regex_t *regexp;
|
||||
- char *a1 = NULL, *a2 = NULL, *a3 = NULL;
|
||||
+ char *a1 = NULL, *a2 = NULL, *a2_end, *a3 = NULL;
|
||||
const char *err;
|
||||
|
||||
sconf = ap_get_module_config(cmd->server->module_config, &rewrite_module);
|
||||
@@ -3763,12 +3786,11 @@ static const char *cmd_rewriterule(cmd_parms *cmd, void *in_dconf,
|
||||
}
|
||||
|
||||
/* parse the argument line ourself */
|
||||
- if (parseargline(str, &a1, &a2, &a3)) {
|
||||
+ if (parseargline(str, &a1, &a2, &a2_end, &a3)) {
|
||||
return apr_pstrcat(cmd->pool, "RewriteRule: bad argument line '", str,
|
||||
"'", NULL);
|
||||
}
|
||||
|
||||
- /* arg3: optional flags field */
|
||||
newrule->forced_mimetype = NULL;
|
||||
newrule->forced_handler = NULL;
|
||||
newrule->forced_responsecode = HTTP_MOVED_TEMPORARILY;
|
||||
@@ -3777,6 +3799,9 @@ static const char *cmd_rewriterule(cmd_parms *cmd, void *in_dconf,
|
||||
newrule->cookie = NULL;
|
||||
newrule->skip = 0;
|
||||
newrule->maxrounds = REWRITE_MAX_ROUNDS;
|
||||
+ newrule->escapes = newrule->noescapes = NULL;
|
||||
+
|
||||
+ /* arg3: optional flags field */
|
||||
if (a3 != NULL) {
|
||||
if ((err = cmd_parseflagfield(cmd->pool, newrule, a3,
|
||||
cmd_rewriterule_setflag)) != NULL) {
|
||||
@@ -3810,6 +3835,17 @@ static const char *cmd_rewriterule(cmd_parms *cmd, void *in_dconf,
|
||||
newrule->flags |= RULEFLAG_NOSUB;
|
||||
}
|
||||
|
||||
+ if (*(a2_end-1) == '?') {
|
||||
+ /* a literal ? at the end of the unsubstituted rewrite rule */
|
||||
+ newrule->flags |= RULEFLAG_QSNONE;
|
||||
+ *(a2_end-1) = '\0'; /* trailing ? has done its job */
|
||||
+ }
|
||||
+ else if (newrule->flags & RULEFLAG_QSDISCARD) {
|
||||
+ if (NULL == ap_strchr(newrule->output, '?')) {
|
||||
+ newrule->flags |= RULEFLAG_QSNONE;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
/* now, if the server or per-dir config holds an
|
||||
* array of RewriteCond entries, we take it for us
|
||||
* and clear the array
|
||||
@@ -4215,9 +4251,7 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx)
|
||||
r->path_info = NULL;
|
||||
}
|
||||
|
||||
- splitout_queryargs(r, p->flags & RULEFLAG_QSAPPEND,
|
||||
- p->flags & RULEFLAG_QSDISCARD,
|
||||
- p->flags & RULEFLAG_QSLAST);
|
||||
+ splitout_queryargs(r, p->flags);
|
||||
|
||||
/* Add the previously stripped per-directory location prefix, unless
|
||||
* (1) it's an absolute URL path and
|
||||
@@ -4696,8 +4730,25 @@ static int hook_uri2file(request_rec *r)
|
||||
}
|
||||
|
||||
if (rulestatus) {
|
||||
- unsigned skip;
|
||||
- apr_size_t flen;
|
||||
+ unsigned skip_absolute = is_absolute_uri(r->filename, NULL);
|
||||
+ apr_size_t flen = r->filename ? strlen(r->filename) : 0;
|
||||
+ int to_proxyreq = (flen > 6 && strncmp(r->filename, "proxy:", 6) == 0);
|
||||
+ int will_escape = skip_absolute && (rulestatus != ACTION_NOESCAPE);
|
||||
+
|
||||
+ if (r->args
|
||||
+ && !will_escape
|
||||
+ && *(ap_scan_vchar_obstext(r->args))) {
|
||||
+ /*
|
||||
+ * We have a raw control character or a ' ' in r->args.
|
||||
+ * Correct encoding was missed.
|
||||
+ * Correct encoding was missed and we're not going to escape
|
||||
+ * it before returning.
|
||||
+ */
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10410)
|
||||
+ "Rewritten query string contains control "
|
||||
+ "characters or spaces");
|
||||
+ return HTTP_FORBIDDEN;
|
||||
+ }
|
||||
|
||||
if (ACTION_STATUS == rulestatus) {
|
||||
int n = r->status;
|
||||
@@ -4706,8 +4757,7 @@ static int hook_uri2file(request_rec *r)
|
||||
return n;
|
||||
}
|
||||
|
||||
- flen = r->filename ? strlen(r->filename) : 0;
|
||||
- if (flen > 6 && strncmp(r->filename, "proxy:", 6) == 0) {
|
||||
+ if (to_proxyreq) {
|
||||
/* it should be go on as an internal proxy request */
|
||||
|
||||
/* check if the proxy module is enabled, so
|
||||
@@ -4749,7 +4799,7 @@ static int hook_uri2file(request_rec *r)
|
||||
r->filename));
|
||||
return OK;
|
||||
}
|
||||
- else if ((skip = is_absolute_uri(r->filename, NULL)) > 0) {
|
||||
+ else if (skip_absolute > 0) {
|
||||
int n;
|
||||
|
||||
/* it was finally rewritten to a remote URL */
|
||||
@@ -4757,7 +4807,7 @@ static int hook_uri2file(request_rec *r)
|
||||
if (rulestatus != ACTION_NOESCAPE) {
|
||||
rewritelog((r, 1, NULL, "escaping %s for redirect",
|
||||
r->filename));
|
||||
- r->filename = escape_absolute_uri(r->pool, r->filename, skip);
|
||||
+ r->filename = escape_absolute_uri(r->pool, r->filename, skip_absolute);
|
||||
}
|
||||
|
||||
/* append the QUERY_STRING part */
|
||||
@@ -4981,7 +5031,26 @@ static int hook_fixup(request_rec *r)
|
||||
*/
|
||||
rulestatus = apply_rewrite_list(r, dconf->rewriterules, dconf->directory);
|
||||
if (rulestatus) {
|
||||
- unsigned skip;
|
||||
+ unsigned skip_absolute = is_absolute_uri(r->filename, NULL);
|
||||
+ int to_proxyreq = 0;
|
||||
+ int will_escape = 0;
|
||||
+
|
||||
+ l = strlen(r->filename);
|
||||
+ to_proxyreq = l > 6 && strncmp(r->filename, "proxy:", 6) == 0;
|
||||
+ will_escape = skip_absolute && (rulestatus != ACTION_NOESCAPE);
|
||||
+
|
||||
+ if (r->args
|
||||
+ && !will_escape
|
||||
+ && *(ap_scan_vchar_obstext(r->args))) {
|
||||
+ /*
|
||||
+ * We have a raw control character or a ' ' in r->args.
|
||||
+ * Correct encoding was missed.
|
||||
+ */
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10411)
|
||||
+ "Rewritten query string contains control "
|
||||
+ "characters or spaces");
|
||||
+ return HTTP_FORBIDDEN;
|
||||
+ }
|
||||
|
||||
if (ACTION_STATUS == rulestatus) {
|
||||
int n = r->status;
|
||||
@@ -4990,8 +5059,7 @@ static int hook_fixup(request_rec *r)
|
||||
return n;
|
||||
}
|
||||
|
||||
- l = strlen(r->filename);
|
||||
- if (l > 6 && strncmp(r->filename, "proxy:", 6) == 0) {
|
||||
+ if (to_proxyreq) {
|
||||
/* it should go on as an internal proxy request */
|
||||
|
||||
/* make sure the QUERY_STRING and
|
||||
@@ -5015,7 +5083,7 @@ static int hook_fixup(request_rec *r)
|
||||
"%s [OK]", r->filename));
|
||||
return OK;
|
||||
}
|
||||
- else if ((skip = is_absolute_uri(r->filename, NULL)) > 0) {
|
||||
+ else if (skip_absolute > 0) {
|
||||
/* it was finally rewritten to a remote URL */
|
||||
|
||||
/* because we are in a per-dir context
|
||||
@@ -5024,7 +5092,7 @@ static int hook_fixup(request_rec *r)
|
||||
*/
|
||||
if (dconf->baseurl != NULL) {
|
||||
/* skip 'scheme://' */
|
||||
- cp = r->filename + skip;
|
||||
+ cp = r->filename + skip_absolute;
|
||||
|
||||
if ((cp = ap_strchr(cp, '/')) != NULL && *(++cp)) {
|
||||
rewritelog((r, 2, dconf->directory,
|
||||
@@ -5069,7 +5137,7 @@ static int hook_fixup(request_rec *r)
|
||||
if (rulestatus != ACTION_NOESCAPE) {
|
||||
rewritelog((r, 1, dconf->directory, "escaping %s for redirect",
|
||||
r->filename));
|
||||
- r->filename = escape_absolute_uri(r->pool, r->filename, skip);
|
||||
+ r->filename = escape_absolute_uri(r->pool, r->filename, skip_absolute);
|
||||
}
|
||||
|
||||
/* append the QUERY_STRING part */
|
||||
diff --git a/modules/proxy/mod_proxy_ajp.c b/modules/proxy/mod_proxy_ajp.c
|
||||
index cbb0872..873ccf1 100644
|
||||
--- a/modules/proxy/mod_proxy_ajp.c
|
||||
+++ b/modules/proxy/mod_proxy_ajp.c
|
||||
@@ -69,6 +69,16 @@ static int proxy_ajp_canon(request_rec *r, char *url)
|
||||
path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0,
|
||||
r->proxyreq);
|
||||
search = r->args;
|
||||
+ if (search && *(ap_scan_vchar_obstext(search))) {
|
||||
+ /*
|
||||
+ * We have a raw control character or a ' ' in r->args.
|
||||
+ * Correct encoding was missed.
|
||||
+ */
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10406)
|
||||
+ "To be forwarded query string contains control "
|
||||
+ "characters or spaces");
|
||||
+ return HTTP_FORBIDDEN;
|
||||
+ }
|
||||
}
|
||||
if (path == NULL)
|
||||
return HTTP_BAD_REQUEST;
|
||||
diff --git a/modules/proxy/mod_proxy_balancer.c b/modules/proxy/mod_proxy_balancer.c
|
||||
index 3a28038..c599e1a 100644
|
||||
--- a/modules/proxy/mod_proxy_balancer.c
|
||||
+++ b/modules/proxy/mod_proxy_balancer.c
|
||||
@@ -106,6 +106,16 @@ static int proxy_balancer_canon(request_rec *r, char *url)
|
||||
path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0,
|
||||
r->proxyreq);
|
||||
search = r->args;
|
||||
+ if (search && *(ap_scan_vchar_obstext(search))) {
|
||||
+ /*
|
||||
+ * We have a raw control character or a ' ' in r->args.
|
||||
+ * Correct encoding was missed.
|
||||
+ */
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10407)
|
||||
+ "To be forwarded query string contains control "
|
||||
+ "characters or spaces");
|
||||
+ return HTTP_FORBIDDEN;
|
||||
+ }
|
||||
}
|
||||
if (path == NULL)
|
||||
return HTTP_BAD_REQUEST;
|
||||
diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c
|
||||
index 7573638..fe7b322 100644
|
||||
--- a/modules/proxy/mod_proxy_http.c
|
||||
+++ b/modules/proxy/mod_proxy_http.c
|
||||
@@ -90,6 +90,16 @@ static int proxy_http_canon(request_rec *r, char *url)
|
||||
path = ap_proxy_canonenc(r->pool, url, strlen(url),
|
||||
enc_path, 0, r->proxyreq);
|
||||
search = r->args;
|
||||
+ if (search && *(ap_scan_vchar_obstext(search))) {
|
||||
+ /*
|
||||
+ * We have a raw control character or a ' ' in r->args.
|
||||
+ * Correct encoding was missed.
|
||||
+ */
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10408)
|
||||
+ "To be forwarded query string contains control "
|
||||
+ "characters or spaces");
|
||||
+ return HTTP_FORBIDDEN;
|
||||
+ }
|
||||
}
|
||||
break;
|
||||
case PROXYREQ_PROXY:
|
||||
diff --git a/modules/proxy/mod_proxy_wstunnel.c b/modules/proxy/mod_proxy_wstunnel.c
|
||||
index e005a94..f5e27d9 100644
|
||||
--- a/modules/proxy/mod_proxy_wstunnel.c
|
||||
+++ b/modules/proxy/mod_proxy_wstunnel.c
|
||||
@@ -77,6 +77,16 @@ static int proxy_wstunnel_canon(request_rec *r, char *url)
|
||||
path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0,
|
||||
r->proxyreq);
|
||||
search = r->args;
|
||||
+ if (search && *(ap_scan_vchar_obstext(search))) {
|
||||
+ /*
|
||||
+ * We have a raw control character or a ' ' in r->args.
|
||||
+ * Correct encoding was missed.
|
||||
+ */
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10409)
|
||||
+ "To be forwarded query string contains control "
|
||||
+ "characters or spaces");
|
||||
+ return HTTP_FORBIDDEN;
|
||||
+ }
|
||||
}
|
||||
if (path == NULL)
|
||||
return HTTP_BAD_REQUEST;
|
||||
diff --git a/server/gen_test_char.c b/server/gen_test_char.c
|
||||
index 48ae6f4..6a153a3 100644
|
||||
--- a/server/gen_test_char.c
|
||||
+++ b/server/gen_test_char.c
|
||||
@@ -169,5 +169,15 @@ int main(int argc, char *argv[])
|
||||
|
||||
printf("\n};\n");
|
||||
|
||||
+
|
||||
+ printf(
|
||||
+ "/* we assume the folks using this ensure 0 <= c < 256... which means\n"
|
||||
+ " * you need a cast to (unsigned char) first, you can't just plug a\n"
|
||||
+ " * char in here and get it to work, because if char is signed then it\n"
|
||||
+ " * will first be sign extended.\n"
|
||||
+ " */\n"
|
||||
+ "#define TEST_CHAR(c, f) (test_char_table[(unsigned char)(c)] & (f))\n"
|
||||
+ );
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
diff --git a/server/util.c b/server/util.c
|
||||
index 45051b7..9d897d4 100644
|
||||
--- a/server/util.c
|
||||
+++ b/server/util.c
|
||||
@@ -74,13 +74,6 @@
|
||||
*/
|
||||
#include "test_char.h"
|
||||
|
||||
-/* we assume the folks using this ensure 0 <= c < 256... which means
|
||||
- * you need a cast to (unsigned char) first, you can't just plug a
|
||||
- * char in here and get it to work, because if char is signed then it
|
||||
- * will first be sign extended.
|
||||
- */
|
||||
-#define TEST_CHAR(c, f) (test_char_table[(unsigned char)(c)] & (f))
|
||||
-
|
||||
/* Win32/NetWare/OS2 need to check for both forward and back slashes
|
||||
* in ap_getparents() and ap_escape_url.
|
||||
*/
|
@ -1,3 +1,19 @@
|
||||
From 45e46db92b5387fdaf6c57e65ac9716c9b8574da Mon Sep 17 00:00:00 2001
|
||||
From: Pavel Mayorov <pmayorov@cloudlinux.com>
|
||||
Date: Wed, 15 Mar 2023 14:00:11 +0300
|
||||
Subject: [PATCH] CVE-2023-27522
|
||||
Taken main fix from the following upstream commit:
|
||||
commit d753ea76b5972a85349b68c31b59d04c60014f2d
|
||||
Author: Eric Covener <covener@apache.org>
|
||||
Date: Sun Mar 5 20:22:52 2023 +0000
|
||||
Merge r1907980 from trunk:
|
||||
mod_proxy_uwsgi: Stricter backend HTTP response parsing/validation
|
||||
Reviewed By: ylavic, covener, gbechis, rpluem
|
||||
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1908094 13f79535-47bb-0310-9956-ffa450edef68
|
||||
Signed-off-by: Pavel Mayorov <pmayorov@cloudlinux.com>
|
||||
---
|
||||
modules/proxy/mod_proxy_uwsgi.c | 49 +++++++++++++++++++++++----------
|
||||
1 file changed, 35 insertions(+), 14 deletions(-)
|
||||
diff --git a/modules/proxy/mod_proxy_uwsgi.c b/modules/proxy/mod_proxy_uwsgi.c
|
||||
index 9dcbed1..a1b564d 100644
|
||||
--- a/modules/proxy/mod_proxy_uwsgi.c
|
||||
@ -87,3 +103,5 @@ index 9dcbed1..a1b564d 100644
|
||||
|
||||
if ((buf = apr_table_get(r->headers_out, "Content-Type"))) {
|
||||
ap_set_content_type(r, apr_pstrdup(r->pool, buf));
|
||||
--
|
||||
2.39.2
|
@ -1,11 +0,0 @@
|
||||
--- a/modules/core/mod_macro.c 2023/10/16 06:19:16 1912992
|
||||
+++ b/modules/core/mod_macro.c 2023/10/16 06:38:32 1912993
|
||||
@@ -483,7 +483,7 @@
|
||||
for (i = 0; i < contents->nelts; i++) {
|
||||
const char *errmsg;
|
||||
/* copy the line and substitute macro parameters */
|
||||
- strncpy(line, ((char **) contents->elts)[i], MAX_STRING_LEN - 1);
|
||||
+ apr_cpystrn(line, ((char **) contents->elts)[i], MAX_STRING_LEN);
|
||||
errmsg = substitute_macro_args(line, MAX_STRING_LEN,
|
||||
macro, replacements, used);
|
||||
if (errmsg) {
|
@ -1,74 +0,0 @@
|
||||
diff --git a/modules/http/http_filters.c b/modules/http/http_filters.c
|
||||
index 393343a..16cb23c 100644
|
||||
--- a/modules/http/http_filters.c
|
||||
+++ b/modules/http/http_filters.c
|
||||
@@ -1348,6 +1348,9 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f,
|
||||
*/
|
||||
apr_table_clear(r->headers_out);
|
||||
apr_table_clear(r->err_headers_out);
|
||||
+ r->content_type = r->content_encoding = NULL;
|
||||
+ r->content_languages = NULL;
|
||||
+ r->clength = r->chunked = 0;
|
||||
apr_brigade_cleanup(b);
|
||||
|
||||
/* Don't recall ap_die() if we come back here (from its own internal
|
||||
@@ -1364,8 +1367,6 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f,
|
||||
APR_BRIGADE_INSERT_TAIL(b, e);
|
||||
e = apr_bucket_eos_create(c->bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(b, e);
|
||||
- r->content_type = r->content_encoding = NULL;
|
||||
- r->content_languages = NULL;
|
||||
ap_set_content_length(r, 0);
|
||||
recursive_error = 1;
|
||||
}
|
||||
@@ -1392,6 +1393,7 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f,
|
||||
if (!apr_is_empty_table(r->err_headers_out)) {
|
||||
r->headers_out = apr_table_overlay(r->pool, r->err_headers_out,
|
||||
r->headers_out);
|
||||
+ apr_table_clear(r->err_headers_out);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1411,6 +1413,17 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f,
|
||||
fixup_vary(r);
|
||||
}
|
||||
|
||||
+
|
||||
+ /*
|
||||
+ * Control cachability for non-cacheable responses if not already set by
|
||||
+ * some other part of the server configuration.
|
||||
+ */
|
||||
+ if (r->no_cache && !apr_table_get(r->headers_out, "Expires")) {
|
||||
+ char *date = apr_palloc(r->pool, APR_RFC822_DATE_LEN);
|
||||
+ ap_recent_rfc822_date(date, r->request_time);
|
||||
+ apr_table_addn(r->headers_out, "Expires", date);
|
||||
+ }
|
||||
+
|
||||
/*
|
||||
* Now remove any ETag response header field if earlier processing
|
||||
* says so (such as a 'FileETag None' directive).
|
||||
@@ -1423,6 +1436,7 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f,
|
||||
basic_http_header_check(r, &protocol);
|
||||
ap_set_keepalive(r);
|
||||
|
||||
+ /* 204/304 responses don't have content related headers */
|
||||
if (AP_STATUS_IS_HEADER_ONLY(r->status)) {
|
||||
apr_table_unset(r->headers_out, "Transfer-Encoding");
|
||||
apr_table_unset(r->headers_out, "Content-Length");
|
||||
@@ -1465,16 +1479,6 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f,
|
||||
apr_table_setn(r->headers_out, "Content-Language", field);
|
||||
}
|
||||
|
||||
- /*
|
||||
- * Control cachability for non-cacheable responses if not already set by
|
||||
- * some other part of the server configuration.
|
||||
- */
|
||||
- if (r->no_cache && !apr_table_get(r->headers_out, "Expires")) {
|
||||
- char *date = apr_palloc(r->pool, APR_RFC822_DATE_LEN);
|
||||
- ap_recent_rfc822_date(date, r->request_time);
|
||||
- apr_table_addn(r->headers_out, "Expires", date);
|
||||
- }
|
||||
-
|
||||
/* This is a hack, but I can't find anyway around it. The idea is that
|
||||
* we don't want to send out 0 Content-Lengths if it is a head request.
|
||||
* This happens when modules try to outsmart the server, and return
|
@ -1,172 +0,0 @@
|
||||
diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c
|
||||
index a6df1b8..94ec87e 100644
|
||||
--- a/modules/proxy/mod_proxy.c
|
||||
+++ b/modules/proxy/mod_proxy.c
|
||||
@@ -968,6 +968,7 @@ static int proxy_fixup(request_rec *r)
|
||||
|
||||
return OK; /* otherwise; we've done the best we can */
|
||||
}
|
||||
+
|
||||
/* Send a redirection if the request contains a hostname which is not */
|
||||
/* fully qualified, i.e. doesn't have a domain name appended. Some proxy */
|
||||
/* servers like Netscape's allow this and access hosts from the local */
|
||||
@@ -1021,7 +1022,7 @@ static int proxy_handler(request_rec *r)
|
||||
ap_get_module_config(sconf, &proxy_module);
|
||||
apr_array_header_t *proxies = conf->proxies;
|
||||
struct proxy_remote *ents = (struct proxy_remote *) proxies->elts;
|
||||
- int i, rc, access_status;
|
||||
+ int rc = DECLINED, access_status, i;
|
||||
int direct_connect = 0;
|
||||
const char *str;
|
||||
apr_int64_t maxfwd;
|
||||
@@ -1036,19 +1037,28 @@ static int proxy_handler(request_rec *r)
|
||||
return DECLINED;
|
||||
}
|
||||
|
||||
- if (!r->proxyreq) {
|
||||
- /* We may have forced the proxy handler via config or .htaccess */
|
||||
- if (r->handler &&
|
||||
- strncmp(r->handler, "proxy:", 6) == 0 &&
|
||||
- strncmp(r->filename, "proxy:", 6) != 0) {
|
||||
- r->proxyreq = PROXYREQ_REVERSE;
|
||||
- r->filename = apr_pstrcat(r->pool, r->handler, r->filename, NULL);
|
||||
+ /* We may have forced the proxy handler via config or .htaccess */
|
||||
+ if (!r->proxyreq && r->handler && strncmp(r->handler, "proxy:", 6) == 0) {
|
||||
+ char *old_filename = r->filename;
|
||||
+
|
||||
+ r->proxyreq = PROXYREQ_REVERSE;
|
||||
+ r->filename = apr_pstrcat(r->pool, r->handler, r->filename, NULL);
|
||||
+
|
||||
+ /* Still need to fixup/canonicalize r->filename */
|
||||
+ rc = ap_proxy_fixup_uds_filename(r);
|
||||
+ if (rc <= OK) {
|
||||
+ rc = proxy_fixup(r);
|
||||
}
|
||||
- else {
|
||||
- return DECLINED;
|
||||
+ if (rc != OK) {
|
||||
+ r->filename = old_filename;
|
||||
+ r->proxyreq = 0;
|
||||
}
|
||||
- } else if (strncmp(r->filename, "proxy:", 6) != 0) {
|
||||
- return DECLINED;
|
||||
+ }
|
||||
+ else if (r->proxyreq && strncmp(r->filename, "proxy:", 6) == 0) {
|
||||
+ rc = OK;
|
||||
+ }
|
||||
+ if (rc != OK) {
|
||||
+ return rc;
|
||||
}
|
||||
|
||||
/* handle max-forwards / OPTIONS / TRACE */
|
||||
diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h
|
||||
index e5c0a26..354f395 100644
|
||||
--- a/modules/proxy/mod_proxy.h
|
||||
+++ b/modules/proxy/mod_proxy.h
|
||||
@@ -921,6 +921,14 @@ PROXY_DECLARE(proxy_balancer_shared *) ap_proxy_find_balancershm(ap_slotmem_prov
|
||||
proxy_balancer *balancer,
|
||||
unsigned int *index);
|
||||
|
||||
+/*
|
||||
+ * Strip the UDS part of r->filename if any, and put the UDS path in
|
||||
+ * r->notes ("uds_path")
|
||||
+ * @param r current request
|
||||
+ * @return OK if fixed up, DECLINED if not UDS, or an HTTP_XXX error
|
||||
+ */
|
||||
+PROXY_DECLARE(int) ap_proxy_fixup_uds_filename(request_rec *r);
|
||||
+
|
||||
/**
|
||||
* Get the most suitable worker and/or balancer for the request
|
||||
* @param worker worker used for processing request
|
||||
diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c
|
||||
index 6626ea0..6244e74 100644
|
||||
--- a/modules/proxy/proxy_util.c
|
||||
+++ b/modules/proxy/proxy_util.c
|
||||
@@ -2098,7 +2098,7 @@ static int ap_proxy_retry_worker(const char *proxy_function, proxy_worker *worke
|
||||
* were passed a UDS url (eg: from mod_proxy) and adjust uds_path
|
||||
* as required.
|
||||
*/
|
||||
-static int fix_uds_filename(request_rec *r, char **url)
|
||||
+PROXY_DECLARE(int) ap_proxy_fixup_uds_filename(request_rec *r)
|
||||
{
|
||||
char *uds_url = r->filename + 6, *origin_url;
|
||||
|
||||
@@ -2106,7 +2106,6 @@ static int fix_uds_filename(request_rec *r, char **url)
|
||||
!ap_cstr_casecmpn(uds_url, "unix:", 5) &&
|
||||
(origin_url = ap_strchr(uds_url + 5, '|'))) {
|
||||
char *uds_path = NULL;
|
||||
- apr_size_t url_len;
|
||||
apr_uri_t urisock;
|
||||
apr_status_t rv;
|
||||
|
||||
@@ -2122,21 +2121,20 @@ static int fix_uds_filename(request_rec *r, char **url)
|
||||
if (!uds_path) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10292)
|
||||
"Invalid proxy UDS filename (%s)", r->filename);
|
||||
- return 0;
|
||||
+ return HTTP_BAD_REQUEST;
|
||||
}
|
||||
apr_table_setn(r->notes, "uds_path", uds_path);
|
||||
|
||||
- /* Remove the UDS path from *url and r->filename */
|
||||
- url_len = strlen(origin_url);
|
||||
- *url = apr_pstrmemdup(r->pool, origin_url, url_len);
|
||||
- memcpy(uds_url, *url, url_len + 1);
|
||||
-
|
||||
ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
|
||||
- "*: rewrite of url due to UDS(%s): %s (%s)",
|
||||
- uds_path, *url, r->filename);
|
||||
+ "*: fixup UDS from %s: %s (%s)",
|
||||
+ r->filename, origin_url, uds_path);
|
||||
+
|
||||
+ /* Overwrite the UDS part in place */
|
||||
+ memmove(uds_url, origin_url, strlen(origin_url) + 1);
|
||||
+ return OK;
|
||||
}
|
||||
|
||||
- return 1;
|
||||
+ return DECLINED;
|
||||
}
|
||||
|
||||
PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker,
|
||||
@@ -2155,9 +2153,6 @@ PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker,
|
||||
ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
|
||||
"%s: found worker %s for %s",
|
||||
(*worker)->s->scheme, (*worker)->s->name, *url);
|
||||
- if (!forward && !fix_uds_filename(r, url)) {
|
||||
- return HTTP_INTERNAL_SERVER_ERROR;
|
||||
- }
|
||||
access_status = OK;
|
||||
}
|
||||
else if (forward) {
|
||||
@@ -2187,9 +2182,6 @@ PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker,
|
||||
* regarding the Connection header in the request.
|
||||
*/
|
||||
apr_table_setn(r->subprocess_env, "proxy-nokeepalive", "1");
|
||||
- if (!fix_uds_filename(r, url)) {
|
||||
- return HTTP_INTERNAL_SERVER_ERROR;
|
||||
- }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2199,6 +2191,20 @@ PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker,
|
||||
"all workers are busy. Unable to serve %s", *url);
|
||||
access_status = HTTP_SERVICE_UNAVAILABLE;
|
||||
}
|
||||
+
|
||||
+ if (access_status == OK && r->proxyreq == PROXYREQ_REVERSE) {
|
||||
+ int rc = ap_proxy_fixup_uds_filename(r);
|
||||
+ if (ap_is_HTTP_ERROR(rc)) {
|
||||
+ return rc;
|
||||
+ }
|
||||
+ /* If the URL has changed in r->filename, take everything after
|
||||
+ * the "proxy:" prefix.
|
||||
+ */
|
||||
+ if (rc == OK) {
|
||||
+ *url = apr_pstrdup(r->pool, r->filename + 6);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
return access_status;
|
||||
}
|
||||
|
@ -1,439 +0,0 @@
|
||||
diff --git a/docs/manual/mod/mod_rewrite.html.en b/docs/manual/mod/mod_rewrite.html.en
|
||||
index 2b8ed35..b7f1c31 100644
|
||||
--- a/docs/manual/mod/mod_rewrite.html.en
|
||||
+++ b/docs/manual/mod/mod_rewrite.html.en
|
||||
@@ -1403,6 +1403,16 @@ cannot use <code>$N</code> in the substitution string!
|
||||
<td>Force the <a class="glossarylink" href="../glossary.html#mime-type" title="see glossary">MIME-type</a> of the target file
|
||||
to be the specified type. <em><a href="../rewrite/flags.html#flag_t">details ...</a></em></td>
|
||||
</tr>
|
||||
+<tr>
|
||||
+ <td>UnsafeAllow3F</td>
|
||||
+ <td>Allows substitutions from URL's that may be unsafe.
|
||||
+ <em><a href="../rewrite/flags.html#flag_unsafe_allow_3f">details ...</a></em></td>
|
||||
+ </tr>
|
||||
+<tr>
|
||||
+ <td>UnsafePrefixStat</td>
|
||||
+ <td>Allows potentially unsafe substitutions from a leading variable or backreference to a filesystem path.
|
||||
+ <em><a href="../rewrite/flags.html#flag_unsafe_prefix_stat">details ...</a></em></td>
|
||||
+ </tr>
|
||||
</table>
|
||||
|
||||
<div class="note"><h3>Home directory expansion</h3>
|
||||
diff --git a/docs/manual/rewrite/flags.html.en b/docs/manual/rewrite/flags.html.en
|
||||
index 734809a..30d549d 100644
|
||||
--- a/docs/manual/rewrite/flags.html.en
|
||||
+++ b/docs/manual/rewrite/flags.html.en
|
||||
@@ -768,6 +768,30 @@ re-processing (including subsequent rounds of mod_rewrite processing).
|
||||
The <code>L</code> flag can be useful in this context to end the
|
||||
<em>current</em> round of mod_rewrite processing.</p>
|
||||
|
||||
+</div>
|
||||
+
|
||||
+<div class="section">
|
||||
+<h2><a name="flag_unsafe_allow_3f" id="flag_unsafe_allow_3f">UnsafeAllow3F</a></h2>
|
||||
+
|
||||
+<p>
|
||||
+Setting this flag is required to allow a rewrite to continue If the
|
||||
+HTTP request being written has an encoded question mark, '%3f', and the
|
||||
+rewritten result has a '?' in the substiution. This protects from a malicious
|
||||
+URL taking advantage of a capture and re-substitution of the encoded
|
||||
+question mark.</p>
|
||||
+
|
||||
+</div>
|
||||
+<div class="section">
|
||||
+<h2><a name="flag_unsafe_prefix_status" id="flag_unsafe_prefix_status">UnsafePrefixStat</a></h2>
|
||||
+
|
||||
+<p>
|
||||
+Setting this flag is required in server-scoped substitutions
|
||||
+start with a variable or backreference and resolve to a filesystem path.
|
||||
+These substitutions are not prefixed with the document root.
|
||||
+This protects from a malicious URL causing the expanded substitution to
|
||||
+map to an unexpected filesystem location.
|
||||
+</p>
|
||||
+
|
||||
</div></div>
|
||||
<div class="bottomlang">
|
||||
<p><span>Available Languages: </span><a href="../en/rewrite/flags.html" title="English"> en </a> |
|
||||
diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c
|
||||
index b71c67c..797f093 100644
|
||||
--- a/modules/mappers/mod_rewrite.c
|
||||
+++ b/modules/mappers/mod_rewrite.c
|
||||
@@ -172,6 +172,8 @@ static const char* really_last_key = "rewrite_really_last";
|
||||
#define RULEFLAG_QSLAST (1<<19)
|
||||
#define RULEFLAG_QSNONE (1<<20) /* programattic only */
|
||||
#define RULEFLAG_ESCAPECTLS (1<<21)
|
||||
+#define RULEFLAG_UNSAFE_PREFIX_STAT (1<<22)
|
||||
+#define RULEFLAG_UNSAFE_ALLOW3F (1<<23)
|
||||
|
||||
/* return code of the rewrite rule
|
||||
* the result may be escaped - or not
|
||||
@@ -179,7 +181,7 @@ static const char* really_last_key = "rewrite_really_last";
|
||||
#define ACTION_NORMAL (1<<0)
|
||||
#define ACTION_NOESCAPE (1<<1)
|
||||
#define ACTION_STATUS (1<<2)
|
||||
-
|
||||
+#define ACTION_STATUS_SET (1<<3)
|
||||
|
||||
#define MAPTYPE_TXT (1<<0)
|
||||
#define MAPTYPE_DBM (1<<1)
|
||||
@@ -203,6 +205,7 @@ static const char* really_last_key = "rewrite_really_last";
|
||||
#define OPTION_IGNORE_INHERIT (1<<8)
|
||||
#define OPTION_IGNORE_CONTEXT_INFO (1<<9)
|
||||
#define OPTION_LEGACY_PREFIX_DOCROOT (1<<10)
|
||||
+#define OPTION_UNSAFE_PREFIX_STAT (1<<12)
|
||||
|
||||
#ifndef RAND_MAX
|
||||
#define RAND_MAX 32767
|
||||
@@ -296,6 +299,14 @@ typedef enum {
|
||||
CONDPAT_AP_EXPR
|
||||
} pattern_type;
|
||||
|
||||
+typedef enum {
|
||||
+ RULE_RC_NOMATCH = 0, /* the rule didn't match */
|
||||
+ RULE_RC_MATCH = 1, /* a matching rule w/ substitution */
|
||||
+ RULE_RC_NOSUB = 2, /* a matching rule w/ no substitution */
|
||||
+ RULE_RC_STATUS_SET = 3 /* a matching rule that has set an HTTP error
|
||||
+ to be returned in r->status */
|
||||
+} rule_return_type;
|
||||
+
|
||||
typedef struct {
|
||||
char *input; /* Input string of RewriteCond */
|
||||
char *pattern; /* the RegExp pattern string */
|
||||
@@ -927,10 +938,15 @@ static void fully_qualify_uri(request_rec *r)
|
||||
return;
|
||||
}
|
||||
|
||||
+static int startsWith(request_rec *r, const char *haystack, const char *needle) {
|
||||
+ int rc = (ap_strstr_c(haystack, needle) == haystack);
|
||||
+ rewritelog((r, 5, NULL, "prefix_stat startsWith(%s, %s) %d", haystack, needle, rc));
|
||||
+ return rc;
|
||||
+}
|
||||
/*
|
||||
- * stat() only the first segment of a path
|
||||
+ * stat() only the first segment of a path, and only if it matches the output of the last matching rule
|
||||
*/
|
||||
-static int prefix_stat(const char *path, apr_pool_t *pool)
|
||||
+static int prefix_stat(request_rec *r, const char *path, apr_pool_t *pool, rewriterule_entry *lastsub)
|
||||
{
|
||||
const char *curpath = path;
|
||||
const char *root;
|
||||
@@ -964,10 +980,36 @@ static int prefix_stat(const char *path, apr_pool_t *pool)
|
||||
apr_finfo_t sb;
|
||||
|
||||
if (apr_stat(&sb, statpath, APR_FINFO_MIN, pool) == APR_SUCCESS) {
|
||||
- return 1;
|
||||
+ if (!lastsub) {
|
||||
+ rewritelog((r, 3, NULL, "prefix_stat no lastsub subst prefix %s", statpath));
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ rewritelog((r, 3, NULL, "prefix_stat compare statpath %s and lastsub output %s STATOK %d ",
|
||||
+ statpath, lastsub->output, lastsub->flags & RULEFLAG_UNSAFE_PREFIX_STAT));
|
||||
+ if (lastsub->flags & RULEFLAG_UNSAFE_PREFIX_STAT) {
|
||||
+ return 1;
|
||||
+ }
|
||||
+ else {
|
||||
+ const char *docroot = ap_document_root(r);
|
||||
+ const char *context_docroot = ap_context_document_root(r);
|
||||
+ /*
|
||||
+ * As an example, path (r->filename) is /var/foo/bar/baz.html
|
||||
+ * even if the flag is not set, we can accept a rule that
|
||||
+ * began with a literal /var (stapath), or if the entire path
|
||||
+ * starts with the docroot or context document root
|
||||
+ */
|
||||
+ if (startsWith(r, lastsub->output, statpath) ||
|
||||
+ startsWith(r, path, docroot) ||
|
||||
+ ((docroot != context_docroot) &&
|
||||
+ startsWith(r, path, context_docroot))) {
|
||||
+ return 1;
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
+ /* prefix will be added */
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3046,6 +3088,9 @@ static const char *cmd_rewriteoptions(cmd_parms *cmd,
|
||||
else if (!strcasecmp(w, "legacyprefixdocroot")) {
|
||||
options |= OPTION_LEGACY_PREFIX_DOCROOT;
|
||||
}
|
||||
+ else if (!strcasecmp(w, "UnsafePrefixStat")) {
|
||||
+ options |= OPTION_UNSAFE_PREFIX_STAT;
|
||||
+ }
|
||||
else {
|
||||
return apr_pstrcat(cmd->pool, "RewriteOptions: unknown option '",
|
||||
w, "'", NULL);
|
||||
@@ -3752,6 +3797,18 @@ static const char *cmd_rewriterule_setflag(apr_pool_t *p, void *_cfg,
|
||||
++error;
|
||||
}
|
||||
break;
|
||||
+ case 'u':
|
||||
+ case 'U':
|
||||
+ if (!strcasecmp(key, "nsafePrefixStat")){
|
||||
+ cfg->flags |= (RULEFLAG_UNSAFE_PREFIX_STAT);
|
||||
+ }
|
||||
+ else if(!strcasecmp(key, "nsafeAllow3F")) {
|
||||
+ cfg->flags |= RULEFLAG_UNSAFE_ALLOW3F;
|
||||
+ }
|
||||
+ else {
|
||||
+ ++error;
|
||||
+ }
|
||||
+ break;
|
||||
default:
|
||||
++error;
|
||||
break;
|
||||
@@ -4102,7 +4159,8 @@ static APR_INLINE void force_type_handler(rewriterule_entry *p,
|
||||
/*
|
||||
* Apply a single RewriteRule
|
||||
*/
|
||||
-static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx)
|
||||
+static rule_return_type apply_rewrite_rule(rewriterule_entry *p,
|
||||
+ rewrite_ctx *ctx)
|
||||
{
|
||||
ap_regmatch_t regmatch[AP_MAX_REG_MATCH];
|
||||
apr_array_header_t *rewriteconds;
|
||||
@@ -4153,7 +4211,7 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx)
|
||||
rc = !ap_regexec(p->regexp, ctx->uri, AP_MAX_REG_MATCH, regmatch, 0);
|
||||
if (! (( rc && !(p->flags & RULEFLAG_NOTMATCH)) ||
|
||||
(!rc && (p->flags & RULEFLAG_NOTMATCH)) ) ) {
|
||||
- return 0;
|
||||
+ return RULE_RC_NOMATCH;
|
||||
}
|
||||
|
||||
/* It matched, wow! Now it's time to prepare the context structure for
|
||||
@@ -4204,7 +4262,7 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx)
|
||||
}
|
||||
}
|
||||
else if (!rc) {
|
||||
- return 0;
|
||||
+ return RULE_RC_NOMATCH;
|
||||
}
|
||||
|
||||
/* If some HTTP header was involved in the condition, remember it
|
||||
@@ -4224,6 +4282,15 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx)
|
||||
newuri = do_expand(p->output, ctx, p);
|
||||
rewritelog((r, 2, ctx->perdir, "rewrite '%s' -> '%s'", ctx->uri,
|
||||
newuri));
|
||||
+ if (!(p->flags & RULEFLAG_UNSAFE_ALLOW3F) &&
|
||||
+ ap_strcasestr(r->unparsed_uri, "%3f") &&
|
||||
+ ap_strchr_c(newuri, '?')) {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO()
|
||||
+ "Unsafe URL with %%3f URL rewritten without "
|
||||
+ "UnsafeAllow3F");
|
||||
+ r->status = HTTP_FORBIDDEN;
|
||||
+ return RULE_RC_STATUS_SET;
|
||||
+ }
|
||||
}
|
||||
|
||||
/* expand [E=var:val] and [CO=<cookie>] */
|
||||
@@ -4241,7 +4308,7 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx)
|
||||
r->status = p->forced_responsecode;
|
||||
}
|
||||
|
||||
- return 2;
|
||||
+ return RULE_RC_NOSUB;
|
||||
}
|
||||
|
||||
/* Now adjust API's knowledge about r->filename and r->args */
|
||||
@@ -4293,7 +4360,7 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx)
|
||||
r->filename));
|
||||
|
||||
r->filename = apr_pstrcat(r->pool, "proxy:", r->filename, NULL);
|
||||
- return 1;
|
||||
+ return RULE_RC_MATCH;
|
||||
}
|
||||
|
||||
/* If this rule is explicitly forced for HTTP redirection
|
||||
@@ -4308,7 +4375,7 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx)
|
||||
r->filename));
|
||||
|
||||
r->status = p->forced_responsecode;
|
||||
- return 1;
|
||||
+ return RULE_RC_MATCH;
|
||||
}
|
||||
|
||||
/* Special Rewriting Feature: Self-Reduction
|
||||
@@ -4330,7 +4397,7 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx)
|
||||
"with %s", p->forced_responsecode, r->filename));
|
||||
|
||||
r->status = p->forced_responsecode;
|
||||
- return 1;
|
||||
+ return RULE_RC_MATCH;
|
||||
}
|
||||
|
||||
/* Finally remember the forced mime-type */
|
||||
@@ -4339,7 +4406,7 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx)
|
||||
/* Puuhhhhhhhh... WHAT COMPLICATED STUFF ;_)
|
||||
* But now we're done for this particular rule.
|
||||
*/
|
||||
- return 1;
|
||||
+ return RULE_RC_MATCH;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -4347,13 +4414,13 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx)
|
||||
* i.e. a list of rewrite rules
|
||||
*/
|
||||
static int apply_rewrite_list(request_rec *r, apr_array_header_t *rewriterules,
|
||||
- char *perdir)
|
||||
+ char *perdir, rewriterule_entry **lastsub)
|
||||
{
|
||||
rewriterule_entry *entries;
|
||||
rewriterule_entry *p;
|
||||
int i;
|
||||
int changed;
|
||||
- int rc;
|
||||
+ rule_return_type rc;
|
||||
int s;
|
||||
rewrite_ctx *ctx;
|
||||
int round = 1;
|
||||
@@ -4361,6 +4428,7 @@ static int apply_rewrite_list(request_rec *r, apr_array_header_t *rewriterules,
|
||||
ctx = apr_palloc(r->pool, sizeof(*ctx));
|
||||
ctx->perdir = perdir;
|
||||
ctx->r = r;
|
||||
+ *lastsub = NULL;
|
||||
|
||||
/*
|
||||
* Iterate over all existing rules
|
||||
@@ -4388,7 +4456,12 @@ static int apply_rewrite_list(request_rec *r, apr_array_header_t *rewriterules,
|
||||
ctx->vary = NULL;
|
||||
rc = apply_rewrite_rule(p, ctx);
|
||||
|
||||
- if (rc) {
|
||||
+ if (rc != RULE_RC_NOMATCH) {
|
||||
+
|
||||
+ if (!(p->flags & RULEFLAG_NOSUB)) {
|
||||
+ rewritelog((r, 2, perdir, "setting lastsub to rule with output %s", p->output));
|
||||
+ *lastsub = p;
|
||||
+ }
|
||||
|
||||
/* Catch looping rules with pathinfo growing unbounded */
|
||||
if ( strlen( r->filename ) > 2*r->server->limit_req_line ) {
|
||||
@@ -4408,6 +4481,12 @@ static int apply_rewrite_list(request_rec *r, apr_array_header_t *rewriterules,
|
||||
apr_table_merge(r->headers_out, "Vary", ctx->vary);
|
||||
}
|
||||
|
||||
+
|
||||
+ /* Error while evaluating rule, r->status set */
|
||||
+ if (RULE_RC_STATUS_SET == rc) {
|
||||
+ return ACTION_STATUS_SET;
|
||||
+ }
|
||||
+
|
||||
/*
|
||||
* The rule sets the response code (implies match-only)
|
||||
*/
|
||||
@@ -4418,7 +4497,7 @@ static int apply_rewrite_list(request_rec *r, apr_array_header_t *rewriterules,
|
||||
/*
|
||||
* Indicate a change if this was not a match-only rule.
|
||||
*/
|
||||
- if (rc != 2) {
|
||||
+ if (rc != RULE_RC_NOSUB) {
|
||||
changed = ((p->flags & RULEFLAG_NOESCAPE)
|
||||
? ACTION_NOESCAPE : ACTION_NORMAL);
|
||||
}
|
||||
@@ -4607,6 +4686,7 @@ static int hook_uri2file(request_rec *r)
|
||||
int rulestatus;
|
||||
void *skipdata;
|
||||
const char *oargs;
|
||||
+ rewriterule_entry *lastsub = NULL;
|
||||
|
||||
/*
|
||||
* retrieve the config structures
|
||||
@@ -4718,7 +4798,7 @@ static int hook_uri2file(request_rec *r)
|
||||
/*
|
||||
* now apply the rules ...
|
||||
*/
|
||||
- rulestatus = apply_rewrite_list(r, conf->rewriterules, NULL);
|
||||
+ rulestatus = apply_rewrite_list(r, conf->rewriterules, NULL, &lastsub);
|
||||
apr_table_setn(r->notes, "mod_rewrite_rewritten",
|
||||
apr_psprintf(r->pool,"%d",rulestatus));
|
||||
}
|
||||
@@ -4756,6 +4836,9 @@ static int hook_uri2file(request_rec *r)
|
||||
r->status = HTTP_OK;
|
||||
return n;
|
||||
}
|
||||
+ else if (ACTION_STATUS_SET == rulestatus) {
|
||||
+ return r->status;
|
||||
+ }
|
||||
|
||||
if (to_proxyreq) {
|
||||
/* it should be go on as an internal proxy request */
|
||||
@@ -4875,23 +4958,29 @@ static int hook_uri2file(request_rec *r)
|
||||
return HTTP_BAD_REQUEST;
|
||||
}
|
||||
|
||||
- /* if there is no valid prefix, we call
|
||||
- * the translator from the core and
|
||||
- * prefix the filename with document_root
|
||||
+ /* We have r->filename as a path in a server-context rewrite without
|
||||
+ * the PT flag. The historical behavior is to treat it as a verbatim
|
||||
+ * filesystem path iff the first component of the path exists and is
|
||||
+ * readable by httpd. Otherwise, it is interpreted as DocumentRoot
|
||||
+ * relative.
|
||||
*
|
||||
* NOTICE:
|
||||
* We cannot leave out the prefix_stat because
|
||||
- * - when we always prefix with document_root
|
||||
- * then no absolute path can be created, e.g. via
|
||||
- * emulating a ScriptAlias directive, etc.
|
||||
- * - when we always NOT prefix with document_root
|
||||
+ * - If we always prefix with document_root
|
||||
+ * then no absolute path can could ever be used in
|
||||
+ * a substitution. e.g. emulating an Alias.
|
||||
+ * - If we never prefix with document_root
|
||||
* then the files under document_root have to
|
||||
* be references directly and document_root
|
||||
* gets never used and will be a dummy parameter -
|
||||
- * this is also bad
|
||||
+ * this is also bad.
|
||||
+ * - Later addition: This part is questionable.
|
||||
+ * If we had never prefixed, users would just
|
||||
+ * need %{DOCUMENT_ROOT} in substitutions or the
|
||||
+ * [PT] flag.
|
||||
*
|
||||
* BUT:
|
||||
- * Under real Unix systems this is no problem,
|
||||
+ * Under real Unix systems this is no perf problem,
|
||||
* because we only do stat() on the first directory
|
||||
* and this gets cached by the kernel for along time!
|
||||
*/
|
||||
@@ -4900,7 +4989,9 @@ static int hook_uri2file(request_rec *r)
|
||||
uri_reduced = apr_table_get(r->notes, "mod_rewrite_uri_reduced");
|
||||
}
|
||||
|
||||
- if (!prefix_stat(r->filename, r->pool) || uri_reduced != NULL) {
|
||||
+ if (!prefix_stat(r, r->filename, r->pool,
|
||||
+ conf->options & OPTION_UNSAFE_PREFIX_STAT ? NULL : lastsub)
|
||||
+ || uri_reduced != NULL) {
|
||||
int res;
|
||||
char *tmp = r->uri;
|
||||
|
||||
@@ -4945,6 +5036,7 @@ static int hook_fixup(request_rec *r)
|
||||
char *ofilename, *oargs;
|
||||
int is_proxyreq;
|
||||
void *skipdata;
|
||||
+ rewriterule_entry *lastsub;
|
||||
|
||||
dconf = (rewrite_perdir_conf *)ap_get_module_config(r->per_dir_config,
|
||||
&rewrite_module);
|
||||
@@ -5029,7 +5121,7 @@ static int hook_fixup(request_rec *r)
|
||||
/*
|
||||
* now apply the rules ...
|
||||
*/
|
||||
- rulestatus = apply_rewrite_list(r, dconf->rewriterules, dconf->directory);
|
||||
+ rulestatus = apply_rewrite_list(r, dconf->rewriterules, dconf->directory, &lastsub);
|
||||
if (rulestatus) {
|
||||
unsigned skip_absolute = is_absolute_uri(r->filename, NULL);
|
||||
int to_proxyreq = 0;
|
||||
@@ -5058,6 +5150,9 @@ static int hook_fixup(request_rec *r)
|
||||
r->status = HTTP_OK;
|
||||
return n;
|
||||
}
|
||||
+ else if (ACTION_STATUS_SET == rulestatus) {
|
||||
+ return r->status;
|
||||
+ }
|
||||
|
||||
if (to_proxyreq) {
|
||||
/* it should go on as an internal proxy request */
|
@ -1,301 +0,0 @@
|
||||
|
||||
-- backported bnotes needed by this CVE fix from https://svn.apache.org/viewvc?view=revision&revision=1887384
|
||||
-- modified it a little bit so it actually doesn't store bnotes into req structure to not brake compatibility
|
||||
-- but it stores AP_REQUEST_TRUSTED_CT info into r->notes
|
||||
|
||||
diff --git a/include/http_protocol.h b/include/http_protocol.h
|
||||
index 8ed77ac..81949ca 100644
|
||||
--- a/include/http_protocol.h
|
||||
+++ b/include/http_protocol.h
|
||||
@@ -402,6 +402,17 @@ AP_DECLARE(void) ap_clear_method_list(ap_method_list_t *l);
|
||||
*/
|
||||
AP_DECLARE(void) ap_set_content_type(request_rec *r, const char *ct);
|
||||
|
||||
+/**
|
||||
+ * Set the content type for this request (r->content_type).
|
||||
+ * @param r The current request
|
||||
+ * @param ct The new content type
|
||||
+ * @param trusted If non-zero, The content-type should come from a
|
||||
+ * trusted source such as server configuration rather
|
||||
+ * than application output.
|
||||
+ * for the AddOutputFilterByType directive to work correctly.
|
||||
+ */
|
||||
+AP_DECLARE(void) ap_set_content_type_ex(request_rec *r, const char *ct, int trusted);
|
||||
+
|
||||
/**
|
||||
* Set the Accept-Ranges header for this response
|
||||
* @param r The current request
|
||||
diff --git a/include/httpd.h b/include/httpd.h
|
||||
index 99f7f04..d8746c1 100644
|
||||
--- a/include/httpd.h
|
||||
+++ b/include/httpd.h
|
||||
@@ -645,6 +645,7 @@ struct ap_method_list_t {
|
||||
/** the array used for extension methods */
|
||||
apr_array_header_t *method_list;
|
||||
};
|
||||
+/** @} */
|
||||
|
||||
/**
|
||||
* @defgroup module_magic Module Magic mime types
|
||||
@@ -715,6 +716,31 @@ struct ap_method_list_t {
|
||||
|
||||
/** @} // values_request_rec_used_path_info */
|
||||
|
||||
+#define AP_REQUEST_TRUSTED_CT "rh-bnotes-trusted-ct"
|
||||
+
|
||||
+/**
|
||||
+ * This is a convenience macro to ease with getting specific request
|
||||
+ * binary notes.
|
||||
+ */
|
||||
+#define AP_REQUEST_GET_BNOTE(r, mask) (apr_table_get(r->notes, mask) ? 1 : 0)
|
||||
+
|
||||
+/**
|
||||
+ * This is a convenience macro to ease with setting specific request
|
||||
+ * binary notes.
|
||||
+ */
|
||||
+#define AP_REQUEST_SET_BNOTE(r, mask, val) do { \
|
||||
+ if (val) \
|
||||
+ apr_table_setn(r->notes, mask, "1"); \
|
||||
+ else \
|
||||
+ apr_table_unset(r->notes, mask); \
|
||||
+} while (0)
|
||||
+
|
||||
+/**
|
||||
+ * Returns true if the content-type field is from a trusted source
|
||||
+ */
|
||||
+#define AP_REQUEST_IS_TRUSTED_CT(r) \
|
||||
+ (!!AP_REQUEST_GET_BNOTE((r), AP_REQUEST_TRUSTED_CT))
|
||||
+/** @} */
|
||||
|
||||
/*
|
||||
* Things which may vary per file-lookup WITHIN a request ---
|
||||
diff --git a/modules/http/http_protocol.c b/modules/http/http_protocol.c
|
||||
index df862e0..d003aea 100644
|
||||
--- a/modules/http/http_protocol.c
|
||||
+++ b/modules/http/http_protocol.c
|
||||
@@ -1077,8 +1077,14 @@ AP_DECLARE(void) ap_set_content_type(request_rec *r, const char *ct)
|
||||
}
|
||||
else if (!r->content_type || strcmp(r->content_type, ct)) {
|
||||
r->content_type = ct;
|
||||
+ AP_REQUEST_SET_BNOTE(r, AP_REQUEST_TRUSTED_CT, 0);
|
||||
}
|
||||
}
|
||||
+AP_DECLARE(void) ap_set_content_type_ex(request_rec *r, const char *ct, int trusted)
|
||||
+{
|
||||
+ ap_set_content_type(r, ct);
|
||||
+ AP_REQUEST_SET_BNOTE(r, AP_REQUEST_TRUSTED_CT, trusted ? AP_REQUEST_TRUSTED_CT : 0);
|
||||
+}
|
||||
|
||||
AP_DECLARE(void) ap_set_accept_ranges(request_rec *r)
|
||||
{
|
||||
diff --git a/modules/http/mod_mime.c b/modules/http/mod_mime.c
|
||||
index 28c53be..4cd1c48 100644
|
||||
--- a/modules/http/mod_mime.c
|
||||
+++ b/modules/http/mod_mime.c
|
||||
@@ -759,7 +759,7 @@ static int find_ct(request_rec *r)
|
||||
int found_metadata = 0;
|
||||
|
||||
if (r->finfo.filetype == APR_DIR) {
|
||||
- ap_set_content_type(r, DIR_MAGIC_TYPE);
|
||||
+ ap_set_content_type_ex(r, DIR_MAGIC_TYPE, 1);
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -837,7 +837,7 @@ static int find_ct(request_rec *r)
|
||||
if (exinfo == NULL || !exinfo->forced_type) {
|
||||
if ((type = apr_hash_get(mime_type_extensions, ext,
|
||||
APR_HASH_KEY_STRING)) != NULL) {
|
||||
- ap_set_content_type(r, (char*) type);
|
||||
+ ap_set_content_type_ex(r, (char*) type, 1);
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
@@ -846,7 +846,7 @@ static int find_ct(request_rec *r)
|
||||
|
||||
/* empty string is treated as special case for RemoveType */
|
||||
if (exinfo->forced_type && *exinfo->forced_type) {
|
||||
- ap_set_content_type(r, exinfo->forced_type);
|
||||
+ ap_set_content_type_ex(r, exinfo->forced_type, 1);
|
||||
found = 1;
|
||||
}
|
||||
|
||||
@@ -951,33 +951,33 @@ static int find_ct(request_rec *r)
|
||||
memcpy(tmp, ctp->subtype, ctp->subtype_len);
|
||||
tmp += ctp->subtype_len;
|
||||
*tmp = 0;
|
||||
- ap_set_content_type(r, base_content_type);
|
||||
+ ap_set_content_type_ex(r, base_content_type, AP_REQUEST_IS_TRUSTED_CT(r));
|
||||
while (pp != NULL) {
|
||||
if (charset && !strcmp(pp->attr, "charset")) {
|
||||
if (!override) {
|
||||
- ap_set_content_type(r,
|
||||
+ ap_set_content_type_ex(r,
|
||||
apr_pstrcat(r->pool,
|
||||
r->content_type,
|
||||
"; charset=",
|
||||
charset,
|
||||
- NULL));
|
||||
+ NULL), AP_REQUEST_IS_TRUSTED_CT(r));
|
||||
override = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
- ap_set_content_type(r,
|
||||
+ ap_set_content_type_ex(r,
|
||||
apr_pstrcat(r->pool,
|
||||
r->content_type,
|
||||
"; ", pp->attr,
|
||||
"=", pp->val,
|
||||
- NULL));
|
||||
+ NULL), AP_REQUEST_IS_TRUSTED_CT(r));
|
||||
}
|
||||
pp = pp->next;
|
||||
}
|
||||
if (charset && !override) {
|
||||
- ap_set_content_type(r, apr_pstrcat(r->pool, r->content_type,
|
||||
+ ap_set_content_type_ex(r, apr_pstrcat(r->pool, r->content_type,
|
||||
"; charset=", charset,
|
||||
- NULL));
|
||||
+ NULL), AP_REQUEST_IS_TRUSTED_CT(r));
|
||||
}
|
||||
}
|
||||
}
|
||||
diff --git a/modules/mappers/mod_actions.c b/modules/mappers/mod_actions.c
|
||||
index ac9c3b7..5e398b5 100644
|
||||
--- a/modules/mappers/mod_actions.c
|
||||
+++ b/modules/mappers/mod_actions.c
|
||||
@@ -182,8 +182,10 @@ static int action_handler(request_rec *r)
|
||||
return DECLINED;
|
||||
|
||||
/* Second, check for actions (which override the method scripts) */
|
||||
- action = r->handler ? r->handler :
|
||||
- ap_field_noparam(r->pool, r->content_type);
|
||||
+ action = r->handler;
|
||||
+ if (!action && AP_REQUEST_IS_TRUSTED_CT(r)) {
|
||||
+ action = ap_field_noparam(r->pool, r->content_type);
|
||||
+ }
|
||||
|
||||
if (action && (t = apr_table_get(conf->action_types, action))) {
|
||||
int virtual = (*t++ == '0' ? 0 : 1);
|
||||
diff --git a/modules/mappers/mod_negotiation.c b/modules/mappers/mod_negotiation.c
|
||||
index da68353..e91ba5f 100644
|
||||
--- a/modules/mappers/mod_negotiation.c
|
||||
+++ b/modules/mappers/mod_negotiation.c
|
||||
@@ -1169,7 +1169,7 @@ static int read_types_multi(negotiation_state *neg)
|
||||
* might be doing.
|
||||
*/
|
||||
if (sub_req->handler && !sub_req->content_type) {
|
||||
- ap_set_content_type(sub_req, CGI_MAGIC_TYPE);
|
||||
+ ap_set_content_type_ex(sub_req, CGI_MAGIC_TYPE, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3008,14 +3008,14 @@ static int handle_map_file(request_rec *r)
|
||||
/* set MIME type and charset as negotiated */
|
||||
if (best->mime_type && *best->mime_type) {
|
||||
if (best->content_charset && *best->content_charset) {
|
||||
- ap_set_content_type(r, apr_pstrcat(r->pool,
|
||||
+ ap_set_content_type_ex(r, apr_pstrcat(r->pool,
|
||||
best->mime_type,
|
||||
"; charset=",
|
||||
best->content_charset,
|
||||
- NULL));
|
||||
+ NULL), 1);
|
||||
}
|
||||
else {
|
||||
- ap_set_content_type(r, apr_pstrdup(r->pool, best->mime_type));
|
||||
+ ap_set_content_type_ex(r, apr_pstrdup(r->pool, best->mime_type), 1);
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c
|
||||
index a25c7ae..2b70d66 100644
|
||||
--- a/modules/mappers/mod_rewrite.c
|
||||
+++ b/modules/mappers/mod_rewrite.c
|
||||
@@ -5477,7 +5477,7 @@ static int hook_mimetype(request_rec *r)
|
||||
rewritelog((r, 1, NULL, "force filename %s to have MIME-type '%s'",
|
||||
r->filename, t));
|
||||
|
||||
- ap_set_content_type(r, t);
|
||||
+ ap_set_content_type_ex(r, t, 1);
|
||||
}
|
||||
|
||||
/* handler */
|
||||
diff --git a/modules/metadata/mod_headers.c b/modules/metadata/mod_headers.c
|
||||
index 1ea970d..55ab281 100644
|
||||
--- a/modules/metadata/mod_headers.c
|
||||
+++ b/modules/metadata/mod_headers.c
|
||||
@@ -792,14 +792,14 @@ static int do_headers_fixup(request_rec *r, apr_table_t *headers,
|
||||
break;
|
||||
case hdr_set:
|
||||
if (!strcasecmp(hdr->header, "Content-Type")) {
|
||||
- ap_set_content_type(r, process_tags(hdr, r));
|
||||
+ ap_set_content_type_ex(r, process_tags(hdr, r), 1);
|
||||
}
|
||||
apr_table_setn(headers, hdr->header, process_tags(hdr, r));
|
||||
break;
|
||||
case hdr_setifempty:
|
||||
if (NULL == apr_table_get(headers, hdr->header)) {
|
||||
if (!strcasecmp(hdr->header, "Content-Type")) {
|
||||
- ap_set_content_type(r, process_tags(hdr, r));
|
||||
+ ap_set_content_type_ex(r, process_tags(hdr, r), 1);
|
||||
}
|
||||
apr_table_setn(headers, hdr->header, process_tags(hdr, r));
|
||||
}
|
||||
@@ -818,7 +818,7 @@ static int do_headers_fixup(request_rec *r, apr_table_t *headers,
|
||||
const char *repl = process_regexp(hdr, r->content_type, r);
|
||||
if (repl == NULL)
|
||||
return 0;
|
||||
- ap_set_content_type(r, repl);
|
||||
+ ap_set_content_type_ex(r, repl, 1);
|
||||
}
|
||||
if (apr_table_get(headers, hdr->header)) {
|
||||
edit_do ed;
|
||||
diff --git a/modules/metadata/mod_mime_magic.c b/modules/metadata/mod_mime_magic.c
|
||||
index c12529a..fe30f27 100644
|
||||
--- a/modules/metadata/mod_mime_magic.c
|
||||
+++ b/modules/metadata/mod_mime_magic.c
|
||||
@@ -789,7 +789,7 @@ static int magic_rsl_to_request(request_rec *r)
|
||||
/* XXX: this could be done at config time I'm sure... but I'm
|
||||
* confused by all this magic_rsl stuff. -djg */
|
||||
ap_content_type_tolower(tmp);
|
||||
- ap_set_content_type(r, tmp);
|
||||
+ ap_set_content_type_ex(r, tmp, 1);
|
||||
|
||||
if (state == rsl_encoding) {
|
||||
tmp = rsl_strdup(r, encoding_frag,
|
||||
@@ -2326,7 +2326,7 @@ static int revision_suffix(request_rec *r)
|
||||
|
||||
/* extract content type/encoding/language from sub-request */
|
||||
if (sub->content_type) {
|
||||
- ap_set_content_type(r, apr_pstrdup(r->pool, sub->content_type));
|
||||
+ ap_set_content_type_ex(r, apr_pstrdup(r->pool, sub->content_type), 1);
|
||||
#if MIME_MAGIC_DEBUG
|
||||
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01557)
|
||||
MODNAME ": subrequest %s got %s",
|
||||
diff --git a/server/config.c b/server/config.c
|
||||
index f815b22..fc4d76b 100644
|
||||
--- a/server/config.c
|
||||
+++ b/server/config.c
|
||||
@@ -419,7 +419,7 @@ AP_CORE_DECLARE(int) ap_invoke_handler(request_rec *r)
|
||||
}
|
||||
|
||||
if (!r->handler) {
|
||||
- if (r->content_type) {
|
||||
+ if (r->content_type && AP_REQUEST_IS_TRUSTED_CT(r)) {
|
||||
handler = r->content_type;
|
||||
if ((p=ap_strchr_c(handler, ';')) != NULL) {
|
||||
char *new_handler = (char *)apr_pmemdup(r->pool, handler,
|
||||
diff --git a/server/core.c b/server/core.c
|
||||
index 8575aae..82706cf 100644
|
||||
--- a/server/core.c
|
||||
+++ b/server/core.c
|
||||
@@ -4722,7 +4722,7 @@ static int core_override_type(request_rec *r)
|
||||
/* Check for overrides with ForceType / SetHandler
|
||||
*/
|
||||
if (conf->mime_type && strcmp(conf->mime_type, "none"))
|
||||
- ap_set_content_type(r, (char*) conf->mime_type);
|
||||
+ ap_set_content_type_ex(r, (char*) conf->mime_type, 1);
|
||||
|
||||
if (conf->expr_handler) {
|
||||
const char *err;
|
@ -1,29 +0,0 @@
|
||||
diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c
|
||||
index 6244e74..f5c3283 100644
|
||||
--- a/modules/proxy/proxy_util.c
|
||||
+++ b/modules/proxy/proxy_util.c
|
||||
@@ -2406,6 +2406,13 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r,
|
||||
apr_pstrcat(p,"URI cannot be parsed: ", *url,
|
||||
NULL));
|
||||
}
|
||||
+
|
||||
+ if (!uri->hostname) {
|
||||
+ return ap_proxyerror(r, HTTP_BAD_REQUEST,
|
||||
+ apr_pstrcat(p,"URI has no hostname: ", *url,
|
||||
+ NULL));
|
||||
+ }
|
||||
+
|
||||
if (!uri->port) {
|
||||
uri->port = ap_proxy_port_of_scheme(uri->scheme);
|
||||
}
|
||||
@@ -3727,6 +3734,10 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p,
|
||||
* way. No telling which legacy backend is relying no this.
|
||||
*/
|
||||
if (dconf->preserve_host == 0) {
|
||||
+ if (!uri->hostname) {
|
||||
+ rc = HTTP_BAD_REQUEST;
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
if (ap_strchr_c(uri->hostname, ':')) { /* if literal IPv6 address */
|
||||
if (uri->port_str && uri->port != DEFAULT_HTTP_PORT) {
|
||||
buf = apr_pstrcat(p, "Host: [", uri->hostname, "]:",
|
@ -1,56 +0,0 @@
|
||||
diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c
|
||||
index 797f093..114b126 100644
|
||||
--- a/modules/mappers/mod_rewrite.c
|
||||
+++ b/modules/mappers/mod_rewrite.c
|
||||
@@ -4311,6 +4311,32 @@ static rule_return_type apply_rewrite_rule(rewriterule_entry *p,
|
||||
return RULE_RC_NOSUB;
|
||||
}
|
||||
|
||||
+ /* Add the previously stripped per-directory location prefix, unless
|
||||
+ * (1) it's an absolute URL path and
|
||||
+ * (2) it's a full qualified URL
|
||||
+ */
|
||||
+ if (!is_proxyreq && *newuri != '/' && !is_absolute_uri(newuri, NULL)) {
|
||||
+ if (ctx->perdir) {
|
||||
+ rewritelog((r, 3, ctx->perdir, "add per-dir prefix: %s -> %s%s",
|
||||
+ newuri, ctx->perdir, newuri));
|
||||
+
|
||||
+ newuri = apr_pstrcat(r->pool, ctx->perdir, newuri, NULL);
|
||||
+ }
|
||||
+ else if (!(p->flags & (RULEFLAG_PROXY | RULEFLAG_FORCEREDIRECT))) {
|
||||
+ /* Not an absolute URI-path and the scheme (if any) is unknown,
|
||||
+ * and it won't be passed to fully_qualify_uri() below either,
|
||||
+ * so add an implicit '/' prefix. This avoids potentially a common
|
||||
+ * rule like "RewriteRule ^/some/path(.*) $1" that is given a path
|
||||
+ * like "/some/pathscheme:..." to produce the fully qualified URL
|
||||
+ * "scheme:..." which could be misinterpreted later.
|
||||
+ */
|
||||
+ rewritelog((r, 3, ctx->perdir, "add root prefix: %s -> /%s",
|
||||
+ newuri, newuri));
|
||||
+
|
||||
+ newuri = apr_pstrcat(r->pool, "/", newuri, NULL);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
/* Now adjust API's knowledge about r->filename and r->args */
|
||||
r->filename = newuri;
|
||||
|
||||
@@ -4320,18 +4346,6 @@ static rule_return_type apply_rewrite_rule(rewriterule_entry *p,
|
||||
|
||||
splitout_queryargs(r, p->flags);
|
||||
|
||||
- /* Add the previously stripped per-directory location prefix, unless
|
||||
- * (1) it's an absolute URL path and
|
||||
- * (2) it's a full qualified URL
|
||||
- */
|
||||
- if ( ctx->perdir && !is_proxyreq && *r->filename != '/'
|
||||
- && !is_absolute_uri(r->filename, NULL)) {
|
||||
- rewritelog((r, 3, ctx->perdir, "add per-dir prefix: %s -> %s%s",
|
||||
- r->filename, ctx->perdir, r->filename));
|
||||
-
|
||||
- r->filename = apr_pstrcat(r->pool, ctx->perdir, r->filename, NULL);
|
||||
- }
|
||||
-
|
||||
/* If this rule is forced for proxy throughput
|
||||
* (`RewriteRule ... ... [P]') then emulate mod_proxy's
|
||||
* URL-to-filename handler to be sure mod_proxy is triggered
|
@ -1,266 +0,0 @@
|
||||
diff --git a/modules/cluster/mod_heartmonitor.c b/modules/cluster/mod_heartmonitor.c
|
||||
index 965fef5..6df3bf4 100644
|
||||
--- a/modules/cluster/mod_heartmonitor.c
|
||||
+++ b/modules/cluster/mod_heartmonitor.c
|
||||
@@ -782,7 +782,7 @@ static int hm_handler(request_rec *r)
|
||||
hmserver.seen = apr_time_now();
|
||||
hm_update_stat(ctx, &hmserver, r->pool);
|
||||
|
||||
- ap_set_content_type(r, "text/plain");
|
||||
+ ap_set_content_type_ex(r, "text/plain", 1);
|
||||
ap_set_content_length(r, 2);
|
||||
ap_rputs("OK", r);
|
||||
ap_rflush(r);
|
||||
diff --git a/modules/dav/main/mod_dav.c b/modules/dav/main/mod_dav.c
|
||||
index 792b514..28479b9 100644
|
||||
--- a/modules/dav/main/mod_dav.c
|
||||
+++ b/modules/dav/main/mod_dav.c
|
||||
@@ -323,7 +323,7 @@ static int dav_error_response(request_rec *r, int status, const char *body)
|
||||
r->status = status;
|
||||
r->status_line = ap_get_status_line(status);
|
||||
|
||||
- ap_set_content_type(r, "text/html; charset=ISO-8859-1");
|
||||
+ ap_set_content_type_ex(r, "text/html; charset=ISO-8859-1", 1);
|
||||
|
||||
/* begin the response now... */
|
||||
ap_rvputs(r,
|
||||
@@ -354,7 +354,7 @@ static int dav_error_response_tag(request_rec *r,
|
||||
{
|
||||
r->status = err->status;
|
||||
|
||||
- ap_set_content_type(r, DAV_XML_CONTENT_TYPE);
|
||||
+ ap_set_content_type_ex(r, DAV_XML_CONTENT_TYPE, 1);
|
||||
|
||||
ap_rputs(DAV_XML_HEADER DEBUG_CR
|
||||
"<D:error xmlns:D=\"DAV:\"", r);
|
||||
@@ -512,7 +512,7 @@ DAV_DECLARE(void) dav_begin_multistatus(apr_bucket_brigade *bb,
|
||||
{
|
||||
/* Set the correct status and Content-Type */
|
||||
r->status = status;
|
||||
- ap_set_content_type(r, DAV_XML_CONTENT_TYPE);
|
||||
+ ap_set_content_type_ex(r, DAV_XML_CONTENT_TYPE, 1);
|
||||
|
||||
/* Send the headers and actual multistatus response now... */
|
||||
ap_fputs(r->output_filters, bb, DAV_XML_HEADER DEBUG_CR
|
||||
@@ -1923,7 +1923,7 @@ static int dav_method_options(request_rec *r)
|
||||
|
||||
/* send the options response */
|
||||
r->status = HTTP_OK;
|
||||
- ap_set_content_type(r, DAV_XML_CONTENT_TYPE);
|
||||
+ ap_set_content_type_ex(r, DAV_XML_CONTENT_TYPE, 1);
|
||||
|
||||
/* send the headers and response body */
|
||||
ap_rputs(DAV_XML_HEADER DEBUG_CR
|
||||
@@ -3191,7 +3191,7 @@ static int dav_method_lock(request_rec *r)
|
||||
(*locks_hooks->close_lockdb)(lockdb);
|
||||
|
||||
r->status = HTTP_OK;
|
||||
- ap_set_content_type(r, DAV_XML_CONTENT_TYPE);
|
||||
+ ap_set_content_type_ex(r, DAV_XML_CONTENT_TYPE, 1);
|
||||
|
||||
ap_rputs(DAV_XML_HEADER DEBUG_CR "<D:prop xmlns:D=\"DAV:\">" DEBUG_CR, r);
|
||||
if (lock == NULL)
|
||||
diff --git a/modules/examples/mod_example_hooks.c b/modules/examples/mod_example_hooks.c
|
||||
index d818dc1..4d79b86 100644
|
||||
--- a/modules/examples/mod_example_hooks.c
|
||||
+++ b/modules/examples/mod_example_hooks.c
|
||||
@@ -993,7 +993,7 @@ static int x_handler(request_rec *r)
|
||||
* Set the Content-type header. Note that we do not actually have to send
|
||||
* the headers: this is done by the http core.
|
||||
*/
|
||||
- ap_set_content_type(r, "text/html");
|
||||
+ ap_set_content_type_ex(r, "text/html", 1);
|
||||
/*
|
||||
* If we're only supposed to send header information (HEAD request), we're
|
||||
* already there.
|
||||
diff --git a/modules/filters/mod_data.c b/modules/filters/mod_data.c
|
||||
index d083d32..489e76c 100644
|
||||
--- a/modules/filters/mod_data.c
|
||||
+++ b/modules/filters/mod_data.c
|
||||
@@ -117,7 +117,7 @@ static apr_status_t data_out_filter(ap_filter_t *f, apr_bucket_brigade *bb)
|
||||
}
|
||||
}
|
||||
|
||||
- ap_set_content_type(r, "text/plain");
|
||||
+ ap_set_content_type_ex(r, "text/plain", 1);
|
||||
|
||||
}
|
||||
|
||||
diff --git a/modules/filters/mod_include.c b/modules/filters/mod_include.c
|
||||
index a46a944..05f994c 100644
|
||||
--- a/modules/filters/mod_include.c
|
||||
+++ b/modules/filters/mod_include.c
|
||||
@@ -3971,7 +3971,7 @@ static int include_fixup(request_rec *r)
|
||||
if (r->handler && (strcmp(r->handler, "server-parsed") == 0))
|
||||
{
|
||||
if (!r->content_type || !*r->content_type) {
|
||||
- ap_set_content_type(r, "text/html");
|
||||
+ ap_set_content_type_ex(r, "text/html", 1);
|
||||
}
|
||||
r->handler = "default-handler";
|
||||
}
|
||||
diff --git a/modules/filters/mod_proxy_html.c b/modules/filters/mod_proxy_html.c
|
||||
index ea6bf03..8b619e8 100644
|
||||
--- a/modules/filters/mod_proxy_html.c
|
||||
+++ b/modules/filters/mod_proxy_html.c
|
||||
@@ -933,7 +933,7 @@ static apr_status_t proxy_html_filter(ap_filter_t *f, apr_bucket_brigade *bb)
|
||||
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, f->r, APLOGNO(01422)
|
||||
"No i18n support found. Install mod_xml2enc if required");
|
||||
enc = XML_CHAR_ENCODING_NONE;
|
||||
- ap_set_content_type(f->r, "text/html;charset=utf-8");
|
||||
+ ap_set_content_type_ex(f->r, "text/html;charset=utf-8", 1);
|
||||
}
|
||||
else {
|
||||
/* if we wanted a non-default charset_out, insert the
|
||||
@@ -949,7 +949,7 @@ static apr_status_t proxy_html_filter(ap_filter_t *f, apr_bucket_brigade *bb)
|
||||
cenc, NULL));
|
||||
}
|
||||
else /* Normal case, everything worked, utf-8 output */
|
||||
- ap_set_content_type(f->r, "text/html;charset=utf-8");
|
||||
+ ap_set_content_type_ex(f->r, "text/html;charset=utf-8", 1);
|
||||
}
|
||||
|
||||
ap_fputs(f->next, ctxt->bb, ctxt->cfg->doctype);
|
||||
diff --git a/modules/generators/mod_cgi.c b/modules/generators/mod_cgi.c
|
||||
index 66cd31c..4650d18 100644
|
||||
--- a/modules/generators/mod_cgi.c
|
||||
+++ b/modules/generators/mod_cgi.c
|
||||
@@ -795,7 +795,7 @@ static apr_status_t include_cgi(include_ctx_t *ctx, ap_filter_t *f,
|
||||
/* Force sub_req to be treated as a CGI request, even if ordinary
|
||||
* typing rules would have called it something else.
|
||||
*/
|
||||
- ap_set_content_type(rr, CGI_MAGIC_TYPE);
|
||||
+ ap_set_content_type_ex(rr, CGI_MAGIC_TYPE, 1);
|
||||
|
||||
/* Run it. */
|
||||
rr_status = ap_run_sub_req(rr);
|
||||
diff --git a/modules/generators/mod_cgid.c b/modules/generators/mod_cgid.c
|
||||
index 102d2b3..57e119f 100644
|
||||
--- a/modules/generators/mod_cgid.c
|
||||
+++ b/modules/generators/mod_cgid.c
|
||||
@@ -1801,7 +1801,7 @@ static apr_status_t include_cgi(include_ctx_t *ctx, ap_filter_t *f,
|
||||
/* Force sub_req to be treated as a CGI request, even if ordinary
|
||||
* typing rules would have called it something else.
|
||||
*/
|
||||
- ap_set_content_type(rr, CGI_MAGIC_TYPE);
|
||||
+ ap_set_content_type_ex(rr, CGI_MAGIC_TYPE, 1);
|
||||
|
||||
/* Run it. */
|
||||
rr_status = ap_run_sub_req(rr);
|
||||
diff --git a/modules/generators/mod_info.c b/modules/generators/mod_info.c
|
||||
index e5e63de..67df675 100644
|
||||
--- a/modules/generators/mod_info.c
|
||||
+++ b/modules/generators/mod_info.c
|
||||
@@ -777,7 +777,7 @@ static int display_info(request_rec * r)
|
||||
return DECLINED;
|
||||
}
|
||||
|
||||
- ap_set_content_type(r, "text/html; charset=ISO-8859-1");
|
||||
+ ap_set_content_type_ex(r, "text/html; charset=ISO-8859-1", 1);
|
||||
|
||||
ap_rputs(DOCTYPE_XHTML_1_0T
|
||||
"<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"
|
||||
diff --git a/modules/generators/mod_status.c b/modules/generators/mod_status.c
|
||||
index 5bada07..2cb38c7 100644
|
||||
--- a/modules/generators/mod_status.c
|
||||
+++ b/modules/generators/mod_status.c
|
||||
@@ -273,7 +273,7 @@ static int status_handler(request_rec *r)
|
||||
if (r->method_number != M_GET)
|
||||
return DECLINED;
|
||||
|
||||
- ap_set_content_type(r, "text/html; charset=ISO-8859-1");
|
||||
+ ap_set_content_type_ex(r, "text/html; charset=ISO-8859-1", 1);
|
||||
|
||||
/*
|
||||
* Simple table-driven form data set parser that lets you alter the header
|
||||
@@ -301,7 +301,7 @@ static int status_handler(request_rec *r)
|
||||
no_table_report = 1;
|
||||
break;
|
||||
case STAT_OPT_AUTO:
|
||||
- ap_set_content_type(r, "text/plain; charset=ISO-8859-1");
|
||||
+ ap_set_content_type_ex(r, "text/plain; charset=ISO-8859-1", 1);
|
||||
short_report = 1;
|
||||
break;
|
||||
}
|
||||
diff --git a/modules/http/http_filters.c b/modules/http/http_filters.c
|
||||
index 16cb23c..27c44b2 100644
|
||||
--- a/modules/http/http_filters.c
|
||||
+++ b/modules/http/http_filters.c
|
||||
@@ -1245,7 +1245,7 @@ AP_DECLARE_NONSTD(int) ap_send_http_trace(request_rec *r)
|
||||
}
|
||||
}
|
||||
|
||||
- ap_set_content_type(r, "message/http");
|
||||
+ ap_set_content_type_ex(r, "message/http", 1);
|
||||
|
||||
/* Now we recreate the request, and echo it back */
|
||||
|
||||
diff --git a/modules/http/http_protocol.c b/modules/http/http_protocol.c
|
||||
index 417fee6..d003aea 100644
|
||||
--- a/modules/http/http_protocol.c
|
||||
+++ b/modules/http/http_protocol.c
|
||||
@@ -1423,10 +1423,10 @@ AP_DECLARE(void) ap_send_error_response(request_rec *r, int recursive_error)
|
||||
request_conf->suppress_charset = 1; /* avoid adding default
|
||||
* charset later
|
||||
*/
|
||||
- ap_set_content_type(r, "text/html");
|
||||
+ ap_set_content_type_ex(r, "text/html", 1);
|
||||
}
|
||||
else {
|
||||
- ap_set_content_type(r, "text/html; charset=iso-8859-1");
|
||||
+ ap_set_content_type_ex(r, "text/html; charset=iso-8859-1", 1);
|
||||
}
|
||||
|
||||
if ((status == HTTP_METHOD_NOT_ALLOWED)
|
||||
diff --git a/modules/http/http_request.c b/modules/http/http_request.c
|
||||
index e873aab..3521cfb 100644
|
||||
--- a/modules/http/http_request.c
|
||||
+++ b/modules/http/http_request.c
|
||||
@@ -709,7 +709,7 @@ AP_DECLARE(void) ap_internal_fast_redirect(request_rec *rr, request_rec *r)
|
||||
r->args = rr->args;
|
||||
r->finfo = rr->finfo;
|
||||
r->handler = rr->handler;
|
||||
- ap_set_content_type(r, rr->content_type);
|
||||
+ ap_set_content_type_ex(r, rr->content_type, AP_REQUEST_IS_TRUSTED_CT(rr));
|
||||
r->content_encoding = rr->content_encoding;
|
||||
r->content_languages = rr->content_languages;
|
||||
r->per_dir_config = rr->per_dir_config;
|
||||
diff --git a/modules/ldap/util_ldap.c b/modules/ldap/util_ldap.c
|
||||
index eecb3f7..b71dc98 100644
|
||||
--- a/modules/ldap/util_ldap.c
|
||||
+++ b/modules/ldap/util_ldap.c
|
||||
@@ -125,7 +125,7 @@ static int util_ldap_handler(request_rec *r)
|
||||
st = (util_ldap_state_t *) ap_get_module_config(r->server->module_config,
|
||||
&ldap_module);
|
||||
|
||||
- ap_set_content_type(r, "text/html; charset=ISO-8859-1");
|
||||
+ ap_set_content_type_ex(r, "text/html; charset=ISO-8859-1", 1);
|
||||
|
||||
if (r->header_only)
|
||||
return OK;
|
||||
diff --git a/modules/mappers/mod_imagemap.c b/modules/mappers/mod_imagemap.c
|
||||
index 187a500..3e14933 100644
|
||||
--- a/modules/mappers/mod_imagemap.c
|
||||
+++ b/modules/mappers/mod_imagemap.c
|
||||
@@ -475,7 +475,7 @@ static int imap_reply(request_rec *r, const char *redirect)
|
||||
|
||||
static void menu_header(request_rec *r, char *menu)
|
||||
{
|
||||
- ap_set_content_type(r, "text/html; charset=ISO-8859-1");
|
||||
+ ap_set_content_type_ex(r, "text/html; charset=ISO-8859-1", 1);
|
||||
|
||||
ap_rvputs(r, DOCTYPE_HTML_3_2, "<html><head>\n<title>Menu for ",
|
||||
ap_escape_html(r->pool, r->uri),
|
||||
diff --git a/modules/proxy/mod_proxy_balancer.c b/modules/proxy/mod_proxy_balancer.c
|
||||
index c599e1a..d5c20af 100644
|
||||
--- a/modules/proxy/mod_proxy_balancer.c
|
||||
+++ b/modules/proxy/mod_proxy_balancer.c
|
||||
@@ -1480,7 +1480,7 @@ static int balancer_handler(request_rec *r)
|
||||
|
||||
if (apr_table_get(params, "xml")) {
|
||||
char date[APR_RFC822_DATE_LEN];
|
||||
- ap_set_content_type(r, "text/xml");
|
||||
+ ap_set_content_type_ex(r, "text/xml", 1);
|
||||
ap_rputs("<?xml version='1.0' encoding='UTF-8' ?>\n", r);
|
||||
ap_rputs("<httpd:manager xmlns:httpd='http://httpd.apache.org'>\n", r);
|
||||
ap_rputs(" <httpd:balancers>\n", r);
|
@ -1,92 +0,0 @@
|
||||
commit 4c0e27d7bfbf46f14dfbd5d888e56c64ad8c8de5
|
||||
Author: Tomas Korbar <tkorbar@redhat.com>
|
||||
Date: Mon Sep 19 13:22:27 2022 +0200
|
||||
|
||||
Backport refactor of SNI support to httpd-2.4.37
|
||||
|
||||
diff --git a/modules/http2/mod_proxy_http2.c b/modules/http2/mod_proxy_http2.c
|
||||
index a7e0dcd..31ccd32 100644
|
||||
--- a/modules/http2/mod_proxy_http2.c
|
||||
+++ b/modules/http2/mod_proxy_http2.c
|
||||
@@ -591,16 +591,6 @@ run_connect:
|
||||
}
|
||||
|
||||
if (!ctx->p_conn->data) {
|
||||
- /* New conection: set a note on the connection what CN is
|
||||
- * requested and what protocol we want */
|
||||
- if (ctx->p_conn->ssl_hostname) {
|
||||
- ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, ctx->owner,
|
||||
- "set SNI to %s for (%s)",
|
||||
- ctx->p_conn->ssl_hostname,
|
||||
- ctx->p_conn->hostname);
|
||||
- apr_table_setn(ctx->p_conn->connection->notes,
|
||||
- "proxy-request-hostname", ctx->p_conn->ssl_hostname);
|
||||
- }
|
||||
if (ctx->is_ssl) {
|
||||
apr_table_setn(ctx->p_conn->connection->notes,
|
||||
"proxy-request-alpn-protos", "h2");
|
||||
diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c
|
||||
index 1b7bb81..c1c591a 100644
|
||||
--- a/modules/proxy/mod_proxy_http.c
|
||||
+++ b/modules/proxy/mod_proxy_http.c
|
||||
@@ -2111,19 +2111,6 @@ static int proxy_http_handler(request_rec *r, proxy_worker *worker,
|
||||
req->origin->keepalive = AP_CONN_CLOSE;
|
||||
}
|
||||
|
||||
- /*
|
||||
- * On SSL connections set a note on the connection what CN is
|
||||
- * requested, such that mod_ssl can check if it is requested to do
|
||||
- * so.
|
||||
- *
|
||||
- * https://github.com/apache/httpd/commit/7d272e2628b4ae05f68cdc74b070707250896a34
|
||||
- */
|
||||
- if (backend->ssl_hostname) {
|
||||
- apr_table_setn(backend->connection->notes,
|
||||
- "proxy-request-hostname",
|
||||
- backend->ssl_hostname);
|
||||
- }
|
||||
-
|
||||
/* Step Four: Send the Request
|
||||
* On the off-chance that we forced a 100-Continue as a
|
||||
* kinda HTTP ping test, allow for retries
|
||||
diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c
|
||||
index ec9a414..805820d 100644
|
||||
--- a/modules/proxy/proxy_util.c
|
||||
+++ b/modules/proxy/proxy_util.c
|
||||
@@ -3261,6 +3261,16 @@ static int proxy_connection_create(const char *proxy_function,
|
||||
backend_addr, conn->hostname);
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
+ if (conn->ssl_hostname) {
|
||||
+ /* Set a note on the connection about what CN is requested,
|
||||
+ * such that mod_ssl can check if it is requested to do so.
|
||||
+ */
|
||||
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, conn->connection,
|
||||
+ "%s: set SNI to %s for (%s)", proxy_function,
|
||||
+ conn->ssl_hostname, conn->hostname);
|
||||
+ apr_table_setn(conn->connection->notes, "proxy-request-hostname",
|
||||
+ conn->ssl_hostname);
|
||||
+ }
|
||||
}
|
||||
else {
|
||||
/* TODO: See if this will break FTP */
|
||||
diff --git a/modules/ssl/ssl_engine_io.c b/modules/ssl/ssl_engine_io.c
|
||||
index 4e3875a..9b4280c 100644
|
||||
--- a/modules/ssl/ssl_engine_io.c
|
||||
+++ b/modules/ssl/ssl_engine_io.c
|
||||
@@ -1273,7 +1273,6 @@ static apr_status_t ssl_io_filter_handshake(ssl_filter_ctx_t *filter_ctx)
|
||||
((dc->proxy->ssl_check_peer_cn != FALSE) ||
|
||||
(dc->proxy->ssl_check_peer_name == TRUE)) &&
|
||||
hostname_note) {
|
||||
- apr_table_unset(c->notes, "proxy-request-hostname");
|
||||
if (!cert
|
||||
|| modssl_X509_match_name(c->pool, cert, hostname_note,
|
||||
TRUE, server) == FALSE) {
|
||||
@@ -1290,7 +1289,6 @@ static apr_status_t ssl_io_filter_handshake(ssl_filter_ctx_t *filter_ctx)
|
||||
|
||||
hostname = ssl_var_lookup(NULL, server, c, NULL,
|
||||
"SSL_CLIENT_S_DN_CN");
|
||||
- apr_table_unset(c->notes, "proxy-request-hostname");
|
||||
|
||||
/* Do string match or simplest wildcard match if that
|
||||
* fails. */
|
@ -1,225 +0,0 @@
|
||||
diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c
|
||||
index ec1e042..2c0500f 100644
|
||||
--- a/modules/proxy/mod_proxy_http.c
|
||||
+++ b/modules/proxy/mod_proxy_http.c
|
||||
@@ -310,16 +310,18 @@ static int stream_reqbody_read(proxy_http_req_t *req, apr_bucket_brigade *bb,
|
||||
return OK;
|
||||
}
|
||||
|
||||
-static int stream_reqbody(proxy_http_req_t *req, rb_methods rb_method)
|
||||
+static int stream_reqbody(proxy_http_req_t *req)
|
||||
{
|
||||
request_rec *r = req->r;
|
||||
int seen_eos = 0, rv = OK;
|
||||
apr_size_t hdr_len;
|
||||
char chunk_hdr[20]; /* must be here due to transient bucket. */
|
||||
+ conn_rec *origin = req->origin;
|
||||
proxy_conn_rec *p_conn = req->backend;
|
||||
apr_bucket_alloc_t *bucket_alloc = req->bucket_alloc;
|
||||
apr_bucket_brigade *header_brigade = req->header_brigade;
|
||||
apr_bucket_brigade *input_brigade = req->input_brigade;
|
||||
+ rb_methods rb_method = req->rb_method;
|
||||
apr_off_t bytes, bytes_streamed = 0;
|
||||
apr_bucket *e;
|
||||
|
||||
@@ -333,7 +335,7 @@ static int stream_reqbody(proxy_http_req_t *req, rb_methods rb_method)
|
||||
}
|
||||
|
||||
if (!APR_BRIGADE_EMPTY(input_brigade)) {
|
||||
- /* If this brigade contains EOS, either stop or remove it. */
|
||||
+ /* If this brigade contains EOS, remove it and be done. */
|
||||
if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) {
|
||||
seen_eos = 1;
|
||||
|
||||
@@ -375,7 +377,8 @@ static int stream_reqbody(proxy_http_req_t *req, rb_methods rb_method)
|
||||
APR_BRIGADE_INSERT_TAIL(input_brigade, e);
|
||||
}
|
||||
}
|
||||
- else if (bytes_streamed > req->cl_val) {
|
||||
+ else if (rb_method == RB_STREAM_CL
|
||||
+ && bytes_streamed > req->cl_val) {
|
||||
/* C-L < bytes streamed?!?
|
||||
* We will error out after the body is completely
|
||||
* consumed, but we can't stream more bytes at the
|
||||
@@ -407,7 +410,7 @@ static int stream_reqbody(proxy_http_req_t *req, rb_methods rb_method)
|
||||
APR_BRIGADE_PREPEND(input_brigade, header_brigade);
|
||||
|
||||
/* Flush here on EOS because we won't stream_reqbody_read() again */
|
||||
- rv = ap_proxy_pass_brigade(bucket_alloc, r, p_conn, req->origin,
|
||||
+ rv = ap_proxy_pass_brigade(bucket_alloc, r, p_conn, origin,
|
||||
input_brigade, seen_eos);
|
||||
if (rv != OK) {
|
||||
return rv;
|
||||
@@ -454,10 +457,6 @@ static int spool_reqbody_cl(proxy_http_req_t *req, apr_off_t *bytes_spooled)
|
||||
/* If this brigade contains EOS, either stop or remove it. */
|
||||
if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) {
|
||||
seen_eos = 1;
|
||||
-
|
||||
- /* We can't pass this EOS to the output_filters. */
|
||||
- e = APR_BRIGADE_LAST(input_brigade);
|
||||
- apr_bucket_delete(e);
|
||||
}
|
||||
|
||||
apr_brigade_length(input_brigade, 1, &bytes);
|
||||
@@ -644,7 +643,18 @@ static int ap_proxy_http_prefetch(proxy_http_req_t *req,
|
||||
*/
|
||||
temp_brigade = apr_brigade_create(p, bucket_alloc);
|
||||
block = req->prefetch_nonblocking ? APR_NONBLOCK_READ : APR_BLOCK_READ;
|
||||
- do {
|
||||
+
|
||||
+ /* Account for saved input, if any. */
|
||||
+ apr_brigade_length(input_brigade, 0, &bytes_read);
|
||||
+
|
||||
+ /* Ensure we don't hit a wall where we have a buffer too small
|
||||
+ * for ap_get_brigade's filters to fetch us another bucket,
|
||||
+ * surrender once we hit 80 bytes less than MAX_MEM_SPOOL
|
||||
+ * (an arbitrary value).
|
||||
+ */
|
||||
+ while (bytes_read < MAX_MEM_SPOOL - 80
|
||||
+ && (APR_BRIGADE_EMPTY(input_brigade)
|
||||
+ || !APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade)))) {
|
||||
status = ap_get_brigade(r->input_filters, temp_brigade,
|
||||
AP_MODE_READBYTES, block,
|
||||
MAX_MEM_SPOOL - bytes_read);
|
||||
@@ -686,15 +696,7 @@ static int ap_proxy_http_prefetch(proxy_http_req_t *req,
|
||||
c->client_ip, c->remote_host ? c->remote_host: "");
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
-
|
||||
- /* Ensure we don't hit a wall where we have a buffer too small
|
||||
- * for ap_get_brigade's filters to fetch us another bucket,
|
||||
- * surrender once we hit 80 bytes less than MAX_MEM_SPOOL
|
||||
- * (an arbitrary value.)
|
||||
- */
|
||||
- } while ((bytes_read < MAX_MEM_SPOOL - 80)
|
||||
- && !APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))
|
||||
- && !req->prefetch_nonblocking);
|
||||
+ }
|
||||
|
||||
/* Use chunked request body encoding or send a content-length body?
|
||||
*
|
||||
@@ -838,35 +840,21 @@ static int ap_proxy_http_request(proxy_http_req_t *req)
|
||||
{
|
||||
int rv;
|
||||
request_rec *r = req->r;
|
||||
- apr_bucket_alloc_t *bucket_alloc = req->bucket_alloc;
|
||||
- apr_bucket_brigade *header_brigade = req->header_brigade;
|
||||
- apr_bucket_brigade *input_brigade = req->input_brigade;
|
||||
|
||||
/* send the request header/body, if any. */
|
||||
switch (req->rb_method) {
|
||||
+ case RB_SPOOL_CL:
|
||||
case RB_STREAM_CL:
|
||||
case RB_STREAM_CHUNKED:
|
||||
if (req->do_100_continue) {
|
||||
- rv = ap_proxy_pass_brigade(bucket_alloc, r, req->backend,
|
||||
- req->origin, header_brigade, 1);
|
||||
+ rv = ap_proxy_pass_brigade(req->bucket_alloc, r, req->backend,
|
||||
+ req->origin, req->header_brigade, 1);
|
||||
}
|
||||
else {
|
||||
- rv = stream_reqbody(req, req->rb_method);
|
||||
+ rv = stream_reqbody(req);
|
||||
}
|
||||
break;
|
||||
|
||||
- case RB_SPOOL_CL:
|
||||
- /* Prefetch has built the header and spooled the whole body;
|
||||
- * if we don't expect 100-continue we can flush both all at once,
|
||||
- * otherwise flush the header only.
|
||||
- */
|
||||
- if (!req->do_100_continue) {
|
||||
- APR_BRIGADE_CONCAT(header_brigade, input_brigade);
|
||||
- }
|
||||
- rv = ap_proxy_pass_brigade(bucket_alloc, r, req->backend,
|
||||
- req->origin, header_brigade, 1);
|
||||
- break;
|
||||
-
|
||||
default:
|
||||
/* shouldn't be possible */
|
||||
rv = HTTP_INTERNAL_SERVER_ERROR;
|
||||
@@ -1577,15 +1565,10 @@ int ap_proxy_http_process_response(proxy_http_req_t *req)
|
||||
|
||||
/* Send the request body (fully). */
|
||||
switch(req->rb_method) {
|
||||
+ case RB_SPOOL_CL:
|
||||
case RB_STREAM_CL:
|
||||
case RB_STREAM_CHUNKED:
|
||||
- status = stream_reqbody(req, req->rb_method);
|
||||
- break;
|
||||
- case RB_SPOOL_CL:
|
||||
- /* Prefetch has spooled the whole body, flush it. */
|
||||
- status = ap_proxy_pass_brigade(req->bucket_alloc, r,
|
||||
- backend, origin,
|
||||
- req->input_brigade, 1);
|
||||
+ status = stream_reqbody(req);
|
||||
break;
|
||||
default:
|
||||
/* Shouldn't happen */
|
||||
@@ -1940,6 +1923,7 @@ static int proxy_http_handler(request_rec *r, proxy_worker *worker,
|
||||
const char *u;
|
||||
proxy_http_req_t *req = NULL;
|
||||
proxy_conn_rec *backend = NULL;
|
||||
+ apr_bucket_brigade *input_brigade = NULL;
|
||||
int is_ssl = 0;
|
||||
conn_rec *c = r->connection;
|
||||
proxy_dir_conf *dconf;
|
||||
@@ -2005,8 +1989,20 @@ static int proxy_http_handler(request_rec *r, proxy_worker *worker,
|
||||
|
||||
dconf = ap_get_module_config(r->per_dir_config, &proxy_module);
|
||||
|
||||
+ /* We possibly reuse input data prefetched in previous call(s), e.g. for a
|
||||
+ * balancer fallback scenario, and in this case the 100 continue settings
|
||||
+ * should be consistent between balancer members. If not, we need to ignore
|
||||
+ * Proxy100Continue on=>off once we tried to prefetch already, otherwise
|
||||
+ * the HTTP_IN filter won't send 100 Continue for us anymore, and we might
|
||||
+ * deadlock with the client waiting for each other. Note that off=>on is
|
||||
+ * not an issue because in this case r->expecting_100 is false (the 100
|
||||
+ * Continue is out already), but we make sure that prefetch will be
|
||||
+ * nonblocking to avoid passing more time there.
|
||||
+ */
|
||||
+ apr_pool_userdata_get((void **)&input_brigade, "proxy-req-input", p);
|
||||
+
|
||||
/* Should we handle end-to-end or ping 100-continue? */
|
||||
- if ((r->expecting_100 && dconf->forward_100_continue)
|
||||
+ if ((r->expecting_100 && (dconf->forward_100_continue || input_brigade))
|
||||
|| PROXY_DO_100_CONTINUE(worker, r)) {
|
||||
/* We need to reset r->expecting_100 or prefetching will cause
|
||||
* ap_http_filter() to send "100 Continue" response by itself. So
|
||||
@@ -2023,7 +2019,8 @@ static int proxy_http_handler(request_rec *r, proxy_worker *worker,
|
||||
/* Should we block while prefetching the body or try nonblocking and flush
|
||||
* data to the backend ASAP?
|
||||
*/
|
||||
- else if (apr_table_get(r->subprocess_env, "proxy-prefetch-nonblocking")) {
|
||||
+ else if (input_brigade || apr_table_get(r->subprocess_env,
|
||||
+ "proxy-prefetch-nonblocking")) {
|
||||
req->prefetch_nonblocking = 1;
|
||||
}
|
||||
|
||||
@@ -2048,6 +2045,17 @@ static int proxy_http_handler(request_rec *r, proxy_worker *worker,
|
||||
sizeof(req->server_portstr))))
|
||||
goto cleanup;
|
||||
|
||||
+ /* The header is always (re-)built since it depends on worker settings,
|
||||
+ * but the body can be fetched only once (even partially), so it's saved
|
||||
+ * in between proxy_http_handler() calls should we come back here.
|
||||
+ */
|
||||
+ req->header_brigade = apr_brigade_create(p, req->bucket_alloc);
|
||||
+ if (input_brigade == NULL) {
|
||||
+ input_brigade = apr_brigade_create(p, req->bucket_alloc);
|
||||
+ apr_pool_userdata_setn(input_brigade, "proxy-req-input", NULL, p);
|
||||
+ }
|
||||
+ req->input_brigade = input_brigade;
|
||||
+
|
||||
/* Prefetch (nonlocking) the request body so to increase the chance to get
|
||||
* the whole (or enough) body and determine Content-Length vs chunked or
|
||||
* spooled. By doing this before connecting or reusing the backend, we want
|
||||
@@ -2058,8 +2066,6 @@ static int proxy_http_handler(request_rec *r, proxy_worker *worker,
|
||||
* to reduce to the minimum the unavoidable local is_socket_connected() vs
|
||||
* remote keepalive race condition.
|
||||
*/
|
||||
- req->input_brigade = apr_brigade_create(p, req->bucket_alloc);
|
||||
- req->header_brigade = apr_brigade_create(p, req->bucket_alloc);
|
||||
if ((status = ap_proxy_http_prefetch(req, uri, locurl)) != OK)
|
||||
goto cleanup;
|
||||
|
@ -1,42 +0,0 @@
|
||||
diff --git a/modules/ssl/mod_ssl.c b/modules/ssl/mod_ssl.c
|
||||
index 37947e7..b50c259 100644
|
||||
--- a/modules/ssl/mod_ssl.c
|
||||
+++ b/modules/ssl/mod_ssl.c
|
||||
@@ -331,9 +331,6 @@ static apr_status_t ssl_cleanup_pre_config(void *data)
|
||||
/*
|
||||
* Try to kill the internals of the SSL library.
|
||||
*/
|
||||
-#ifdef HAVE_FIPS
|
||||
- FIPS_mode_set(0);
|
||||
-#endif
|
||||
/* Corresponds to OBJ_create()s */
|
||||
OBJ_cleanup();
|
||||
/* Corresponds to OPENSSL_load_builtin_modules() */
|
||||
diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c
|
||||
index 5063a72..21e41e2 100644
|
||||
--- a/modules/ssl/ssl_engine_init.c
|
||||
+++ b/modules/ssl/ssl_engine_init.c
|
||||
@@ -183,6 +183,14 @@ int ssl_is_challenge(conn_rec *c, const char *servername,
|
||||
return 0;
|
||||
}
|
||||
|
||||
+#ifdef HAVE_FIPS
|
||||
+static apr_status_t ssl_fips_cleanup(void *data)
|
||||
+{
|
||||
+ FIPS_mode_set(0);
|
||||
+ return APR_SUCCESS;
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
/*
|
||||
* Per-module initialization
|
||||
*/
|
||||
@@ -316,6 +324,8 @@ apr_status_t ssl_init_Module(apr_pool_t *p, apr_pool_t *plog,
|
||||
if (FIPS_mode_set(1)) {
|
||||
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, APLOGNO(01884)
|
||||
"Operating in SSL FIPS mode");
|
||||
+ apr_pool_cleanup_register(p, NULL, ssl_fips_cleanup,
|
||||
+ apr_pool_cleanup_null);
|
||||
}
|
||||
else {
|
||||
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01885) "FIPS mode failed");
|
@ -1,199 +0,0 @@
|
||||
diff --git a/modules/proxy/mod_proxy_hcheck.c b/modules/proxy/mod_proxy_hcheck.c
|
||||
index bd89779..d7c0a68 100644
|
||||
--- a/modules/proxy/mod_proxy_hcheck.c
|
||||
+++ b/modules/proxy/mod_proxy_hcheck.c
|
||||
@@ -33,7 +33,6 @@ module AP_MODULE_DECLARE_DATA proxy_hcheck_module;
|
||||
#endif
|
||||
#else
|
||||
#define HC_USE_THREADS 0
|
||||
-typedef void apr_thread_pool_t;
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
@@ -73,7 +72,7 @@ typedef struct {
|
||||
proxy_balancer *balancer;
|
||||
proxy_worker *worker;
|
||||
proxy_worker *hc;
|
||||
- apr_time_t now;
|
||||
+ apr_time_t *now;
|
||||
} baton_t;
|
||||
|
||||
static void *hc_create_config(apr_pool_t *p, server_rec *s)
|
||||
@@ -89,7 +88,10 @@ static void *hc_create_config(apr_pool_t *p, server_rec *s)
|
||||
}
|
||||
|
||||
static ap_watchdog_t *watchdog;
|
||||
-static int tpsize = HC_THREADPOOL_SIZE;
|
||||
+#if HC_USE_THREADS
|
||||
+static apr_thread_pool_t *hctp;
|
||||
+static int tpsize;
|
||||
+#endif
|
||||
|
||||
/*
|
||||
* This serves double duty by not only validating (and creating)
|
||||
@@ -825,29 +827,28 @@ static void * APR_THREAD_FUNC hc_check(apr_thread_t *thread, void *b)
|
||||
server_rec *s = baton->ctx->s;
|
||||
proxy_worker *worker = baton->worker;
|
||||
proxy_worker *hc = baton->hc;
|
||||
- apr_time_t now = baton->now;
|
||||
+ apr_time_t now;
|
||||
apr_status_t rv;
|
||||
|
||||
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(03256)
|
||||
"%sHealth checking %s", (thread ? "Threaded " : ""),
|
||||
worker->s->name);
|
||||
|
||||
- worker->s->updated = now;
|
||||
if (hc->s->method == TCP) {
|
||||
rv = hc_check_tcp(baton);
|
||||
}
|
||||
else {
|
||||
rv = hc_check_http(baton);
|
||||
}
|
||||
+
|
||||
+ now = apr_time_now();
|
||||
if (rv == APR_ENOTIMPL) {
|
||||
ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(03257)
|
||||
"Somehow tried to use unimplemented hcheck method: %d",
|
||||
(int)hc->s->method);
|
||||
- apr_pool_destroy(baton->ptemp);
|
||||
- return NULL;
|
||||
}
|
||||
/* what state are we in ? */
|
||||
- if (PROXY_WORKER_IS_HCFAILED(worker)) {
|
||||
+ else if (PROXY_WORKER_IS_HCFAILED(worker)) {
|
||||
if (rv == APR_SUCCESS) {
|
||||
worker->s->pcount += 1;
|
||||
if (worker->s->pcount >= worker->s->passes) {
|
||||
@@ -860,7 +861,8 @@ static void * APR_THREAD_FUNC hc_check(apr_thread_t *thread, void *b)
|
||||
|
||||
}
|
||||
}
|
||||
- } else {
|
||||
+ }
|
||||
+ else {
|
||||
if (rv != APR_SUCCESS) {
|
||||
worker->s->error_time = now;
|
||||
worker->s->fcount += 1;
|
||||
@@ -873,7 +875,12 @@ static void * APR_THREAD_FUNC hc_check(apr_thread_t *thread, void *b)
|
||||
}
|
||||
}
|
||||
}
|
||||
+ if (baton->now) {
|
||||
+ *baton->now = now;
|
||||
+ }
|
||||
apr_pool_destroy(baton->ptemp);
|
||||
+ worker->s->updated = now;
|
||||
+
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -881,12 +888,10 @@ static apr_status_t hc_watchdog_callback(int state, void *data,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
apr_status_t rv = APR_SUCCESS;
|
||||
- apr_time_t now = apr_time_now();
|
||||
proxy_balancer *balancer;
|
||||
sctx_t *ctx = (sctx_t *)data;
|
||||
server_rec *s = ctx->s;
|
||||
proxy_server_conf *conf;
|
||||
- static apr_thread_pool_t *hctp = NULL;
|
||||
|
||||
switch (state) {
|
||||
case AP_WATCHDOG_STATE_STARTING:
|
||||
@@ -913,7 +918,6 @@ static apr_status_t hc_watchdog_callback(int state, void *data,
|
||||
"Skipping apr_thread_pool_create()");
|
||||
hctp = NULL;
|
||||
}
|
||||
-
|
||||
#endif
|
||||
break;
|
||||
|
||||
@@ -929,45 +933,53 @@ static apr_status_t hc_watchdog_callback(int state, void *data,
|
||||
ctx->s = s;
|
||||
for (i = 0; i < conf->balancers->nelts; i++, balancer++) {
|
||||
int n;
|
||||
+ apr_time_t now;
|
||||
proxy_worker **workers;
|
||||
proxy_worker *worker;
|
||||
/* Have any new balancers or workers been added dynamically? */
|
||||
ap_proxy_sync_balancer(balancer, s, conf);
|
||||
workers = (proxy_worker **)balancer->workers->elts;
|
||||
+ now = apr_time_now();
|
||||
for (n = 0; n < balancer->workers->nelts; n++) {
|
||||
worker = *workers;
|
||||
if (!PROXY_WORKER_IS(worker, PROXY_WORKER_STOPPED) &&
|
||||
- (worker->s->method != NONE) &&
|
||||
- (now > worker->s->updated + worker->s->interval)) {
|
||||
+ (worker->s->method != NONE) &&
|
||||
+ (worker->s->updated != 0) &&
|
||||
+ (now > worker->s->updated + worker->s->interval)) {
|
||||
baton_t *baton;
|
||||
apr_pool_t *ptemp;
|
||||
+
|
||||
ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, s,
|
||||
"Checking %s worker: %s [%d] (%pp)", balancer->s->name,
|
||||
worker->s->name, worker->s->method, worker);
|
||||
|
||||
if ((rv = hc_init_worker(ctx, worker)) != APR_SUCCESS) {
|
||||
+ worker->s->updated = now;
|
||||
return rv;
|
||||
}
|
||||
- /* This pool must last the lifetime of the (possible) thread */
|
||||
+ worker->s->updated = 0;
|
||||
+
|
||||
+ /* This pool has the lifetime of the check */
|
||||
apr_pool_create(&ptemp, ctx->p);
|
||||
apr_pool_tag(ptemp, "hc_request");
|
||||
- baton = apr_palloc(ptemp, sizeof(baton_t));
|
||||
+ baton = apr_pcalloc(ptemp, sizeof(baton_t));
|
||||
baton->ctx = ctx;
|
||||
- baton->now = now;
|
||||
baton->balancer = balancer;
|
||||
baton->worker = worker;
|
||||
baton->ptemp = ptemp;
|
||||
baton->hc = hc_get_hcworker(ctx, worker, ptemp);
|
||||
-
|
||||
- if (!hctp) {
|
||||
- hc_check(NULL, baton);
|
||||
- }
|
||||
#if HC_USE_THREADS
|
||||
- else {
|
||||
- rv = apr_thread_pool_push(hctp, hc_check, (void *)baton,
|
||||
- APR_THREAD_TASK_PRIORITY_NORMAL, NULL);
|
||||
+ if (hctp) {
|
||||
+ apr_thread_pool_push(hctp, hc_check, (void *)baton,
|
||||
+ APR_THREAD_TASK_PRIORITY_NORMAL,
|
||||
+ NULL);
|
||||
}
|
||||
+ else
|
||||
#endif
|
||||
+ {
|
||||
+ baton->now = &now;
|
||||
+ hc_check(NULL, baton);
|
||||
+ }
|
||||
}
|
||||
workers++;
|
||||
}
|
||||
@@ -986,9 +998,9 @@ static apr_status_t hc_watchdog_callback(int state, void *data,
|
||||
ap_log_error(APLOG_MARK, APLOG_INFO, rv, s, APLOGNO(03315)
|
||||
"apr_thread_pool_destroy() failed");
|
||||
}
|
||||
+ hctp = NULL;
|
||||
}
|
||||
#endif
|
||||
- hctp = NULL;
|
||||
break;
|
||||
}
|
||||
return rv;
|
||||
@@ -996,7 +1008,10 @@ static apr_status_t hc_watchdog_callback(int state, void *data,
|
||||
static int hc_pre_config(apr_pool_t *pconf, apr_pool_t *plog,
|
||||
apr_pool_t *ptemp)
|
||||
{
|
||||
+#if HC_USE_THREADS
|
||||
+ hctp = NULL;
|
||||
tpsize = HC_THREADPOOL_SIZE;
|
||||
+#endif
|
||||
return OK;
|
||||
}
|
||||
static int hc_post_config(apr_pool_t *p, apr_pool_t *plog,
|
@ -1,544 +0,0 @@
|
||||
diff --git a/modules/ssl/mod_ssl.h b/modules/ssl/mod_ssl.h
|
||||
index 24a65a0..a360911 100644
|
||||
--- a/modules/ssl/mod_ssl.h
|
||||
+++ b/modules/ssl/mod_ssl.h
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "httpd.h"
|
||||
#include "http_config.h"
|
||||
#include "apr_optional.h"
|
||||
+#include "apr_tables.h" /* for apr_array_header_t */
|
||||
|
||||
/* Create a set of SSL_DECLARE(type), SSL_DECLARE_NONSTD(type) and
|
||||
* SSL_DECLARE_DATA with appropriate export and import tags for the platform
|
||||
@@ -86,6 +87,34 @@ APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *));
|
||||
APR_DECLARE_OPTIONAL_FN(int, ssl_engine_set, (conn_rec *,
|
||||
ap_conf_vector_t *,
|
||||
int proxy, int enable));
|
||||
+
|
||||
+/* Check for availability of new hooks */
|
||||
+#define SSL_CERT_HOOKS
|
||||
+#ifdef SSL_CERT_HOOKS
|
||||
+
|
||||
+/** Lets others add certificate and key files to the given server.
|
||||
+ * For each cert a key must also be added.
|
||||
+ * @param cert_file and array of const char* with the path to the certificate chain
|
||||
+ * @param key_file and array of const char* with the path to the private key file
|
||||
+ */
|
||||
+APR_DECLARE_EXTERNAL_HOOK(ssl, SSL, int, add_cert_files,
|
||||
+ (server_rec *s, apr_pool_t *p,
|
||||
+ apr_array_header_t *cert_files,
|
||||
+ apr_array_header_t *key_files))
|
||||
+
|
||||
+/** In case no certificates are available for a server, this
|
||||
+ * lets other modules add a fallback certificate for the time
|
||||
+ * being. Regular requests against this server will be answered
|
||||
+ * with a 503.
|
||||
+ * @param cert_file and array of const char* with the path to the certificate chain
|
||||
+ * @param key_file and array of const char* with the path to the private key file
|
||||
+ */
|
||||
+APR_DECLARE_EXTERNAL_HOOK(ssl, SSL, int, add_fallback_cert_files,
|
||||
+ (server_rec *s, apr_pool_t *p,
|
||||
+ apr_array_header_t *cert_files,
|
||||
+ apr_array_header_t *key_files))
|
||||
+
|
||||
+#endif /* SSL_CERT_HOOKS */
|
||||
|
||||
#endif /* __MOD_SSL_H__ */
|
||||
/** @} */
|
||||
diff --git a/modules/ssl/mod_ssl_openssl.h b/modules/ssl/mod_ssl_openssl.h
|
||||
index 0fa654a..d4f684f 100644
|
||||
--- a/modules/ssl/mod_ssl_openssl.h
|
||||
+++ b/modules/ssl/mod_ssl_openssl.h
|
||||
@@ -69,5 +69,45 @@ APR_DECLARE_EXTERNAL_HOOK(ssl, SSL, int, pre_handshake,
|
||||
APR_DECLARE_EXTERNAL_HOOK(ssl, SSL, int, proxy_post_handshake,
|
||||
(conn_rec *c, SSL *ssl))
|
||||
|
||||
+/** On TLS connections that do not relate to a configured virtual host,
|
||||
+ * allow other modules to provide a X509 certificate and EVP_PKEY to
|
||||
+ * be used on the connection. This first hook which does not
|
||||
+ * return DECLINED will determine the outcome. */
|
||||
+APR_DECLARE_EXTERNAL_HOOK(ssl, SSL, int, answer_challenge,
|
||||
+ (conn_rec *c, const char *server_name,
|
||||
+ X509 **pcert, EVP_PKEY **pkey))
|
||||
+
|
||||
+/** During post_config phase, ask around if someone wants to provide
|
||||
+ * OCSP stapling status information for the given cert (with the also
|
||||
+ * provided issuer certificate). The first hook which does not
|
||||
+ * return DECLINED promises to take responsibility (and respond
|
||||
+ * in later calls via hook ssl_get_stapling_status).
|
||||
+ * If no hook takes over, mod_ssl's own stapling implementation will
|
||||
+ * be applied (if configured).
|
||||
+ */
|
||||
+APR_DECLARE_EXTERNAL_HOOK(ssl, SSL, int, init_stapling_status,
|
||||
+ (server_rec *s, apr_pool_t *p,
|
||||
+ X509 *cert, X509 *issuer))
|
||||
+
|
||||
+/** Anyone answering positive to ssl_init_stapling_status for a
|
||||
+ * certificate, needs to register here and supply the actual OCSP stapling
|
||||
+ * status data (OCSP_RESP) for a new connection.
|
||||
+ * A hook supplying the response data must return APR_SUCCESS.
|
||||
+ * The data is returned in DER encoded bytes via pder and pderlen. The
|
||||
+ * returned pointer may be NULL, which indicates that data is (currently)
|
||||
+ * unavailable.
|
||||
+ * If DER data is returned, it MUST come from a response with
|
||||
+ * status OCSP_RESPONSE_STATUS_SUCCESSFUL and V_OCSP_CERTSTATUS_GOOD
|
||||
+ * or V_OCSP_CERTSTATUS_REVOKED, not V_OCSP_CERTSTATUS_UNKNOWN. This means
|
||||
+ * errors in OCSP retrieval are to be handled/logged by the hook and
|
||||
+ * are not done by mod_ssl.
|
||||
+ * Any DER bytes returned MUST be allocated via malloc() and ownership
|
||||
+ * passes to mod_ssl. Meaning, the hook must return a malloced copy of
|
||||
+ * the data it has. mod_ssl (or OpenSSL) will free it.
|
||||
+ */
|
||||
+APR_DECLARE_EXTERNAL_HOOK(ssl, SSL, int, get_stapling_status,
|
||||
+ (unsigned char **pder, int *pderlen,
|
||||
+ conn_rec *c, server_rec *s, X509 *cert))
|
||||
+
|
||||
#endif /* __MOD_SSL_OPENSSL_H__ */
|
||||
/** @} */
|
||||
diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c
|
||||
index 21e41e2..ef631c1 100644
|
||||
--- a/modules/ssl/ssl_engine_init.c
|
||||
+++ b/modules/ssl/ssl_engine_init.c
|
||||
@@ -36,6 +36,25 @@ APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ssl, SSL, int, init_server,
|
||||
(server_rec *s,apr_pool_t *p,int is_proxy,SSL_CTX *ctx),
|
||||
(s,p,is_proxy,ctx), OK, DECLINED)
|
||||
|
||||
+APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ssl, SSL, int, add_cert_files,
|
||||
+ (server_rec *s, apr_pool_t *p,
|
||||
+ apr_array_header_t *cert_files, apr_array_header_t *key_files),
|
||||
+ (s, p, cert_files, key_files),
|
||||
+ OK, DECLINED)
|
||||
+
|
||||
+APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ssl, SSL, int, add_fallback_cert_files,
|
||||
+ (server_rec *s, apr_pool_t *p,
|
||||
+ apr_array_header_t *cert_files, apr_array_header_t *key_files),
|
||||
+ (s, p, cert_files, key_files),
|
||||
+ OK, DECLINED)
|
||||
+
|
||||
+APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ssl, SSL, int, answer_challenge,
|
||||
+ (conn_rec *c, const char *server_name,
|
||||
+ X509 **pcert, EVP_PKEY **pkey),
|
||||
+ (c, server_name, pcert, pkey),
|
||||
+ DECLINED, DECLINED)
|
||||
+
|
||||
+
|
||||
/* _________________________________________________________________
|
||||
**
|
||||
** Module Initialization
|
||||
@@ -165,18 +184,18 @@ static void ssl_add_version_components(apr_pool_t *p,
|
||||
modver, AP_SERVER_BASEVERSION, incver);
|
||||
}
|
||||
|
||||
-/**************************************************************************************************/
|
||||
-/* Managed Domains Interface */
|
||||
-
|
||||
-static APR_OPTIONAL_FN_TYPE(md_is_managed) *md_is_managed;
|
||||
-static APR_OPTIONAL_FN_TYPE(md_get_certificate) *md_get_certificate;
|
||||
-static APR_OPTIONAL_FN_TYPE(md_is_challenge) *md_is_challenge;
|
||||
+/* _________________________________________________________________
|
||||
+**
|
||||
+** Let other answer special connection attempts.
|
||||
+** Used in ACME challenge handling by mod_md.
|
||||
+** _________________________________________________________________
|
||||
+*/
|
||||
|
||||
int ssl_is_challenge(conn_rec *c, const char *servername,
|
||||
X509 **pcert, EVP_PKEY **pkey)
|
||||
{
|
||||
- if (md_is_challenge) {
|
||||
- return md_is_challenge(c, servername, pcert, pkey);
|
||||
+ if (APR_SUCCESS == ssl_run_answer_challenge(c, servername, pcert, pkey)) {
|
||||
+ return 1;
|
||||
}
|
||||
*pcert = NULL;
|
||||
*pkey = NULL;
|
||||
@@ -231,16 +250,6 @@ apr_status_t ssl_init_Module(apr_pool_t *p, apr_pool_t *plog,
|
||||
ssl_config_global_create(base_server); /* just to avoid problems */
|
||||
ssl_config_global_fix(mc);
|
||||
|
||||
- /* Initialize our interface to mod_md, if it is loaded
|
||||
- */
|
||||
- md_is_managed = APR_RETRIEVE_OPTIONAL_FN(md_is_managed);
|
||||
- md_get_certificate = APR_RETRIEVE_OPTIONAL_FN(md_get_certificate);
|
||||
- md_is_challenge = APR_RETRIEVE_OPTIONAL_FN(md_is_challenge);
|
||||
- if (!md_is_managed || !md_get_certificate) {
|
||||
- md_is_managed = NULL;
|
||||
- md_get_certificate = NULL;
|
||||
- }
|
||||
-
|
||||
/*
|
||||
* try to fix the configuration and open the dedicated SSL
|
||||
* logfile as early as possible
|
||||
@@ -1392,8 +1401,7 @@ static apr_status_t ssl_init_server_certs(server_rec *s,
|
||||
* loaded via SSLOpenSSLConfCmd Certificate), so for 1.0.2 and
|
||||
* later, we defer to the code in ssl_init_server_ctx.
|
||||
*/
|
||||
- if ((mctx->stapling_enabled == TRUE) &&
|
||||
- !ssl_stapling_init_cert(s, p, ptemp, mctx, cert)) {
|
||||
+ if (!ssl_stapling_init_cert(s, p, ptemp, mctx, cert)) {
|
||||
ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02567)
|
||||
"Unable to configure certificate %s for stapling",
|
||||
key_id);
|
||||
@@ -1788,11 +1796,13 @@ static apr_status_t ssl_init_server_ctx(server_rec *s,
|
||||
apr_array_header_t *pphrases)
|
||||
{
|
||||
apr_status_t rv;
|
||||
+ modssl_pk_server_t *pks;
|
||||
#ifdef HAVE_SSL_CONF_CMD
|
||||
ssl_ctx_param_t *param = (ssl_ctx_param_t *)sc->server->ssl_ctx_param->elts;
|
||||
SSL_CONF_CTX *cctx = sc->server->ssl_ctx_config;
|
||||
int i;
|
||||
#endif
|
||||
+ int n;
|
||||
|
||||
/*
|
||||
* Check for problematic re-initializations
|
||||
@@ -1804,50 +1814,24 @@ static apr_status_t ssl_init_server_ctx(server_rec *s,
|
||||
return APR_EGENERAL;
|
||||
}
|
||||
|
||||
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(10083)
|
||||
- "Init: (%s) mod_md support is %s.", ssl_util_vhostid(p, s),
|
||||
- md_is_managed? "available" : "unavailable");
|
||||
- if (md_is_managed && md_is_managed(s)) {
|
||||
- modssl_pk_server_t *const pks = sc->server->pks;
|
||||
- if (pks->cert_files->nelts > 0 || pks->key_files->nelts > 0) {
|
||||
- ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(10084)
|
||||
- "Init: (%s) You configured certificate/key files on this host, but "
|
||||
- "is is covered by a Managed Domain. You need to remove these directives "
|
||||
- "for the Managed Domain to take over.", ssl_util_vhostid(p, s));
|
||||
- }
|
||||
- else {
|
||||
- const char *key_file, *cert_file, *chain_file;
|
||||
-
|
||||
- key_file = cert_file = chain_file = NULL;
|
||||
-
|
||||
- if (md_get_certificate) {
|
||||
- rv = md_get_certificate(s, p, &key_file, &cert_file);
|
||||
- }
|
||||
- else {
|
||||
- rv = APR_ENOTIMPL;
|
||||
- }
|
||||
-
|
||||
- if (key_file && cert_file) {
|
||||
- ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, s,
|
||||
- "%s: installing key=%s, cert=%s, chain=%s",
|
||||
- ssl_util_vhostid(p, s), key_file, cert_file, chain_file);
|
||||
- APR_ARRAY_PUSH(pks->key_files, const char *) = key_file;
|
||||
- APR_ARRAY_PUSH(pks->cert_files, const char *) = cert_file;
|
||||
- sc->server->cert_chain = chain_file;
|
||||
- }
|
||||
-
|
||||
- if (APR_STATUS_IS_EAGAIN(rv)) {
|
||||
- /* Managed Domain not ready yet. This is not a reason to fail the config */
|
||||
- ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(10085)
|
||||
- "Init: %s will respond with '503 Service Unavailable' for now. This "
|
||||
- "host is part of a Managed Domain, but no SSL certificate is "
|
||||
- "available (yet).", ssl_util_vhostid(p, s));
|
||||
- pks->service_unavailable = 1;
|
||||
- }
|
||||
- else if (rv != APR_SUCCESS) {
|
||||
- return rv;
|
||||
- }
|
||||
- }
|
||||
+ /* Allow others to provide certificate files */
|
||||
+ pks = sc->server->pks;
|
||||
+ n = pks->cert_files->nelts;
|
||||
+ ssl_run_add_cert_files(s, p, pks->cert_files, pks->key_files);
|
||||
+
|
||||
+ if (n < pks->cert_files->nelts) {
|
||||
+ /* this overrides any old chain configuration */
|
||||
+ sc->server->cert_chain = NULL;
|
||||
+ }
|
||||
+
|
||||
+ if (apr_is_empty_array(pks->cert_files) && !sc->server->cert_chain) {
|
||||
+ ssl_run_add_fallback_cert_files(s, p, pks->cert_files, pks->key_files);
|
||||
+
|
||||
+ pks->service_unavailable = 1;
|
||||
+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(10085)
|
||||
+ "Init: %s will respond with '503 Service Unavailable' for now. There "
|
||||
+ "are no SSL certificates configured and no other module contributed any.",
|
||||
+ ssl_util_vhostid(p, s));
|
||||
}
|
||||
|
||||
if ((rv = ssl_init_ctx(s, p, ptemp, sc->server)) != APR_SUCCESS) {
|
||||
@@ -1900,7 +1884,7 @@ static apr_status_t ssl_init_server_ctx(server_rec *s,
|
||||
* (late) point makes sure that we catch both certificates loaded
|
||||
* via SSLCertificateFile and SSLOpenSSLConfCmd Certificate.
|
||||
*/
|
||||
- if (sc->server->stapling_enabled == TRUE) {
|
||||
+ do {
|
||||
X509 *cert;
|
||||
int i = 0;
|
||||
int ret = SSL_CTX_set_current_cert(sc->server->ssl_ctx,
|
||||
@@ -1917,7 +1901,7 @@ static apr_status_t ssl_init_server_ctx(server_rec *s,
|
||||
SSL_CERT_SET_NEXT);
|
||||
i++;
|
||||
}
|
||||
- }
|
||||
+ } while(0);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TLS_SESSION_TICKETS
|
||||
diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c
|
||||
index e6a9f67..a5e86e4 100644
|
||||
--- a/modules/ssl/ssl_engine_kernel.c
|
||||
+++ b/modules/ssl/ssl_engine_kernel.c
|
||||
@@ -2303,6 +2303,37 @@ void ssl_callback_Info(const SSL *ssl, int where, int rc)
|
||||
}
|
||||
|
||||
#ifdef HAVE_TLSEXT
|
||||
+
|
||||
+static apr_status_t set_challenge_creds(conn_rec *c, const char *servername,
|
||||
+ SSL *ssl, X509 *cert, EVP_PKEY *key)
|
||||
+{
|
||||
+ SSLConnRec *sslcon = myConnConfig(c);
|
||||
+
|
||||
+ sslcon->service_unavailable = 1;
|
||||
+ if ((SSL_use_certificate(ssl, cert) < 1)) {
|
||||
+ ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, c, APLOGNO(10086)
|
||||
+ "Failed to configure challenge certificate %s",
|
||||
+ servername);
|
||||
+ return APR_EGENERAL;
|
||||
+ }
|
||||
+
|
||||
+ if (!SSL_use_PrivateKey(ssl, key)) {
|
||||
+ ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, c, APLOGNO(10087)
|
||||
+ "error '%s' using Challenge key: %s",
|
||||
+ ERR_error_string(ERR_peek_last_error(), NULL),
|
||||
+ servername);
|
||||
+ return APR_EGENERAL;
|
||||
+ }
|
||||
+
|
||||
+ if (SSL_check_private_key(ssl) < 1) {
|
||||
+ ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, c, APLOGNO(10088)
|
||||
+ "Challenge certificate and private key %s "
|
||||
+ "do not match", servername);
|
||||
+ return APR_EGENERAL;
|
||||
+ }
|
||||
+ return APR_SUCCESS;
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* This function sets the virtual host from an extended
|
||||
* client hello with a server name indication extension ("SNI", cf. RFC 6066).
|
||||
@@ -2332,30 +2363,12 @@ static apr_status_t init_vhost(conn_rec *c, SSL *ssl)
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
else if (ssl_is_challenge(c, servername, &cert, &key)) {
|
||||
-
|
||||
- sslcon->service_unavailable = 1;
|
||||
- if ((SSL_use_certificate(ssl, cert) < 1)) {
|
||||
- ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, c, APLOGNO(10086)
|
||||
- "Failed to configure challenge certificate %s",
|
||||
- servername);
|
||||
+ /* With ACMEv1 we can have challenge connections to a unknown domains
|
||||
+ * that need to be answered with a special certificate and will
|
||||
+ * otherwise not answer any requests. */
|
||||
+ if (set_challenge_creds(c, servername, ssl, cert, key) != APR_SUCCESS) {
|
||||
return APR_EGENERAL;
|
||||
}
|
||||
-
|
||||
- if (!SSL_use_PrivateKey(ssl, key)) {
|
||||
- ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, c, APLOGNO(10087)
|
||||
- "error '%s' using Challenge key: %s",
|
||||
- ERR_error_string(ERR_peek_last_error(), NULL),
|
||||
- servername);
|
||||
- return APR_EGENERAL;
|
||||
- }
|
||||
-
|
||||
- if (SSL_check_private_key(ssl) < 1) {
|
||||
- ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, c, APLOGNO(10088)
|
||||
- "Challenge certificate and private key %s "
|
||||
- "do not match", servername);
|
||||
- return APR_EGENERAL;
|
||||
- }
|
||||
-
|
||||
}
|
||||
else {
|
||||
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(02044)
|
||||
@@ -2648,6 +2661,23 @@ int ssl_callback_alpn_select(SSL *ssl,
|
||||
proposed);
|
||||
return SSL_TLSEXT_ERR_ALERT_FATAL;
|
||||
}
|
||||
+
|
||||
+ /* protocol was switched, this could be a challenge protocol such as "acme-tls/1".
|
||||
+ * For that to work, we need to allow overrides to our ssl certificate.
|
||||
+ * However, exclude challenge checks on our best known traffic protocol.
|
||||
+ * (http/1.1 is the default, we never switch to it anyway.)
|
||||
+ */
|
||||
+ if (strcmp("h2", proposed)) {
|
||||
+ const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
|
||||
+ X509 *cert;
|
||||
+ EVP_PKEY *key;
|
||||
+
|
||||
+ if (ssl_is_challenge(c, servername, &cert, &key)) {
|
||||
+ if (set_challenge_creds(c, servername, ssl, cert, key) != APR_SUCCESS) {
|
||||
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
diff --git a/modules/ssl/ssl_util_stapling.c b/modules/ssl/ssl_util_stapling.c
|
||||
index c3e2cfa..4df0a9a 100644
|
||||
--- a/modules/ssl/ssl_util_stapling.c
|
||||
+++ b/modules/ssl/ssl_util_stapling.c
|
||||
@@ -31,12 +31,28 @@
|
||||
#include "ssl_private.h"
|
||||
#include "ap_mpm.h"
|
||||
#include "apr_thread_mutex.h"
|
||||
+#include "mod_ssl_openssl.h"
|
||||
+
|
||||
+APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ssl, SSL, int, init_stapling_status,
|
||||
+ (server_rec *s, apr_pool_t *p,
|
||||
+ X509 *cert, X509 *issuer),
|
||||
+ (s, p, cert, issuer),
|
||||
+ DECLINED, DECLINED)
|
||||
+
|
||||
+APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ssl, SSL, int, get_stapling_status,
|
||||
+ (unsigned char **pder, int *pderlen,
|
||||
+ conn_rec *c, server_rec *s, X509 *cert),
|
||||
+ (pder, pderlen, c, s, cert),
|
||||
+ DECLINED, DECLINED)
|
||||
+
|
||||
|
||||
#ifdef HAVE_OCSP_STAPLING
|
||||
|
||||
static int stapling_cache_mutex_on(server_rec *s);
|
||||
static int stapling_cache_mutex_off(server_rec *s);
|
||||
|
||||
+static int stapling_cb(SSL *ssl, void *arg);
|
||||
+
|
||||
/**
|
||||
* Maxiumum OCSP stapling response size. This should be the response for a
|
||||
* single certificate and will typically include the responder certificate chain
|
||||
@@ -119,7 +135,38 @@ int ssl_stapling_init_cert(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp,
|
||||
OCSP_CERTID *cid = NULL;
|
||||
STACK_OF(OPENSSL_STRING) *aia = NULL;
|
||||
|
||||
- if ((x == NULL) || (X509_digest(x, EVP_sha1(), idx, NULL) != 1))
|
||||
+ if (x == NULL)
|
||||
+ return 0;
|
||||
+
|
||||
+ if (!(issuer = stapling_get_issuer(mctx, x))) {
|
||||
+ /* In Apache pre 2.4.40, we use to come here only when mod_ssl stapling
|
||||
+ * was enabled. With the new hooks, we give other modules the chance
|
||||
+ * to provide stapling status. However, we do not want to log ssl errors
|
||||
+ * where we did not do so in the past. */
|
||||
+ if (mctx->stapling_enabled == TRUE) {
|
||||
+ ssl_log_xerror(SSLLOG_MARK, APLOG_ERR, 0, ptemp, s, x, APLOGNO(02217)
|
||||
+ "ssl_stapling_init_cert: can't retrieve issuer "
|
||||
+ "certificate!");
|
||||
+ return 0;
|
||||
+ }
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ if (ssl_run_init_stapling_status(s, p, x, issuer) == APR_SUCCESS) {
|
||||
+ /* Someone's taken over or mod_ssl's own implementation is not enabled */
|
||||
+ if (mctx->stapling_enabled != TRUE) {
|
||||
+ SSL_CTX_set_tlsext_status_cb(mctx->ssl_ctx, stapling_cb);
|
||||
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO() "OCSP stapling added via hook");
|
||||
+ }
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ if (mctx->stapling_enabled != TRUE) {
|
||||
+ /* mod_ssl's own implementation is not enabled */
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ if (X509_digest(x, EVP_sha1(), idx, NULL) != 1)
|
||||
return 0;
|
||||
|
||||
cinf = apr_hash_get(stapling_certinfo, idx, sizeof(idx));
|
||||
@@ -139,13 +186,6 @@ int ssl_stapling_init_cert(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp,
|
||||
return 1;
|
||||
}
|
||||
|
||||
- if (!(issuer = stapling_get_issuer(mctx, x))) {
|
||||
- ssl_log_xerror(SSLLOG_MARK, APLOG_ERR, 0, ptemp, s, x, APLOGNO(02217)
|
||||
- "ssl_stapling_init_cert: can't retrieve issuer "
|
||||
- "certificate!");
|
||||
- return 0;
|
||||
- }
|
||||
-
|
||||
cid = OCSP_cert_to_id(NULL, x, issuer);
|
||||
X509_free(issuer);
|
||||
if (!cid) {
|
||||
@@ -182,18 +222,16 @@ int ssl_stapling_init_cert(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp,
|
||||
mctx->sc->vhost_id);
|
||||
|
||||
apr_hash_set(stapling_certinfo, cinf->idx, sizeof(cinf->idx), cinf);
|
||||
-
|
||||
+
|
||||
return 1;
|
||||
}
|
||||
|
||||
-static certinfo *stapling_get_certinfo(server_rec *s, modssl_ctx_t *mctx,
|
||||
+static certinfo *stapling_get_certinfo(server_rec *s, X509 *x, modssl_ctx_t *mctx,
|
||||
SSL *ssl)
|
||||
{
|
||||
certinfo *cinf;
|
||||
- X509 *x;
|
||||
UCHAR idx[SHA_DIGEST_LENGTH];
|
||||
- x = SSL_get_certificate(ssl);
|
||||
- if ((x == NULL) || (X509_digest(x, EVP_sha1(), idx, NULL) != 1))
|
||||
+ if (X509_digest(x, EVP_sha1(), idx, NULL) != 1)
|
||||
return NULL;
|
||||
cinf = apr_hash_get(stapling_certinfo, idx, sizeof(idx));
|
||||
if (cinf && cinf->cid)
|
||||
@@ -750,18 +788,34 @@ static int stapling_cb(SSL *ssl, void *arg)
|
||||
OCSP_RESPONSE *rsp = NULL;
|
||||
int rv;
|
||||
BOOL ok = TRUE;
|
||||
+ X509 *x;
|
||||
+ unsigned char *rspder = NULL;
|
||||
+ int rspderlen;
|
||||
|
||||
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01951)
|
||||
+ "stapling_cb: OCSP Stapling callback called");
|
||||
+
|
||||
+ x = SSL_get_certificate(ssl);
|
||||
+ if (x == NULL) {
|
||||
+ return SSL_TLSEXT_ERR_NOACK;
|
||||
+ }
|
||||
+
|
||||
+ if (ssl_run_get_stapling_status(&rspder, &rspderlen, conn, s, x) == APR_SUCCESS) {
|
||||
+ /* a hook handles stapling for this certicate and determines the response */
|
||||
+ if (rspder == NULL || rspderlen <= 0) {
|
||||
+ return SSL_TLSEXT_ERR_NOACK;
|
||||
+ }
|
||||
+ SSL_set_tlsext_status_ocsp_resp(ssl, rspder, rspderlen);
|
||||
+ return SSL_TLSEXT_ERR_OK;
|
||||
+ }
|
||||
+
|
||||
if (sc->server->stapling_enabled != TRUE) {
|
||||
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01950)
|
||||
"stapling_cb: OCSP Stapling disabled");
|
||||
return SSL_TLSEXT_ERR_NOACK;
|
||||
}
|
||||
|
||||
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01951)
|
||||
- "stapling_cb: OCSP Stapling callback called");
|
||||
-
|
||||
- cinf = stapling_get_certinfo(s, mctx, ssl);
|
||||
- if (cinf == NULL) {
|
||||
+ if ((cinf = stapling_get_certinfo(s, x, mctx, ssl)) == NULL) {
|
||||
return SSL_TLSEXT_ERR_NOACK;
|
||||
}
|
||||
|
||||
@@ -864,9 +918,10 @@ apr_status_t modssl_init_stapling(server_rec *s, apr_pool_t *p,
|
||||
if (mctx->stapling_responder_timeout == UNSET) {
|
||||
mctx->stapling_responder_timeout = 10 * APR_USEC_PER_SEC;
|
||||
}
|
||||
+
|
||||
SSL_CTX_set_tlsext_status_cb(ctx, stapling_cb);
|
||||
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01960) "OCSP stapling initialized");
|
||||
-
|
||||
+
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
@ -1,44 +0,0 @@
|
||||
diff --git a/modules/md/mod_md_os.c b/modules/md/mod_md_os.c
|
||||
index f96d566..8df0248 100644
|
||||
--- a/modules/md/mod_md_os.c
|
||||
+++ b/modules/md/mod_md_os.c
|
||||
@@ -41,14 +41,20 @@
|
||||
|
||||
apr_status_t md_try_chown(const char *fname, unsigned int uid, int gid, apr_pool_t *p)
|
||||
{
|
||||
-#if AP_NEED_SET_MUTEX_PERMS
|
||||
- if (-1 == chown(fname, (uid_t)uid, (gid_t)gid)) {
|
||||
- apr_status_t rv = APR_FROM_OS_ERROR(errno);
|
||||
- if (!APR_STATUS_IS_ENOENT(rv)) {
|
||||
- ap_log_perror(APLOG_MARK, APLOG_ERR, rv, p, APLOGNO(10082)
|
||||
- "Can't change owner of %s", fname);
|
||||
+#if AP_NEED_SET_MUTEX_PERMS && HAVE_UNISTD_H
|
||||
+ /* Since we only switch user when running as root, we only need to chown directories
|
||||
+ * in that case. Otherwise, the server will ignore any "user/group" directives and
|
||||
+ * child processes have the same privileges as the parent.
|
||||
+ */
|
||||
+ if (!geteuid()) {
|
||||
+ if (-1 == chown(fname, (uid_t)uid, (gid_t)gid)) {
|
||||
+ apr_status_t rv = APR_FROM_OS_ERROR(errno);
|
||||
+ if (!APR_STATUS_IS_ENOENT(rv)) {
|
||||
+ ap_log_perror(APLOG_MARK, APLOG_ERR, rv, p, APLOGNO(10082)
|
||||
+ "Can't change owner of %s", fname);
|
||||
+ }
|
||||
+ return rv;
|
||||
}
|
||||
- return rv;
|
||||
}
|
||||
return APR_SUCCESS;
|
||||
#else
|
||||
@@ -58,11 +64,7 @@ apr_status_t md_try_chown(const char *fname, unsigned int uid, int gid, apr_pool
|
||||
|
||||
apr_status_t md_make_worker_accessible(const char *fname, apr_pool_t *p)
|
||||
{
|
||||
-#if AP_NEED_SET_MUTEX_PERMS
|
||||
return md_try_chown(fname, ap_unixd_config.user_id, -1, p);
|
||||
-#else
|
||||
- return APR_ENOTIMPL;
|
||||
-#endif
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
@ -1,24 +0,0 @@
|
||||
diff --git a/docs/conf/magic b/docs/conf/magic
|
||||
index 7c56119..bc891d9 100644
|
||||
--- a/docs/conf/magic
|
||||
+++ b/docs/conf/magic
|
||||
@@ -87,7 +87,7 @@
|
||||
# Microsoft WAVE format (*.wav)
|
||||
# [GRR 950115: probably all of the shorts and longs should be leshort/lelong]
|
||||
# Microsoft RIFF
|
||||
-0 string RIFF audio/unknown
|
||||
+0 string RIFF
|
||||
# - WAVE format
|
||||
>8 string WAVE audio/x-wav
|
||||
# MPEG audio.
|
||||
--- a/modules/metadata/mod_mime_magic.c 2013/06/11 07:36:13 1491699
|
||||
+++ b/modules/metadata/mod_mime_magic.c 2013/06/11 07:41:40 1491700
|
||||
@@ -606,7 +606,7 @@
|
||||
/* high overhead for 1 char - just hope they don't do this much */
|
||||
str[0] = c;
|
||||
str[1] = '\0';
|
||||
- return magic_rsl_add(r, str);
|
||||
+ return magic_rsl_add(r, apr_pstrdup(r->pool, str));
|
||||
}
|
||||
|
||||
/* allocate and copy a contiguous string from a result string list */
|
File diff suppressed because it is too large
Load Diff
@ -1,35 +0,0 @@
|
||||
diff --git a/modules/arch/unix/mod_systemd.c b/modules/arch/unix/mod_systemd.c
|
||||
index 7a82a90..6c244b6 100644
|
||||
--- a/modules/arch/unix/mod_systemd.c
|
||||
+++ b/modules/arch/unix/mod_systemd.c
|
||||
@@ -100,6 +100,21 @@ static int systemd_post_config(apr_pool_t *pconf, apr_pool_t *plog,
|
||||
return OK;
|
||||
}
|
||||
|
||||
+/* Report the service is ready in post_config, which could be during
|
||||
+ * startup or after a reload. The server could still hit a fatal
|
||||
+ * startup error after this point during ap_run_mpm(), so this is
|
||||
+ * perhaps too early, but by post_config listen() has been called on
|
||||
+ * the TCP ports so new connections will not be rejected. There will
|
||||
+ * always be a possible async failure event simultaneous to the
|
||||
+ * service reporting "ready", so this should be good enough. */
|
||||
+static int systemd_post_config_last(apr_pool_t *p, apr_pool_t *plog,
|
||||
+ apr_pool_t *ptemp, server_rec *main_server)
|
||||
+{
|
||||
+ sd_notify(0, "READY=1\n"
|
||||
+ "STATUS=Configuration loaded.\n");
|
||||
+ return OK;
|
||||
+}
|
||||
+
|
||||
static int systemd_pre_mpm(apr_pool_t *p, ap_scoreboard_e sb_type)
|
||||
{
|
||||
int rv;
|
||||
@@ -187,6 +202,8 @@ static void systemd_register_hooks(apr_pool_t *p)
|
||||
ap_hook_pre_config(systemd_pre_config, NULL, NULL, APR_HOOK_LAST);
|
||||
/* Grab the listener config. */
|
||||
ap_hook_post_config(systemd_post_config, NULL, NULL, APR_HOOK_LAST);
|
||||
+ /* Signal service is ready. */
|
||||
+ ap_hook_post_config(systemd_post_config_last, NULL, NULL, APR_HOOK_REALLY_LAST);
|
||||
/* We know the PID in this hook ... */
|
||||
ap_hook_pre_mpm(systemd_pre_mpm, NULL, NULL, APR_HOOK_LAST);
|
||||
/* Used to update httpd's status line using sd_notifyf */
|
@ -1,48 +0,0 @@
|
||||
diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c
|
||||
index 70d151e..e4f5fc8 100644
|
||||
--- a/modules/ssl/ssl_engine_init.c
|
||||
+++ b/modules/ssl/ssl_engine_init.c
|
||||
@@ -1095,7 +1095,9 @@ static apr_status_t ssl_init_ctx_crl(server_rec *s,
|
||||
/*
|
||||
* Read a file that optionally contains the server certificate in PEM
|
||||
* format, possibly followed by a sequence of CA certificates that
|
||||
- * should be sent to the peer in the SSL Certificate message.
|
||||
+ * should be sent to the peer in the SSL Certificate message. Returns
|
||||
+ * 0 on success, otherwise the OpenSSL error stack contents should be
|
||||
+ * reported.
|
||||
*/
|
||||
static int use_certificate_chain(
|
||||
SSL_CTX *ctx, char *file, int skipfirst, pem_password_cb *cb)
|
||||
@@ -1128,8 +1130,10 @@ static int use_certificate_chain(
|
||||
ctx->extra_certs = NULL;
|
||||
}
|
||||
#endif
|
||||
+
|
||||
/* create new extra chain by loading the certs */
|
||||
n = 0;
|
||||
+ ERR_clear_error();
|
||||
while ((x509 = PEM_read_bio_X509(bio, NULL, cb, NULL)) != NULL) {
|
||||
if (!SSL_CTX_add_extra_chain_cert(ctx, x509)) {
|
||||
X509_free(x509);
|
||||
@@ -1190,6 +1194,7 @@ static apr_status_t ssl_init_ctx_cert_chain(server_rec *s,
|
||||
if (n < 0) {
|
||||
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01903)
|
||||
"Failed to configure CA certificate chain!");
|
||||
+ ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
|
||||
return ssl_die(s);
|
||||
}
|
||||
|
||||
diff --git a/modules/ssl/ssl_util_ocsp.c b/modules/ssl/ssl_util_ocsp.c
|
||||
index b11a6e9..b66e151 100644
|
||||
--- a/modules/ssl/ssl_util_ocsp.c
|
||||
+++ b/modules/ssl/ssl_util_ocsp.c
|
||||
@@ -363,7 +363,9 @@ static STACK_OF(X509) *modssl_read_ocsp_certificates(const char *file)
|
||||
BIO_free(bio);
|
||||
return NULL;
|
||||
}
|
||||
+
|
||||
/* create new extra chain by loading the certs */
|
||||
+ ERR_clear_error();
|
||||
while ((x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) {
|
||||
if (!other_certs) {
|
||||
other_certs = sk_X509_new_null();
|
@ -1,44 +0,0 @@
|
||||
diff --git a/modules/ssl/ssl_engine_io.c b/modules/ssl/ssl_engine_io.c
|
||||
index 0958135..018b667 100644
|
||||
--- a/modules/ssl/ssl_engine_io.c
|
||||
+++ b/modules/ssl/ssl_engine_io.c
|
||||
@@ -200,6 +200,8 @@ static int bio_filter_out_write(BIO *bio, const char *in, int inl)
|
||||
apr_bucket *e;
|
||||
int need_flush;
|
||||
|
||||
+ BIO_clear_retry_flags(bio);
|
||||
+
|
||||
#ifndef SSL_OP_NO_RENEGOTIATION
|
||||
/* Abort early if the client has initiated a renegotiation. */
|
||||
if (outctx->filter_ctx->config->reneg_state == RENEG_ABORT) {
|
||||
@@ -208,12 +210,6 @@ static int bio_filter_out_write(BIO *bio, const char *in, int inl)
|
||||
}
|
||||
#endif
|
||||
|
||||
- /* when handshaking we'll have a small number of bytes.
|
||||
- * max size SSL will pass us here is about 16k.
|
||||
- * (16413 bytes to be exact)
|
||||
- */
|
||||
- BIO_clear_retry_flags(bio);
|
||||
-
|
||||
/* Use a transient bucket for the output data - any downstream
|
||||
* filter must setaside if necessary. */
|
||||
e = apr_bucket_transient_create(in, inl, outctx->bb->bucket_alloc);
|
||||
@@ -460,6 +456,8 @@ static int bio_filter_in_read(BIO *bio, char *in, int inlen)
|
||||
if (!in)
|
||||
return 0;
|
||||
|
||||
+ BIO_clear_retry_flags(bio);
|
||||
+
|
||||
#ifndef SSL_OP_NO_RENEGOTIATION
|
||||
/* Abort early if the client has initiated a renegotiation. */
|
||||
if (inctx->filter_ctx->config->reneg_state == RENEG_ABORT) {
|
||||
@@ -468,8 +466,6 @@ static int bio_filter_in_read(BIO *bio, char *in, int inlen)
|
||||
}
|
||||
#endif
|
||||
|
||||
- BIO_clear_retry_flags(bio);
|
||||
-
|
||||
if (!inctx->bb) {
|
||||
inctx->rc = APR_EOF;
|
||||
return -1;
|
@ -1,209 +0,0 @@
|
||||
diff --git a/configure.in b/configure.in
|
||||
index de6a8ad..4ca489d 100644
|
||||
--- a/configure.in
|
||||
+++ b/configure.in
|
||||
@@ -465,6 +465,28 @@ LIBS=""
|
||||
AC_SEARCH_LIBS(crypt, crypt)
|
||||
CRYPT_LIBS="$LIBS"
|
||||
APACHE_SUBST(CRYPT_LIBS)
|
||||
+
|
||||
+if test "$ac_cv_search_crypt" != "no"; then
|
||||
+ # Test crypt() with the SHA-512 test vector from https://akkadia.org/drepper/SHA-crypt.txt
|
||||
+ AC_CACHE_CHECK([whether crypt() supports SHA-2], [ap_cv_crypt_sha2], [
|
||||
+ AC_RUN_IFELSE([AC_LANG_PROGRAM([[
|
||||
+#include <crypt.h>
|
||||
+#include <stdlib.h>
|
||||
+#include <string.h>
|
||||
+
|
||||
+#define PASSWD_0 "Hello world!"
|
||||
+#define SALT_0 "\$6\$saltstring"
|
||||
+#define EXPECT_0 "\$6\$saltstring\$svn8UoSVapNtMuq1ukKS4tPQd8iKwSMHWjl/O817G3uBnIFNjnQJu" \
|
||||
+ "esI68u4OTLiBFdcbYEdFCoEOfaS35inz1"
|
||||
+]], [char *result = crypt(PASSWD_0, SALT_0);
|
||||
+ if (!result) return 1;
|
||||
+ if (strcmp(result, EXPECT_0)) return 2;
|
||||
+])], [ap_cv_crypt_sha2=yes], [ap_cv_crypt_sha2=no])])
|
||||
+ if test "$ap_cv_crypt_sha2" = yes; then
|
||||
+ AC_DEFINE([HAVE_CRYPT_SHA2], 1, [Define if crypt() supports SHA-2 hashes])
|
||||
+ fi
|
||||
+fi
|
||||
+
|
||||
LIBS="$saved_LIBS"
|
||||
|
||||
dnl See Comment #Spoon
|
||||
diff --git a/support/htpasswd.c b/support/htpasswd.c
|
||||
index 660a27c..136f62a 100644
|
||||
--- a/support/htpasswd.c
|
||||
+++ b/support/htpasswd.c
|
||||
@@ -98,28 +98,32 @@ static int mkrecord(struct passwd_ctx *ctx, char *user)
|
||||
static void usage(void)
|
||||
{
|
||||
apr_file_printf(errfile, "Usage:" NL
|
||||
- "\thtpasswd [-cimBdpsDv] [-C cost] passwordfile username" NL
|
||||
- "\thtpasswd -b[cmBdpsDv] [-C cost] passwordfile username password" NL
|
||||
+ "\thtpasswd [-cimB25dpsDv] [-C cost] [-r rounds] passwordfile username" NL
|
||||
+ "\thtpasswd -b[cmB25dpsDv] [-C cost] [-r rounds] passwordfile username password" NL
|
||||
NL
|
||||
- "\thtpasswd -n[imBdps] [-C cost] username" NL
|
||||
- "\thtpasswd -nb[mBdps] [-C cost] username password" NL
|
||||
+ "\thtpasswd -n[imB25dps] [-C cost] [-r rounds] username" NL
|
||||
+ "\thtpasswd -nb[mB25dps] [-C cost] [-r rounds] username password" NL
|
||||
" -c Create a new file." NL
|
||||
" -n Don't update file; display results on stdout." NL
|
||||
" -b Use the password from the command line rather than prompting "
|
||||
"for it." NL
|
||||
" -i Read password from stdin without verification (for script usage)." NL
|
||||
" -m Force MD5 encryption of the password (default)." NL
|
||||
- " -B Force bcrypt encryption of the password (very secure)." NL
|
||||
+ " -2 Force SHA-256 crypt() hash of the password (secure)." NL
|
||||
+ " -5 Force SHA-512 crypt() hash of the password (secure)." NL
|
||||
+ " -B Force bcrypt encryption of the password (very secure)." NL
|
||||
" -C Set the computing time used for the bcrypt algorithm" NL
|
||||
" (higher is more secure but slower, default: %d, valid: 4 to 31)." NL
|
||||
+ " -r Set the number of rounds used for the SHA-256, SHA-512 algorithms" NL
|
||||
+ " (higher is more secure but slower, default: 5000)." NL
|
||||
" -d Force CRYPT encryption of the password (8 chars max, insecure)." NL
|
||||
- " -s Force SHA encryption of the password (insecure)." NL
|
||||
+ " -s Force SHA-1 encryption of the password (insecure)." NL
|
||||
" -p Do not encrypt the password (plaintext, insecure)." NL
|
||||
" -D Delete the specified user." NL
|
||||
" -v Verify password for the specified user." NL
|
||||
"On other systems than Windows and NetWare the '-p' flag will "
|
||||
"probably not work." NL
|
||||
- "The SHA algorithm does not use a salt and is less secure than the "
|
||||
+ "The SHA-1 algorithm does not use a salt and is less secure than the "
|
||||
"MD5 algorithm." NL,
|
||||
BCRYPT_DEFAULT_COST
|
||||
);
|
||||
@@ -178,7 +182,7 @@ static void check_args(int argc, const char *const argv[],
|
||||
if (rv != APR_SUCCESS)
|
||||
exit(ERR_SYNTAX);
|
||||
|
||||
- while ((rv = apr_getopt(state, "cnmspdBbDiC:v", &opt, &opt_arg)) == APR_SUCCESS) {
|
||||
+ while ((rv = apr_getopt(state, "cnmspdBbDi25C:r:v", &opt, &opt_arg)) == APR_SUCCESS) {
|
||||
switch (opt) {
|
||||
case 'c':
|
||||
*mask |= APHTP_NEWFILE;
|
||||
diff --git a/support/passwd_common.c b/support/passwd_common.c
|
||||
index 664e509..d45657c 100644
|
||||
--- a/support/passwd_common.c
|
||||
+++ b/support/passwd_common.c
|
||||
@@ -185,10 +185,15 @@ int mkhash(struct passwd_ctx *ctx)
|
||||
#if CRYPT_ALGO_SUPPORTED
|
||||
char *cbuf;
|
||||
#endif
|
||||
+#ifdef HAVE_CRYPT_SHA2
|
||||
+ const char *setting;
|
||||
+ char method;
|
||||
+#endif
|
||||
|
||||
- if (ctx->cost != 0 && ctx->alg != ALG_BCRYPT) {
|
||||
+ if (ctx->cost != 0 && ctx->alg != ALG_BCRYPT
|
||||
+ && ctx->alg != ALG_CRYPT_SHA256 && ctx->alg != ALG_CRYPT_SHA512 ) {
|
||||
apr_file_printf(errfile,
|
||||
- "Warning: Ignoring -C argument for this algorithm." NL);
|
||||
+ "Warning: Ignoring -C/-r argument for this algorithm." NL);
|
||||
}
|
||||
|
||||
if (ctx->passwd == NULL) {
|
||||
@@ -246,6 +251,34 @@ int mkhash(struct passwd_ctx *ctx)
|
||||
break;
|
||||
#endif /* CRYPT_ALGO_SUPPORTED */
|
||||
|
||||
+#ifdef HAVE_CRYPT_SHA2
|
||||
+ case ALG_CRYPT_SHA256:
|
||||
+ case ALG_CRYPT_SHA512:
|
||||
+ ret = generate_salt(salt, 16, &ctx->errstr, ctx->pool);
|
||||
+ if (ret != 0)
|
||||
+ break;
|
||||
+
|
||||
+ method = ctx->alg == ALG_CRYPT_SHA256 ? '5': '6';
|
||||
+
|
||||
+ if (ctx->cost)
|
||||
+ setting = apr_psprintf(ctx->pool, "$%c$rounds=%d$%s",
|
||||
+ method, ctx->cost, salt);
|
||||
+ else
|
||||
+ setting = apr_psprintf(ctx->pool, "$%c$%s",
|
||||
+ method, salt);
|
||||
+
|
||||
+ cbuf = crypt(pw, setting);
|
||||
+ if (cbuf == NULL) {
|
||||
+ rv = APR_FROM_OS_ERROR(errno);
|
||||
+ ctx->errstr = apr_psprintf(ctx->pool, "crypt() failed: %pm", &rv);
|
||||
+ ret = ERR_PWMISMATCH;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ apr_cpystrn(ctx->out, cbuf, ctx->out_len - 1);
|
||||
+ break;
|
||||
+#endif /* HAVE_CRYPT_SHA2 */
|
||||
+
|
||||
#if BCRYPT_ALGO_SUPPORTED
|
||||
case ALG_BCRYPT:
|
||||
rv = apr_generate_random_bytes((unsigned char*)salt, 16);
|
||||
@@ -294,6 +327,19 @@ int parse_common_options(struct passwd_ctx *ctx, char opt,
|
||||
case 's':
|
||||
ctx->alg = ALG_APSHA;
|
||||
break;
|
||||
+#ifdef HAVE_CRYPT_SHA2
|
||||
+ case '2':
|
||||
+ ctx->alg = ALG_CRYPT_SHA256;
|
||||
+ break;
|
||||
+ case '5':
|
||||
+ ctx->alg = ALG_CRYPT_SHA512;
|
||||
+ break;
|
||||
+#else
|
||||
+ case '2':
|
||||
+ case '5':
|
||||
+ ctx->errstr = "SHA-2 crypt() algorithms are not supported on this platform.";
|
||||
+ return ERR_ALG_NOT_SUPP;
|
||||
+#endif
|
||||
case 'p':
|
||||
ctx->alg = ALG_PLAIN;
|
||||
#if !PLAIN_ALGO_SUPPORTED
|
||||
@@ -324,11 +370,12 @@ int parse_common_options(struct passwd_ctx *ctx, char opt,
|
||||
return ERR_ALG_NOT_SUPP;
|
||||
#endif
|
||||
break;
|
||||
- case 'C': {
|
||||
+ case 'C':
|
||||
+ case 'r': {
|
||||
char *endptr;
|
||||
long num = strtol(opt_arg, &endptr, 10);
|
||||
if (*endptr != '\0' || num <= 0) {
|
||||
- ctx->errstr = "argument to -C must be a positive integer";
|
||||
+ ctx->errstr = "argument to -C/-r must be a positive integer";
|
||||
return ERR_SYNTAX;
|
||||
}
|
||||
ctx->cost = num;
|
||||
diff --git a/support/passwd_common.h b/support/passwd_common.h
|
||||
index 660081e..f1b3cd7 100644
|
||||
--- a/support/passwd_common.h
|
||||
+++ b/support/passwd_common.h
|
||||
@@ -28,6 +28,8 @@
|
||||
#include "apu_version.h"
|
||||
#endif
|
||||
|
||||
+#include "ap_config_auto.h"
|
||||
+
|
||||
#define MAX_STRING_LEN 256
|
||||
|
||||
#define ALG_PLAIN 0
|
||||
@@ -35,6 +37,8 @@
|
||||
#define ALG_APMD5 2
|
||||
#define ALG_APSHA 3
|
||||
#define ALG_BCRYPT 4
|
||||
+#define ALG_CRYPT_SHA256 5
|
||||
+#define ALG_CRYPT_SHA512 6
|
||||
|
||||
#define BCRYPT_DEFAULT_COST 5
|
||||
|
||||
@@ -84,7 +88,7 @@ struct passwd_ctx {
|
||||
apr_size_t out_len;
|
||||
char *passwd;
|
||||
int alg;
|
||||
- int cost;
|
||||
+ int cost; /* cost for bcrypt, rounds for SHA-2 */
|
||||
enum {
|
||||
PW_PROMPT = 0,
|
||||
PW_ARG,
|
@ -1,108 +0,0 @@
|
||||
--- a/modules/dav/main/mod_dav.c
|
||||
+++ b/modules/dav/main/mod_dav.c
|
||||
@@ -557,6 +557,7 @@
|
||||
dav_begin_multistatus(bb, r, status, namespaces);
|
||||
|
||||
apr_pool_create(&subpool, r->pool);
|
||||
+ apr_pool_tag(subpool, "mod_dav-multistatus");
|
||||
|
||||
for (; first != NULL; first = first->next) {
|
||||
apr_pool_clear(subpool);
|
||||
@@ -1980,8 +1981,9 @@
|
||||
** Note: we cast to lose the "const". The propdb won't try to change
|
||||
** the resource, however, since we are opening readonly.
|
||||
*/
|
||||
- err = dav_open_propdb(ctx->r, ctx->w.lockdb, wres->resource, 1,
|
||||
- ctx->doc ? ctx->doc->namespaces : NULL, &propdb);
|
||||
+ err = dav_popen_propdb(ctx->scratchpool,
|
||||
+ ctx->r, ctx->w.lockdb, wres->resource, 1,
|
||||
+ ctx->doc ? ctx->doc->namespaces : NULL, &propdb);
|
||||
if (err != NULL) {
|
||||
/* ### do something with err! */
|
||||
|
||||
--- a/modules/dav/main/mod_dav.h
|
||||
+++ b/modules/dav/main/mod_dav.h
|
||||
@@ -1590,6 +1590,16 @@
|
||||
apr_array_header_t *ns_xlate,
|
||||
dav_propdb **propdb);
|
||||
|
||||
+DAV_DECLARE(dav_error *) dav_popen_propdb(
|
||||
+ apr_pool_t *p,
|
||||
+ request_rec *r,
|
||||
+ dav_lockdb *lockdb,
|
||||
+ const dav_resource *resource,
|
||||
+ int ro,
|
||||
+ apr_array_header_t *ns_xlate,
|
||||
+ dav_propdb **propdb);
|
||||
+
|
||||
+
|
||||
DAV_DECLARE(void) dav_close_propdb(dav_propdb *db);
|
||||
|
||||
DAV_DECLARE(dav_get_props_result) dav_get_props(
|
||||
--- a/modules/dav/main/props.c
|
||||
+++ b/modules/dav/main/props.c
|
||||
@@ -323,7 +323,7 @@
|
||||
{
|
||||
/* need to escape the uri that's in the resource struct because during
|
||||
* the property walker it's not encoded. */
|
||||
- const char *e_uri = ap_escape_uri(propdb->resource->pool,
|
||||
+ const char *e_uri = ap_escape_uri(propdb->p,
|
||||
propdb->resource->uri);
|
||||
|
||||
/* perform a "GET" on the resource's URI (note that the resource
|
||||
@@ -524,8 +524,21 @@
|
||||
apr_array_header_t * ns_xlate,
|
||||
dav_propdb **p_propdb)
|
||||
{
|
||||
- dav_propdb *propdb = apr_pcalloc(r->pool, sizeof(*propdb));
|
||||
+ return dav_popen_propdb(r->pool, r, lockdb, resource, ro, ns_xlate, p_propdb);
|
||||
+}
|
||||
|
||||
+DAV_DECLARE(dav_error *)dav_popen_propdb(apr_pool_t *p,
|
||||
+ request_rec *r, dav_lockdb *lockdb,
|
||||
+ const dav_resource *resource,
|
||||
+ int ro,
|
||||
+ apr_array_header_t * ns_xlate,
|
||||
+ dav_propdb **p_propdb)
|
||||
+{
|
||||
+ dav_propdb *propdb = NULL;
|
||||
+
|
||||
+ propdb = apr_pcalloc(p, sizeof(*propdb));
|
||||
+ propdb->p = p;
|
||||
+
|
||||
*p_propdb = NULL;
|
||||
|
||||
#if DAV_DEBUG
|
||||
@@ -537,7 +550,6 @@
|
||||
#endif
|
||||
|
||||
propdb->r = r;
|
||||
- apr_pool_create(&propdb->p, r->pool);
|
||||
propdb->resource = resource;
|
||||
propdb->ns_xlate = ns_xlate;
|
||||
|
||||
@@ -562,10 +574,10 @@
|
||||
(*propdb->db_hooks->close)(propdb->db);
|
||||
}
|
||||
|
||||
- /* Currently, mod_dav's pool usage doesn't allow clearing this pool. */
|
||||
-#if 0
|
||||
- apr_pool_destroy(propdb->p);
|
||||
-#endif
|
||||
+ if (propdb->subreq) {
|
||||
+ ap_destroy_sub_req(propdb->subreq);
|
||||
+ propdb->subreq = NULL;
|
||||
+ }
|
||||
}
|
||||
|
||||
DAV_DECLARE(dav_get_props_result) dav_get_allprops(dav_propdb *propdb,
|
||||
@@ -739,7 +751,8 @@
|
||||
*/
|
||||
|
||||
if (elem->priv == NULL) {
|
||||
- elem->priv = apr_pcalloc(propdb->p, sizeof(*priv));
|
||||
+ /* elem->priv outlives propdb->p. Hence use the request pool */
|
||||
+ elem->priv = apr_pcalloc(propdb->r->pool, sizeof(*priv));
|
||||
}
|
||||
priv = elem->priv;
|
||||
|
@ -1,40 +0,0 @@
|
||||
--- a/modules/proxy/mod_proxy_hcheck.c 2019/07/30 13:01:08 1863999
|
||||
+++ b/modules/proxy/mod_proxy_hcheck.c 2019/07/30 13:01:21 1864000
|
||||
@@ -110,6 +110,10 @@
|
||||
if (!worker && !v) {
|
||||
return "Bad call to set_worker_hc_param()";
|
||||
}
|
||||
+ if (!ctx) {
|
||||
+ ctx = hc_create_config(p, s);
|
||||
+ ap_set_module_config(s->module_config, &proxy_hcheck_module, ctx);
|
||||
+ }
|
||||
temp = (hc_template_t *)v;
|
||||
if (!strcasecmp(key, "hctemplate")) {
|
||||
hc_template_t *template;
|
||||
@@ -1059,6 +1063,8 @@
|
||||
int i;
|
||||
sctx_t *ctx = (sctx_t *) ap_get_module_config(r->server->module_config,
|
||||
&proxy_hcheck_module);
|
||||
+ if (!ctx)
|
||||
+ return;
|
||||
if (apr_is_empty_table(ctx->conditions))
|
||||
return;
|
||||
|
||||
@@ -1088,6 +1094,8 @@
|
||||
int i;
|
||||
sctx_t *ctx = (sctx_t *) ap_get_module_config(r->server->module_config,
|
||||
&proxy_hcheck_module);
|
||||
+ if (!ctx)
|
||||
+ return;
|
||||
if (apr_is_empty_table(ctx->conditions))
|
||||
return;
|
||||
|
||||
@@ -1111,6 +1119,8 @@
|
||||
int i;
|
||||
sctx_t *ctx = (sctx_t *) ap_get_module_config(r->server->module_config,
|
||||
&proxy_hcheck_module);
|
||||
+ if (!ctx)
|
||||
+ return 0;
|
||||
if (apr_is_empty_table(ctx->conditions))
|
||||
return 0;
|
||||
|
@ -1,117 +0,0 @@
|
||||
# ./pullrev.sh 1870095 1870097
|
||||
http://svn.apache.org/viewvc?view=revision&revision=1870095
|
||||
http://svn.apache.org/viewvc?view=revision&revision=1870097
|
||||
|
||||
--- httpd-2.4.37/modules/ssl/ssl_engine_kernel.c
|
||||
+++ httpd-2.4.37/modules/ssl/ssl_engine_kernel.c
|
||||
@@ -114,6 +114,45 @@
|
||||
return result;
|
||||
}
|
||||
|
||||
+/* If a renegotiation is required for the location, and the request
|
||||
+ * includes a message body (and the client has not requested a "100
|
||||
+ * Continue" response), then the client will be streaming the request
|
||||
+ * body over the wire already. In that case, it is not possible to
|
||||
+ * stop and perform a new SSL handshake immediately; once the SSL
|
||||
+ * library moves to the "accept" state, it will reject the SSL packets
|
||||
+ * which the client is sending for the request body.
|
||||
+ *
|
||||
+ * To allow authentication to complete in the hook, the solution used
|
||||
+ * here is to fill a (bounded) buffer with the request body, and then
|
||||
+ * to reinject that request body later.
|
||||
+ *
|
||||
+ * This function is called to fill the renegotiation buffer for the
|
||||
+ * location as required, or fail. Returns zero on success or HTTP_
|
||||
+ * error code on failure.
|
||||
+ */
|
||||
+static int fill_reneg_buffer(request_rec *r, SSLDirConfigRec *dc)
|
||||
+{
|
||||
+ int rv;
|
||||
+ apr_size_t rsize;
|
||||
+
|
||||
+ /* ### this is HTTP/1.1 specific, special case for protocol? */
|
||||
+ if (r->expecting_100 || !ap_request_has_body(r)) {
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ rsize = dc->nRenegBufferSize == UNSET ? DEFAULT_RENEG_BUFFER_SIZE : dc->nRenegBufferSize;
|
||||
+ if (rsize > 0) {
|
||||
+ /* Fill the I/O buffer with the request body if possible. */
|
||||
+ rv = ssl_io_buffer_fill(r, rsize);
|
||||
+ }
|
||||
+ else {
|
||||
+ /* If the reneg buffer size is set to zero, just fail. */
|
||||
+ rv = HTTP_REQUEST_ENTITY_TOO_LARGE;
|
||||
+ }
|
||||
+
|
||||
+ return rv;
|
||||
+}
|
||||
+
|
||||
#ifdef HAVE_TLSEXT
|
||||
static int ap_array_same_str_set(apr_array_header_t *s1, apr_array_header_t *s2)
|
||||
{
|
||||
@@ -814,41 +853,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
- /* If a renegotiation is now required for this location, and the
|
||||
- * request includes a message body (and the client has not
|
||||
- * requested a "100 Continue" response), then the client will be
|
||||
- * streaming the request body over the wire already. In that
|
||||
- * case, it is not possible to stop and perform a new SSL
|
||||
- * handshake immediately; once the SSL library moves to the
|
||||
- * "accept" state, it will reject the SSL packets which the client
|
||||
- * is sending for the request body.
|
||||
- *
|
||||
- * To allow authentication to complete in this auth hook, the
|
||||
- * solution used here is to fill a (bounded) buffer with the
|
||||
- * request body, and then to reinject that request body later.
|
||||
- */
|
||||
- if (renegotiate && !renegotiate_quick
|
||||
- && !r->expecting_100
|
||||
- && ap_request_has_body(r)) {
|
||||
- int rv;
|
||||
- apr_size_t rsize;
|
||||
-
|
||||
- rsize = dc->nRenegBufferSize == UNSET ? DEFAULT_RENEG_BUFFER_SIZE :
|
||||
- dc->nRenegBufferSize;
|
||||
- if (rsize > 0) {
|
||||
- /* Fill the I/O buffer with the request body if possible. */
|
||||
- rv = ssl_io_buffer_fill(r, rsize);
|
||||
- }
|
||||
- else {
|
||||
- /* If the reneg buffer size is set to zero, just fail. */
|
||||
- rv = HTTP_REQUEST_ENTITY_TOO_LARGE;
|
||||
- }
|
||||
-
|
||||
- if (rv) {
|
||||
+ /* Fill reneg buffer if required. */
|
||||
+ if (renegotiate && !renegotiate_quick) {
|
||||
+ rc = fill_reneg_buffer(r, dc);
|
||||
+ if (rc) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02257)
|
||||
"could not buffer message body to allow "
|
||||
"SSL renegotiation to proceed");
|
||||
- return rv;
|
||||
+ return rc;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1132,6 +1144,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
+ /* Fill reneg buffer if required. */
|
||||
+ if (change_vmode) {
|
||||
+ rc = fill_reneg_buffer(r, dc);
|
||||
+ if (rc) {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10228)
|
||||
+ "could not buffer message body to allow "
|
||||
+ "TLS Post-Handshake Authentication to proceed");
|
||||
+ return rc;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
if (change_vmode) {
|
||||
char peekbuf[1];
|
||||
|
@ -1,636 +0,0 @@
|
||||
diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h
|
||||
index 57cc92f..fbbd508 100644
|
||||
--- a/modules/proxy/mod_proxy.h
|
||||
+++ b/modules/proxy/mod_proxy.h
|
||||
@@ -288,12 +288,15 @@ typedef struct {
|
||||
|
||||
/* Connection pool */
|
||||
struct proxy_conn_pool {
|
||||
- apr_pool_t *pool; /* The pool used in constructor and destructor calls */
|
||||
- apr_sockaddr_t *addr; /* Preparsed remote address info */
|
||||
- apr_reslist_t *res; /* Connection resource list */
|
||||
- proxy_conn_rec *conn; /* Single connection for prefork mpm */
|
||||
+ apr_pool_t *pool; /* The pool used in constructor and destructor calls */
|
||||
+ apr_sockaddr_t *addr; /* Preparsed remote address info */
|
||||
+ apr_reslist_t *res; /* Connection resource list */
|
||||
+ proxy_conn_rec *conn; /* Single connection for prefork mpm */
|
||||
+ apr_pool_t *dns_pool; /* The pool used for worker scoped DNS resolutions */
|
||||
};
|
||||
|
||||
+#define AP_VOLATILIZE_T(T, x) (*(T volatile *)&(x))
|
||||
+
|
||||
/* worker status bits */
|
||||
/*
|
||||
* NOTE: Keep up-to-date w/ proxy_wstat_tbl[]
|
||||
@@ -475,7 +478,9 @@ struct proxy_worker {
|
||||
proxy_conn_pool *cp; /* Connection pool to use */
|
||||
proxy_worker_shared *s; /* Shared data */
|
||||
proxy_balancer *balancer; /* which balancer am I in? */
|
||||
+#if APR_HAS_THREADS
|
||||
apr_thread_mutex_t *tmutex; /* Thread lock for updating address cache */
|
||||
+#endif
|
||||
void *context; /* general purpose storage */
|
||||
ap_conf_vector_t *section_config; /* <Proxy>-section wherein defined */
|
||||
};
|
||||
@@ -534,7 +539,9 @@ struct proxy_balancer {
|
||||
apr_time_t wupdated; /* timestamp of last change to workers list */
|
||||
proxy_balancer_method *lbmethod;
|
||||
apr_global_mutex_t *gmutex; /* global lock for updating list of workers */
|
||||
+#if APR_HAS_THREADS
|
||||
apr_thread_mutex_t *tmutex; /* Thread lock for updating shm */
|
||||
+#endif
|
||||
proxy_server_conf *sconf;
|
||||
void *context; /* general purpose storage */
|
||||
proxy_balancer_shared *s; /* Shared data */
|
||||
diff --git a/modules/proxy/mod_proxy_balancer.c b/modules/proxy/mod_proxy_balancer.c
|
||||
index c59f5e9..3a28038 100644
|
||||
--- a/modules/proxy/mod_proxy_balancer.c
|
||||
+++ b/modules/proxy/mod_proxy_balancer.c
|
||||
@@ -346,23 +346,27 @@ static proxy_worker *find_best_worker(proxy_balancer *balancer,
|
||||
proxy_worker *candidate = NULL;
|
||||
apr_status_t rv;
|
||||
|
||||
+#if APR_HAS_THREADS
|
||||
if ((rv = PROXY_THREAD_LOCK(balancer)) != APR_SUCCESS) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01163)
|
||||
"%s: Lock failed for find_best_worker()",
|
||||
balancer->s->name);
|
||||
return NULL;
|
||||
}
|
||||
+#endif
|
||||
|
||||
candidate = (*balancer->lbmethod->finder)(balancer, r);
|
||||
|
||||
if (candidate)
|
||||
candidate->s->elected++;
|
||||
|
||||
+#if APR_HAS_THREADS
|
||||
if ((rv = PROXY_THREAD_UNLOCK(balancer)) != APR_SUCCESS) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01164)
|
||||
"%s: Unlock failed for find_best_worker()",
|
||||
balancer->s->name);
|
||||
}
|
||||
+#endif
|
||||
|
||||
if (candidate == NULL) {
|
||||
/* All the workers are in error state or disabled.
|
||||
@@ -492,11 +496,13 @@ static int proxy_balancer_pre_request(proxy_worker **worker,
|
||||
/* Step 2: Lock the LoadBalancer
|
||||
* XXX: perhaps we need the process lock here
|
||||
*/
|
||||
+#if APR_HAS_THREADS
|
||||
if ((rv = PROXY_THREAD_LOCK(*balancer)) != APR_SUCCESS) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01166)
|
||||
"%s: Lock failed for pre_request", (*balancer)->s->name);
|
||||
return DECLINED;
|
||||
}
|
||||
+#endif
|
||||
|
||||
/* Step 3: force recovery */
|
||||
force_recovery(*balancer, r->server);
|
||||
@@ -557,20 +563,24 @@ static int proxy_balancer_pre_request(proxy_worker **worker,
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01167)
|
||||
"%s: All workers are in error state for route (%s)",
|
||||
(*balancer)->s->name, route);
|
||||
+#if APR_HAS_THREADS
|
||||
if ((rv = PROXY_THREAD_UNLOCK(*balancer)) != APR_SUCCESS) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01168)
|
||||
"%s: Unlock failed for pre_request",
|
||||
(*balancer)->s->name);
|
||||
}
|
||||
+#endif
|
||||
return HTTP_SERVICE_UNAVAILABLE;
|
||||
}
|
||||
}
|
||||
|
||||
+#if APR_HAS_THREADS
|
||||
if ((rv = PROXY_THREAD_UNLOCK(*balancer)) != APR_SUCCESS) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01169)
|
||||
"%s: Unlock failed for pre_request",
|
||||
(*balancer)->s->name);
|
||||
}
|
||||
+#endif
|
||||
if (!*worker) {
|
||||
runtime = find_best_worker(*balancer, r);
|
||||
if (!runtime) {
|
||||
@@ -644,12 +654,14 @@ static int proxy_balancer_post_request(proxy_worker *worker,
|
||||
|
||||
apr_status_t rv;
|
||||
|
||||
+#if APR_HAS_THREADS
|
||||
if ((rv = PROXY_THREAD_LOCK(balancer)) != APR_SUCCESS) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01173)
|
||||
"%s: Lock failed for post_request",
|
||||
balancer->s->name);
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
+#endif
|
||||
|
||||
if (!apr_is_empty_array(balancer->errstatuses)
|
||||
&& !(worker->s->status & PROXY_WORKER_IGNORE_ERRORS)) {
|
||||
@@ -681,11 +693,12 @@ static int proxy_balancer_post_request(proxy_worker *worker,
|
||||
worker->s->error_time = apr_time_now();
|
||||
|
||||
}
|
||||
-
|
||||
+#if APR_HAS_THREADS
|
||||
if ((rv = PROXY_THREAD_UNLOCK(balancer)) != APR_SUCCESS) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01175)
|
||||
"%s: Unlock failed for post_request", balancer->s->name);
|
||||
}
|
||||
+#endif
|
||||
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01176)
|
||||
"proxy_balancer_post_request for (%s)", balancer->s->name);
|
||||
|
||||
@@ -945,7 +958,6 @@ static int balancer_post_config(apr_pool_t *pconf, apr_pool_t *plog,
|
||||
PROXY_STRNCPY(balancer->s->sname, sname); /* We know this will succeed */
|
||||
|
||||
balancer->max_workers = balancer->workers->nelts + balancer->growth;
|
||||
-
|
||||
/* Create global mutex */
|
||||
rv = ap_global_mutex_create(&(balancer->gmutex), NULL, balancer_mutex_type,
|
||||
balancer->s->sname, s, pconf, 0);
|
||||
@@ -955,7 +967,6 @@ static int balancer_post_config(apr_pool_t *pconf, apr_pool_t *plog,
|
||||
balancer->s->sname);
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
-
|
||||
apr_pool_cleanup_register(pconf, (void *)s, lock_remove,
|
||||
apr_pool_cleanup_null);
|
||||
|
||||
@@ -1135,17 +1146,21 @@ static int balancer_handler(request_rec *r)
|
||||
|
||||
balancer = (proxy_balancer *)conf->balancers->elts;
|
||||
for (i = 0; i < conf->balancers->nelts; i++, balancer++) {
|
||||
+#if APR_HAS_THREADS
|
||||
if ((rv = PROXY_THREAD_LOCK(balancer)) != APR_SUCCESS) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01189)
|
||||
"%s: Lock failed for balancer_handler",
|
||||
balancer->s->name);
|
||||
}
|
||||
+#endif
|
||||
ap_proxy_sync_balancer(balancer, r->server, conf);
|
||||
+#if APR_HAS_THREADS
|
||||
if ((rv = PROXY_THREAD_UNLOCK(balancer)) != APR_SUCCESS) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01190)
|
||||
"%s: Unlock failed for balancer_handler",
|
||||
balancer->s->name);
|
||||
}
|
||||
+#endif
|
||||
}
|
||||
|
||||
if (r->args && (r->method_number == M_GET)) {
|
||||
@@ -1359,11 +1374,13 @@ static int balancer_handler(request_rec *r)
|
||||
proxy_worker *nworker;
|
||||
nworker = ap_proxy_get_worker(r->pool, bsel, conf, val);
|
||||
if (!nworker && storage->num_free_slots(bsel->wslot)) {
|
||||
+#if APR_HAS_THREADS
|
||||
if ((rv = PROXY_GLOBAL_LOCK(bsel)) != APR_SUCCESS) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01194)
|
||||
"%s: Lock failed for adding worker",
|
||||
bsel->s->name);
|
||||
}
|
||||
+#endif
|
||||
ret = ap_proxy_define_worker(conf->pool, &nworker, bsel, conf, val, 0);
|
||||
if (!ret) {
|
||||
unsigned int index;
|
||||
@@ -1372,53 +1389,76 @@ static int balancer_handler(request_rec *r)
|
||||
if ((rv = storage->grab(bsel->wslot, &index)) != APR_SUCCESS) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_EMERG, rv, r, APLOGNO(01195)
|
||||
"worker slotmem_grab failed");
|
||||
+#if APR_HAS_THREADS
|
||||
if ((rv = PROXY_GLOBAL_UNLOCK(bsel)) != APR_SUCCESS) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01196)
|
||||
"%s: Unlock failed for adding worker",
|
||||
bsel->s->name);
|
||||
}
|
||||
+#endif
|
||||
return HTTP_BAD_REQUEST;
|
||||
}
|
||||
if ((rv = storage->dptr(bsel->wslot, index, (void *)&shm)) != APR_SUCCESS) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_EMERG, rv, r, APLOGNO(01197)
|
||||
"worker slotmem_dptr failed");
|
||||
+#if APR_HAS_THREADS
|
||||
if ((rv = PROXY_GLOBAL_UNLOCK(bsel)) != APR_SUCCESS) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01198)
|
||||
"%s: Unlock failed for adding worker",
|
||||
bsel->s->name);
|
||||
}
|
||||
+#endif
|
||||
return HTTP_BAD_REQUEST;
|
||||
}
|
||||
if ((rv = ap_proxy_share_worker(nworker, shm, index)) != APR_SUCCESS) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_EMERG, rv, r, APLOGNO(01199)
|
||||
"Cannot share worker");
|
||||
+#if APR_HAS_THREADS
|
||||
if ((rv = PROXY_GLOBAL_UNLOCK(bsel)) != APR_SUCCESS) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01200)
|
||||
"%s: Unlock failed for adding worker",
|
||||
bsel->s->name);
|
||||
}
|
||||
+#endif
|
||||
return HTTP_BAD_REQUEST;
|
||||
}
|
||||
if ((rv = ap_proxy_initialize_worker(nworker, r->server, conf->pool)) != APR_SUCCESS) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_EMERG, rv, r, APLOGNO(01201)
|
||||
"Cannot init worker");
|
||||
+#if APR_HAS_THREADS
|
||||
if ((rv = PROXY_GLOBAL_UNLOCK(bsel)) != APR_SUCCESS) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01202)
|
||||
"%s: Unlock failed for adding worker",
|
||||
bsel->s->name);
|
||||
}
|
||||
+#endif
|
||||
return HTTP_BAD_REQUEST;
|
||||
}
|
||||
/* sync all timestamps */
|
||||
bsel->wupdated = bsel->s->wupdated = nworker->s->updated = apr_time_now();
|
||||
/* by default, all new workers are disabled */
|
||||
ap_proxy_set_wstatus(PROXY_WORKER_DISABLED_FLAG, 1, nworker);
|
||||
+ } else {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10163)
|
||||
+ "%s: failed to add worker %s",
|
||||
+ bsel->s->name, val);
|
||||
+#if APR_HAS_THREADS
|
||||
+ PROXY_GLOBAL_UNLOCK(bsel);
|
||||
+#endif
|
||||
+ return HTTP_BAD_REQUEST;
|
||||
}
|
||||
+#if APR_HAS_THREADS
|
||||
if ((rv = PROXY_GLOBAL_UNLOCK(bsel)) != APR_SUCCESS) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01203)
|
||||
"%s: Unlock failed for adding worker",
|
||||
bsel->s->name);
|
||||
}
|
||||
+#endif
|
||||
+ } else {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10164)
|
||||
+ "%s: failed to add worker %s",
|
||||
+ bsel->s->name, val);
|
||||
+ return HTTP_BAD_REQUEST;
|
||||
}
|
||||
|
||||
}
|
||||
diff --git a/modules/proxy/mod_proxy_ftp.c b/modules/proxy/mod_proxy_ftp.c
|
||||
index 5d9175e..5c4d641 100644
|
||||
--- a/modules/proxy/mod_proxy_ftp.c
|
||||
+++ b/modules/proxy/mod_proxy_ftp.c
|
||||
@@ -979,8 +979,10 @@ static int proxy_ftp_handler(request_rec *r, proxy_worker *worker,
|
||||
apr_status_t rv;
|
||||
conn_rec *origin, *data = NULL;
|
||||
apr_status_t err = APR_SUCCESS;
|
||||
+#if APR_HAS_THREADS
|
||||
apr_status_t uerr = APR_SUCCESS;
|
||||
- apr_bucket_brigade *bb = apr_brigade_create(p, c->bucket_alloc);
|
||||
+#endif
|
||||
+ apr_bucket_brigade *bb;
|
||||
char *buf, *connectname;
|
||||
apr_port_t connectport;
|
||||
char *ftpmessage = NULL;
|
||||
@@ -1120,13 +1122,15 @@ static int proxy_ftp_handler(request_rec *r, proxy_worker *worker,
|
||||
|
||||
if (worker->s->is_address_reusable) {
|
||||
if (!worker->cp->addr) {
|
||||
+#if APR_HAS_THREADS
|
||||
if ((err = PROXY_THREAD_LOCK(worker->balancer)) != APR_SUCCESS) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, err, r, APLOGNO(01037) "lock");
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
+#endif
|
||||
}
|
||||
- connect_addr = worker->cp->addr;
|
||||
- address_pool = worker->cp->pool;
|
||||
+ connect_addr = AP_VOLATILIZE_T(apr_sockaddr_t *, worker->cp->addr);
|
||||
+ address_pool = worker->cp->dns_pool;
|
||||
}
|
||||
else
|
||||
address_pool = r->pool;
|
||||
@@ -1139,9 +1143,11 @@ static int proxy_ftp_handler(request_rec *r, proxy_worker *worker,
|
||||
address_pool);
|
||||
if (worker->s->is_address_reusable && !worker->cp->addr) {
|
||||
worker->cp->addr = connect_addr;
|
||||
+#if APR_HAS_THREADS
|
||||
if ((uerr = PROXY_THREAD_UNLOCK(worker->balancer)) != APR_SUCCESS) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, uerr, r, APLOGNO(01038) "unlock");
|
||||
}
|
||||
+#endif
|
||||
}
|
||||
/*
|
||||
* get all the possible IP addresses for the destname and loop through
|
||||
@@ -1212,6 +1218,7 @@ static int proxy_ftp_handler(request_rec *r, proxy_worker *worker,
|
||||
* correct directory...
|
||||
*/
|
||||
|
||||
+ bb = apr_brigade_create(p, c->bucket_alloc);
|
||||
|
||||
/* possible results: */
|
||||
/* 120 Service ready in nnn minutes. */
|
||||
diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c
|
||||
index 2bfc8f0..7714b6c 100644
|
||||
--- a/modules/proxy/proxy_util.c
|
||||
+++ b/modules/proxy/proxy_util.c
|
||||
@@ -1167,8 +1167,10 @@ PROXY_DECLARE(char *) ap_proxy_define_balancer(apr_pool_t *p,
|
||||
lbmethod = ap_lookup_provider(PROXY_LBMETHOD, "byrequests", "0");
|
||||
|
||||
(*balancer)->workers = apr_array_make(p, 5, sizeof(proxy_worker *));
|
||||
+#if APR_HAS_THREADS
|
||||
(*balancer)->gmutex = NULL;
|
||||
(*balancer)->tmutex = NULL;
|
||||
+#endif
|
||||
(*balancer)->lbmethod = lbmethod;
|
||||
|
||||
if (do_malloc)
|
||||
@@ -1257,7 +1259,9 @@ PROXY_DECLARE(apr_status_t) ap_proxy_share_balancer(proxy_balancer *balancer,
|
||||
|
||||
PROXY_DECLARE(apr_status_t) ap_proxy_initialize_balancer(proxy_balancer *balancer, server_rec *s, apr_pool_t *p)
|
||||
{
|
||||
+#if APR_HAS_THREADS
|
||||
apr_status_t rv = APR_SUCCESS;
|
||||
+#endif
|
||||
ap_slotmem_provider_t *storage = balancer->storage;
|
||||
apr_size_t size;
|
||||
unsigned int num;
|
||||
@@ -1297,6 +1301,7 @@ PROXY_DECLARE(apr_status_t) ap_proxy_initialize_balancer(proxy_balancer *balance
|
||||
if (balancer->lbmethod && balancer->lbmethod->reset)
|
||||
balancer->lbmethod->reset(balancer, s);
|
||||
|
||||
+#if APR_HAS_THREADS
|
||||
if (balancer->tmutex == NULL) {
|
||||
rv = apr_thread_mutex_create(&(balancer->tmutex), APR_THREAD_MUTEX_DEFAULT, p);
|
||||
if (rv != APR_SUCCESS) {
|
||||
@@ -1305,6 +1310,7 @@ PROXY_DECLARE(apr_status_t) ap_proxy_initialize_balancer(proxy_balancer *balance
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
+#endif
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1446,16 +1452,14 @@ static void socket_cleanup(proxy_conn_rec *conn)
|
||||
|
||||
static apr_status_t conn_pool_cleanup(void *theworker)
|
||||
{
|
||||
- proxy_worker *worker = (proxy_worker *)theworker;
|
||||
- if (worker->cp->res) {
|
||||
- worker->cp->pool = NULL;
|
||||
- }
|
||||
+ ((proxy_worker *)theworker)->cp = NULL;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
static void init_conn_pool(apr_pool_t *p, proxy_worker *worker)
|
||||
{
|
||||
apr_pool_t *pool;
|
||||
+ apr_pool_t *dns_pool;
|
||||
proxy_conn_pool *cp;
|
||||
|
||||
/*
|
||||
@@ -1466,12 +1470,21 @@ static void init_conn_pool(apr_pool_t *p, proxy_worker *worker)
|
||||
*/
|
||||
apr_pool_create(&pool, p);
|
||||
apr_pool_tag(pool, "proxy_worker_cp");
|
||||
+ /*
|
||||
+ * Create a subpool of the connection pool for worker
|
||||
+ * scoped DNS resolutions. This is needed to avoid race
|
||||
+ * conditions in using the connection pool by multiple
|
||||
+ * threads during ramp up.
|
||||
+ */
|
||||
+ apr_pool_create(&dns_pool, pool);
|
||||
+ apr_pool_tag(dns_pool, "proxy_worker_dns");
|
||||
/*
|
||||
* Alloc from the same pool as worker.
|
||||
* proxy_conn_pool is permanently attached to the worker.
|
||||
*/
|
||||
cp = (proxy_conn_pool *)apr_pcalloc(p, sizeof(proxy_conn_pool));
|
||||
cp->pool = pool;
|
||||
+ cp->dns_pool = dns_pool;
|
||||
worker->cp = cp;
|
||||
}
|
||||
|
||||
@@ -1487,14 +1500,6 @@ static apr_status_t connection_cleanup(void *theconn)
|
||||
proxy_conn_rec *conn = (proxy_conn_rec *)theconn;
|
||||
proxy_worker *worker = conn->worker;
|
||||
|
||||
- /*
|
||||
- * If the connection pool is NULL the worker
|
||||
- * cleanup has been run. Just return.
|
||||
- */
|
||||
- if (!worker->cp->pool) {
|
||||
- return APR_SUCCESS;
|
||||
- }
|
||||
-
|
||||
if (conn->r) {
|
||||
apr_pool_destroy(conn->r->pool);
|
||||
conn->r = NULL;
|
||||
@@ -1616,7 +1621,7 @@ static apr_status_t connection_destructor(void *resource, void *params,
|
||||
proxy_worker *worker = params;
|
||||
|
||||
/* Destroy the pool only if not called from reslist_destroy */
|
||||
- if (worker->cp->pool) {
|
||||
+ if (worker->cp) {
|
||||
proxy_conn_rec *conn = resource;
|
||||
apr_pool_destroy(conn->pool);
|
||||
}
|
||||
@@ -1972,67 +1977,73 @@ PROXY_DECLARE(apr_status_t) ap_proxy_initialize_worker(proxy_worker *worker, ser
|
||||
ap_proxy_worker_name(p, worker));
|
||||
}
|
||||
else {
|
||||
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00927)
|
||||
- "initializing worker %s local",
|
||||
- ap_proxy_worker_name(p, worker));
|
||||
apr_global_mutex_lock(proxy_mutex);
|
||||
- /* Now init local worker data */
|
||||
- if (worker->tmutex == NULL) {
|
||||
- rv = apr_thread_mutex_create(&(worker->tmutex), APR_THREAD_MUTEX_DEFAULT, p);
|
||||
- if (rv != APR_SUCCESS) {
|
||||
- ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(00928)
|
||||
- "can not create worker thread mutex");
|
||||
+ /* Check again after we got the lock if we are still uninitialized */
|
||||
+ if (!(AP_VOLATILIZE_T(unsigned int, worker->local_status) & PROXY_WORKER_INITIALIZED)) {
|
||||
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00927)
|
||||
+ "initializing worker %s local",
|
||||
+ ap_proxy_worker_name(p, worker));
|
||||
+ /* Now init local worker data */
|
||||
+#if APR_HAS_THREADS
|
||||
+ if (worker->tmutex == NULL) {
|
||||
+ rv = apr_thread_mutex_create(&(worker->tmutex), APR_THREAD_MUTEX_DEFAULT, p);
|
||||
+ if (rv != APR_SUCCESS) {
|
||||
+ ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00928)
|
||||
+ "can not create worker thread mutex");
|
||||
+ apr_global_mutex_unlock(proxy_mutex);
|
||||
+ return rv;
|
||||
+ }
|
||||
+ }
|
||||
+#endif
|
||||
+ if (worker->cp == NULL)
|
||||
+ init_conn_pool(p, worker);
|
||||
+ if (worker->cp == NULL) {
|
||||
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(00929)
|
||||
+ "can not create connection pool");
|
||||
apr_global_mutex_unlock(proxy_mutex);
|
||||
- return rv;
|
||||
+ return APR_EGENERAL;
|
||||
}
|
||||
- }
|
||||
- if (worker->cp == NULL)
|
||||
- init_conn_pool(p, worker);
|
||||
- if (worker->cp == NULL) {
|
||||
- ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(00929)
|
||||
- "can not create connection pool");
|
||||
- apr_global_mutex_unlock(proxy_mutex);
|
||||
- return APR_EGENERAL;
|
||||
- }
|
||||
|
||||
- if (worker->s->hmax) {
|
||||
- rv = apr_reslist_create(&(worker->cp->res),
|
||||
- worker->s->min, worker->s->smax,
|
||||
- worker->s->hmax, worker->s->ttl,
|
||||
- connection_constructor, connection_destructor,
|
||||
- worker, worker->cp->pool);
|
||||
+ if (worker->s->hmax) {
|
||||
+ rv = apr_reslist_create(&(worker->cp->res),
|
||||
+ worker->s->min, worker->s->smax,
|
||||
+ worker->s->hmax, worker->s->ttl,
|
||||
+ connection_constructor, connection_destructor,
|
||||
+ worker, worker->cp->pool);
|
||||
|
||||
- apr_pool_cleanup_register(worker->cp->pool, (void *)worker,
|
||||
- conn_pool_cleanup,
|
||||
- apr_pool_cleanup_null);
|
||||
+ apr_pool_pre_cleanup_register(worker->cp->pool, worker,
|
||||
+ conn_pool_cleanup);
|
||||
|
||||
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00930)
|
||||
- "initialized pool in child %" APR_PID_T_FMT " for (%s) min=%d max=%d smax=%d",
|
||||
- getpid(), worker->s->hostname_ex, worker->s->min,
|
||||
- worker->s->hmax, worker->s->smax);
|
||||
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00930)
|
||||
+ "initialized pool in child %" APR_PID_T_FMT " for (%s) min=%d max=%d smax=%d",
|
||||
+ getpid(), worker->s->hostname_ex, worker->s->min,
|
||||
+ worker->s->hmax, worker->s->smax);
|
||||
|
||||
- /* Set the acquire timeout */
|
||||
- if (rv == APR_SUCCESS && worker->s->acquire_set) {
|
||||
- apr_reslist_timeout_set(worker->cp->res, worker->s->acquire);
|
||||
- }
|
||||
+ /* Set the acquire timeout */
|
||||
+ if (rv == APR_SUCCESS && worker->s->acquire_set) {
|
||||
+ apr_reslist_timeout_set(worker->cp->res, worker->s->acquire);
|
||||
+ }
|
||||
|
||||
- }
|
||||
- else {
|
||||
- void *conn;
|
||||
+ }
|
||||
+ else {
|
||||
+ void *conn;
|
||||
|
||||
- rv = connection_constructor(&conn, worker, worker->cp->pool);
|
||||
- worker->cp->conn = conn;
|
||||
+ rv = connection_constructor(&conn, worker, worker->cp->pool);
|
||||
+ worker->cp->conn = conn;
|
||||
|
||||
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00931)
|
||||
- "initialized single connection worker in child %" APR_PID_T_FMT " for (%s)",
|
||||
- getpid(), worker->s->hostname_ex);
|
||||
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, s, APLOGNO(00931)
|
||||
+ "initialized single connection worker in child %" APR_PID_T_FMT " for (%s)",
|
||||
+ getpid(), worker->s->hostname_ex);
|
||||
+ }
|
||||
+ if (rv == APR_SUCCESS) {
|
||||
+ worker->local_status |= (PROXY_WORKER_INITIALIZED);
|
||||
+ }
|
||||
}
|
||||
apr_global_mutex_unlock(proxy_mutex);
|
||||
|
||||
}
|
||||
if (rv == APR_SUCCESS) {
|
||||
worker->s->status |= (PROXY_WORKER_INITIALIZED);
|
||||
- worker->local_status |= (PROXY_WORKER_INITIALIZED);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
@@ -2292,13 +2303,13 @@ PROXY_DECLARE(int) ap_proxy_acquire_connection(const char *proxy_function,
|
||||
else {
|
||||
/* create the new connection if the previous was destroyed */
|
||||
if (!worker->cp->conn) {
|
||||
- connection_constructor((void **)conn, worker, worker->cp->pool);
|
||||
+ rv = connection_constructor((void **)conn, worker, worker->cp->pool);
|
||||
}
|
||||
else {
|
||||
*conn = worker->cp->conn;
|
||||
worker->cp->conn = NULL;
|
||||
+ rv = APR_SUCCESS;
|
||||
}
|
||||
- rv = APR_SUCCESS;
|
||||
}
|
||||
|
||||
if (rv != APR_SUCCESS) {
|
||||
@@ -2344,7 +2355,9 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r,
|
||||
{
|
||||
int server_port;
|
||||
apr_status_t err = APR_SUCCESS;
|
||||
+#if APR_HAS_THREADS
|
||||
apr_status_t uerr = APR_SUCCESS;
|
||||
+#endif
|
||||
const char *uds_path;
|
||||
|
||||
/*
|
||||
@@ -2481,25 +2494,39 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r,
|
||||
* we can reuse the address.
|
||||
*/
|
||||
if (!worker->cp->addr) {
|
||||
+#if APR_HAS_THREADS
|
||||
if ((err = PROXY_THREAD_LOCK(worker)) != APR_SUCCESS) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, err, r, APLOGNO(00945) "lock");
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
+#endif
|
||||
|
||||
/*
|
||||
- * Worker can have the single constant backend address.
|
||||
- * The single DNS lookup is used once per worker.
|
||||
- * If dynamic change is needed then set the addr to NULL
|
||||
- * inside dynamic config to force the lookup.
|
||||
+ * Recheck addr after we got the lock. This may have changed
|
||||
+ * while waiting for the lock.
|
||||
*/
|
||||
- err = apr_sockaddr_info_get(&(worker->cp->addr),
|
||||
- conn->hostname, APR_UNSPEC,
|
||||
- conn->port, 0,
|
||||
- worker->cp->pool);
|
||||
+ if (!AP_VOLATILIZE_T(apr_sockaddr_t *, worker->cp->addr)) {
|
||||
+
|
||||
+ apr_sockaddr_t *addr;
|
||||
+
|
||||
+ /*
|
||||
+ * Worker can have the single constant backend address.
|
||||
+ * The single DNS lookup is used once per worker.
|
||||
+ * If dynamic change is needed then set the addr to NULL
|
||||
+ * inside dynamic config to force the lookup.
|
||||
+ */
|
||||
+ err = apr_sockaddr_info_get(&addr,
|
||||
+ conn->hostname, APR_UNSPEC,
|
||||
+ conn->port, 0,
|
||||
+ worker->cp->dns_pool);
|
||||
+ worker->cp->addr = addr;
|
||||
+ }
|
||||
conn->addr = worker->cp->addr;
|
||||
+#if APR_HAS_THREADS
|
||||
if ((uerr = PROXY_THREAD_UNLOCK(worker)) != APR_SUCCESS) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, uerr, r, APLOGNO(00946) "unlock");
|
||||
}
|
||||
+#endif
|
||||
}
|
||||
else {
|
||||
conn->addr = worker->cp->addr;
|
||||
@@ -3422,7 +3449,9 @@ PROXY_DECLARE(apr_status_t) ap_proxy_sync_balancer(proxy_balancer *b, server_rec
|
||||
(*runtime)->cp = NULL;
|
||||
(*runtime)->balancer = b;
|
||||
(*runtime)->s = shm;
|
||||
+#if APR_HAS_THREADS
|
||||
(*runtime)->tmutex = NULL;
|
||||
+#endif
|
||||
rv = ap_proxy_initialize_worker(*runtime, s, conf->pool);
|
||||
if (rv != APR_SUCCESS) {
|
||||
ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(00966) "Cannot init worker");
|
@ -1,265 +0,0 @@
|
||||
diff --git a/docs/manual/mod/mod_ssl.html.en b/docs/manual/mod/mod_ssl.html.en
|
||||
index b543150..ab72d4f 100644
|
||||
--- a/docs/manual/mod/mod_ssl.html.en
|
||||
+++ b/docs/manual/mod/mod_ssl.html.en
|
||||
@@ -1524,6 +1524,32 @@ The available (case-insensitive) <em>protocol</em>s are:</p>
|
||||
<div class="example"><h3>Example</h3><pre class="prettyprint lang-config">SSLProtocol TLSv1</pre>
|
||||
</div>
|
||||
|
||||
+<div class="note">
|
||||
+<h3><code class="directive">SSLProtocol</code> for name-based virtual hosts</h3>
|
||||
+<p>
|
||||
+Before OpenSSL 1.1.1, even though the Server Name Indication (SNI) allowed to
|
||||
+determine the targeted virtual host early in the TLS handshake, it was not
|
||||
+possible to switch the TLS protocol version of the connection at this point,
|
||||
+and thus the <code class="directive">SSLProtocol</code> negotiated was always based off
|
||||
+the one of the <em>base virtual host</em> (first virtual host declared on the
|
||||
+listening <code>IP:port</code> of the connection).
|
||||
+</p>
|
||||
+<p>
|
||||
+Beginning with Apache HTTP server version 2.4.42, when built/linked against
|
||||
+OpenSSL 1.1.1 or later, and when the SNI is provided by the client in the TLS
|
||||
+handshake, the <code class="directive">SSLProtocol</code> of each (name-based) virtual
|
||||
+host can and will be honored.
|
||||
+</p>
|
||||
+<p>
|
||||
+For compatibility with previous versions, if no
|
||||
+<code class="directive">SSLProtocol</code> is configured in a name-based virtual host,
|
||||
+the one from the base virtual host still applies, <strong>unless</strong>
|
||||
+<code class="directive">SSLProtocol</code> is configured globally in which case the
|
||||
+global value applies (this latter exception is more sensible than compatible,
|
||||
+though).
|
||||
+</p>
|
||||
+</div>
|
||||
+
|
||||
</div>
|
||||
<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
|
||||
<div class="directive-section"><h2><a name="SSLProxyCACertificateFile" id="SSLProxyCACertificateFile">SSLProxyCACertificateFile</a> <a name="sslproxycacertificatefile" id="sslproxycacertificatefile">Directive</a></h2>
|
||||
diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c
|
||||
index 0c4bf1f..ca5f702 100644
|
||||
--- a/modules/ssl/ssl_engine_config.c
|
||||
+++ b/modules/ssl/ssl_engine_config.c
|
||||
@@ -269,6 +269,7 @@ static void modssl_ctx_cfg_merge(apr_pool_t *p,
|
||||
mrg->protocol_set = 1;
|
||||
}
|
||||
else {
|
||||
+ mrg->protocol_set = base->protocol_set;
|
||||
mrg->protocol = base->protocol;
|
||||
}
|
||||
|
||||
diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c
|
||||
index 31062bc..70d151e 100644
|
||||
--- a/modules/ssl/ssl_engine_init.c
|
||||
+++ b/modules/ssl/ssl_engine_init.c
|
||||
@@ -520,7 +520,9 @@ static apr_status_t ssl_init_ctx_tls_extensions(server_rec *s,
|
||||
"Configuring TLS extension handling");
|
||||
|
||||
/*
|
||||
- * Server name indication (SNI)
|
||||
+ * The Server Name Indication (SNI) provided by the ClientHello can be
|
||||
+ * used to select the right (name-based-)vhost and its SSL configuration
|
||||
+ * before the handshake takes place.
|
||||
*/
|
||||
if (!SSL_CTX_set_tlsext_servername_callback(mctx->ssl_ctx,
|
||||
ssl_callback_ServerNameIndication) ||
|
||||
@@ -532,6 +534,16 @@ static apr_status_t ssl_init_ctx_tls_extensions(server_rec *s,
|
||||
return ssl_die(s);
|
||||
}
|
||||
|
||||
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER)
|
||||
+ /*
|
||||
+ * The ClientHello callback also allows to retrieve the SNI, but since it
|
||||
+ * runs at the earliest possible connection stage we can even set the TLS
|
||||
+ * protocol version(s) according to the selected (name-based-)vhost, which
|
||||
+ * is not possible at the SNI callback stage (due to OpenSSL internals).
|
||||
+ */
|
||||
+ SSL_CTX_set_client_hello_cb(mctx->ssl_ctx, ssl_callback_ClientHello, NULL);
|
||||
+#endif
|
||||
+
|
||||
#ifdef HAVE_OCSP_STAPLING
|
||||
/*
|
||||
* OCSP Stapling support, status_request extension
|
||||
@@ -708,7 +720,7 @@ static apr_status_t ssl_init_ctx_protocol(server_rec *s,
|
||||
#else /* #if OPENSSL_VERSION_NUMBER < 0x10100000L */
|
||||
/* We first determine the maximum protocol version we should provide */
|
||||
#if SSL_HAVE_PROTOCOL_TLSV1_3
|
||||
- if (SSL_HAVE_PROTOCOL_TLSV1_3 && (protocol & SSL_PROTOCOL_TLSV1_3)) {
|
||||
+ if (protocol & SSL_PROTOCOL_TLSV1_3) {
|
||||
prot = TLS1_3_VERSION;
|
||||
} else
|
||||
#endif
|
||||
diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c
|
||||
index 8b44674..7313a55 100644
|
||||
--- a/modules/ssl/ssl_engine_kernel.c
|
||||
+++ b/modules/ssl/ssl_engine_kernel.c
|
||||
@@ -2357,28 +2357,31 @@ static apr_status_t set_challenge_creds(conn_rec *c, const char *servername,
|
||||
* This function sets the virtual host from an extended
|
||||
* client hello with a server name indication extension ("SNI", cf. RFC 6066).
|
||||
*/
|
||||
-static apr_status_t init_vhost(conn_rec *c, SSL *ssl)
|
||||
+static apr_status_t init_vhost(conn_rec *c, SSL *ssl, const char *servername)
|
||||
{
|
||||
- const char *servername;
|
||||
X509 *cert;
|
||||
EVP_PKEY *key;
|
||||
|
||||
if (c) {
|
||||
SSLConnRec *sslcon = myConnConfig(c);
|
||||
-
|
||||
- if (sslcon->server != c->base_server) {
|
||||
- /* already found the vhost */
|
||||
- return APR_SUCCESS;
|
||||
+
|
||||
+ if (sslcon->vhost_found) {
|
||||
+ /* already found the vhost? */
|
||||
+ return sslcon->vhost_found > 0 ? APR_SUCCESS : APR_NOTFOUND;
|
||||
}
|
||||
+ sslcon->vhost_found = -1;
|
||||
|
||||
- servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
|
||||
+ if (!servername) {
|
||||
+ servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
|
||||
+ }
|
||||
if (servername) {
|
||||
if (ap_vhost_iterate_given_conn(c, ssl_find_vhost,
|
||||
(void *)servername)) {
|
||||
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(02043)
|
||||
"SSL virtual host for servername %s found",
|
||||
servername);
|
||||
-
|
||||
+
|
||||
+ sslcon->vhost_found = +1;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
else if (ssl_is_challenge(c, servername, &cert, &key)) {
|
||||
@@ -2428,11 +2431,72 @@ static apr_status_t init_vhost(conn_rec *c, SSL *ssl)
|
||||
int ssl_callback_ServerNameIndication(SSL *ssl, int *al, modssl_ctx_t *mctx)
|
||||
{
|
||||
conn_rec *c = (conn_rec *)SSL_get_app_data(ssl);
|
||||
- apr_status_t status = init_vhost(c, ssl);
|
||||
+ apr_status_t status = init_vhost(c, ssl, NULL);
|
||||
|
||||
return (status == APR_SUCCESS)? SSL_TLSEXT_ERR_OK : SSL_TLSEXT_ERR_NOACK;
|
||||
}
|
||||
|
||||
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER)
|
||||
+/*
|
||||
+ * This callback function is called when the ClientHello is received.
|
||||
+ */
|
||||
+int ssl_callback_ClientHello(SSL *ssl, int *al, void *arg)
|
||||
+{
|
||||
+ char *servername = NULL;
|
||||
+ conn_rec *c = (conn_rec *)SSL_get_app_data(ssl);
|
||||
+ const unsigned char *pos;
|
||||
+ size_t len, remaining;
|
||||
+ (void)arg;
|
||||
+
|
||||
+ /* We can't use SSL_get_servername() at this earliest OpenSSL connection
|
||||
+ * stage, and there is no SSL_client_hello_get0_servername() provided as
|
||||
+ * of OpenSSL 1.1.1. So the code below, that extracts the SNI from the
|
||||
+ * ClientHello's TLS extensions, is taken from some test code in OpenSSL,
|
||||
+ * i.e. client_hello_select_server_ctx() in "test/handshake_helper.c".
|
||||
+ */
|
||||
+
|
||||
+ /*
|
||||
+ * The server_name extension was given too much extensibility when it
|
||||
+ * was written, so parsing the normal case is a bit complex.
|
||||
+ */
|
||||
+ if (!SSL_client_hello_get0_ext(ssl, TLSEXT_TYPE_server_name, &pos,
|
||||
+ &remaining)
|
||||
+ || remaining <= 2)
|
||||
+ goto give_up;
|
||||
+
|
||||
+ /* Extract the length of the supplied list of names. */
|
||||
+ len = (*(pos++) << 8);
|
||||
+ len += *(pos++);
|
||||
+ if (len + 2 != remaining)
|
||||
+ goto give_up;
|
||||
+ remaining = len;
|
||||
+
|
||||
+ /*
|
||||
+ * The list in practice only has a single element, so we only consider
|
||||
+ * the first one.
|
||||
+ */
|
||||
+ if (remaining <= 3 || *pos++ != TLSEXT_NAMETYPE_host_name)
|
||||
+ goto give_up;
|
||||
+ remaining--;
|
||||
+
|
||||
+ /* Now we can finally pull out the byte array with the actual hostname. */
|
||||
+ len = (*(pos++) << 8);
|
||||
+ len += *(pos++);
|
||||
+ if (len + 2 != remaining)
|
||||
+ goto give_up;
|
||||
+
|
||||
+ /* Use the SNI to switch to the relevant vhost, should it differ from
|
||||
+ * c->base_server.
|
||||
+ */
|
||||
+ servername = apr_pstrmemdup(c->pool, (const char *)pos, len);
|
||||
+
|
||||
+give_up:
|
||||
+ init_vhost(c, ssl, servername);
|
||||
+ return SSL_CLIENT_HELLO_SUCCESS;
|
||||
+}
|
||||
+#endif /* OPENSSL_VERSION_NUMBER < 0x10101000L */
|
||||
+
|
||||
+
|
||||
/*
|
||||
* Find a (name-based) SSL virtual host where either the ServerName
|
||||
* or one of the ServerAliases matches the supplied name (to be used
|
||||
@@ -2452,12 +2516,25 @@ static int ssl_find_vhost(void *servername, conn_rec *c, server_rec *s)
|
||||
if (found && (ssl = sslcon->ssl) &&
|
||||
(sc = mySrvConfig(s))) {
|
||||
SSL_CTX *ctx = SSL_set_SSL_CTX(ssl, sc->server->ssl_ctx);
|
||||
+
|
||||
/*
|
||||
* SSL_set_SSL_CTX() only deals with the server cert,
|
||||
* so we need to duplicate a few additional settings
|
||||
* from the ctx by hand
|
||||
*/
|
||||
SSL_set_options(ssl, SSL_CTX_get_options(ctx));
|
||||
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L \
|
||||
+ && (!defined(LIBRESSL_VERSION_NUMBER) \
|
||||
+ || LIBRESSL_VERSION_NUMBER >= 0x20800000L)
|
||||
+ /*
|
||||
+ * Don't switch the protocol if none is configured for this vhost,
|
||||
+ * the default in this case is still the base server's SSLProtocol.
|
||||
+ */
|
||||
+ if (myCtxConfig(sslcon, sc)->protocol_set) {
|
||||
+ SSL_set_min_proto_version(ssl, SSL_CTX_get_min_proto_version(ctx));
|
||||
+ SSL_set_max_proto_version(ssl, SSL_CTX_get_max_proto_version(ctx));
|
||||
+ }
|
||||
+#endif
|
||||
if ((SSL_get_verify_mode(ssl) == SSL_VERIFY_NONE) ||
|
||||
(SSL_num_renegotiations(ssl) == 0)) {
|
||||
/*
|
||||
@@ -2654,7 +2731,7 @@ int ssl_callback_alpn_select(SSL *ssl,
|
||||
* they callback the SNI. We need to make sure that we know which vhost
|
||||
* we are dealing with so we respect the correct protocols.
|
||||
*/
|
||||
- init_vhost(c, ssl);
|
||||
+ init_vhost(c, ssl, NULL);
|
||||
|
||||
proposed = ap_select_protocol(c, NULL, sslconn->server, client_protos);
|
||||
if (!proposed) {
|
||||
diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h
|
||||
index 8055200..f8a1db7 100644
|
||||
--- a/modules/ssl/ssl_private.h
|
||||
+++ b/modules/ssl/ssl_private.h
|
||||
@@ -563,6 +563,7 @@ typedef struct {
|
||||
|
||||
const char *cipher_suite; /* cipher suite used in last reneg */
|
||||
int service_unavailable; /* thouugh we negotiate SSL, no requests will be served */
|
||||
+ int vhost_found; /* whether we found vhost from SNI already */
|
||||
} SSLConnRec;
|
||||
|
||||
/* BIG FAT WARNING: SSLModConfigRec has unusual memory lifetime: it is
|
||||
@@ -946,6 +947,9 @@ void ssl_callback_Info(const SSL *, int, int);
|
||||
#ifdef HAVE_TLSEXT
|
||||
int ssl_callback_ServerNameIndication(SSL *, int *, modssl_ctx_t *);
|
||||
#endif
|
||||
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER)
|
||||
+int ssl_callback_ClientHello(SSL *, int *, void *);
|
||||
+#endif
|
||||
#ifdef HAVE_TLS_SESSION_TICKETS
|
||||
int ssl_callback_SessionTicket(SSL *, unsigned char *, unsigned char *,
|
||||
EVP_CIPHER_CTX *, HMAC_CTX *, int);
|
@ -1,47 +0,0 @@
|
||||
From ced24e032ebe185a2d885fa309d6de47668ba31e Mon Sep 17 00:00:00 2001
|
||||
From: Yann Ylavic <ylavic@apache.org>
|
||||
Date: Fri, 26 Jun 2020 10:21:19 +0000
|
||||
Subject: [PATCH] Merge r1878280 from trunk:
|
||||
|
||||
mod_proxy_http: don't strip EOS when spooling request body to file.
|
||||
|
||||
To prevent stream_reqbody() from sending the FILE and FLUSH bucket in separate
|
||||
brigades, and thus apr_file_setaside() to trigger if network congestion occurs
|
||||
with the backend, restore the EOS in spool_reqbody_cl() which was stripped
|
||||
when spooling the request body to a file.
|
||||
|
||||
Until APR r1878279 is released (and installed by users), apr_file_setaside()
|
||||
on a temporary file (mktemp) will simply drop the file cleanup, leaking the
|
||||
fd and inode..
|
||||
|
||||
This fixes BZ 64452.
|
||||
|
||||
|
||||
Submitted by: ylavic
|
||||
Reviewed by: ylavic, jorton, rpluem
|
||||
|
||||
|
||||
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1879226 13f79535-47bb-0310-9956-ffa450edef68
|
||||
---
|
||||
modules/proxy/mod_proxy_http.c | 8 ++++++++
|
||||
1 file changed, 8 insertions(+)
|
||||
|
||||
diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c
|
||||
index e94bf26d412..7a0f063f705 100644
|
||||
--- a/modules/proxy/mod_proxy_http.c
|
||||
+++ b/modules/proxy/mod_proxy_http.c
|
||||
@@ -548,6 +548,14 @@ static int spool_reqbody_cl(proxy_http_req_t *req, apr_off_t *bytes_spooled)
|
||||
e = apr_bucket_immortal_create(CRLF_ASCII, 2, bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(input_brigade, e);
|
||||
}
|
||||
+ if (tmpfile) {
|
||||
+ /* We dropped metadata buckets when spooling to tmpfile,
|
||||
+ * terminate with EOS for stream_reqbody() to flush the
|
||||
+ * whole in one go.
|
||||
+ */
|
||||
+ e = apr_bucket_eos_create(bucket_alloc);
|
||||
+ APR_BRIGADE_INSERT_TAIL(input_brigade, e);
|
||||
+ }
|
||||
return OK;
|
||||
}
|
||||
|
@ -1,13 +0,0 @@
|
||||
diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c
|
||||
index c217a0d..d07d0ba 100644
|
||||
--- a/modules/ssl/ssl_engine_kernel.c
|
||||
+++ b/modules/ssl/ssl_engine_kernel.c
|
||||
@@ -1947,7 +1947,7 @@ static void modssl_proxy_info_log(conn_rec *c,
|
||||
*cert = info->x509; \
|
||||
CRYPTO_add(&(*cert)->references, +1, CRYPTO_LOCK_X509); \
|
||||
*pkey = info->x_pkey->dec_pkey; \
|
||||
- CRYPTO_add(&(*pkey)->references, +1, CRYPTO_LOCK_X509_PKEY)
|
||||
+ CRYPTO_add(&(*pkey)->references, +1, CRYPTO_LOCK_EVP_PKEY)
|
||||
#else
|
||||
#define modssl_set_cert_info(info, cert, pkey) \
|
||||
*cert = info->x509; \
|
@ -1,16 +0,0 @@
|
||||
--- a/modules/generators/cgi_common.h 2020/09/04 13:16:53 1881458
|
||||
+++ b/modules/generators/cgi_common.h 2020/09/04 13:56:25 1881459
|
||||
@@ -259,6 +259,13 @@
|
||||
if ((ret = ap_scan_script_header_err_brigade_ex(r, bb, sbuf,
|
||||
APLOG_MODULE_INDEX)))
|
||||
{
|
||||
+ /* In the case of a timeout reading script output, clear
|
||||
+ * the brigade to avoid a second attempt to read the
|
||||
+ * output. */
|
||||
+ if (ret == HTTP_GATEWAY_TIME_OUT) {
|
||||
+ apr_brigade_cleanup(bb);
|
||||
+ }
|
||||
+
|
||||
ret = log_script(r, conf, ret, logdata, sbuf, bb, script_err);
|
||||
|
||||
/*
|
@ -1,849 +0,0 @@
|
||||
diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h
|
||||
index fbbd508..8fcd26d 100644
|
||||
--- a/modules/proxy/mod_proxy.h
|
||||
+++ b/modules/proxy/mod_proxy.h
|
||||
@@ -1168,6 +1168,55 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p,
|
||||
char **old_cl_val,
|
||||
char **old_te_val);
|
||||
|
||||
+/**
|
||||
+ * Prefetch the client request body (in memory), up to a limit.
|
||||
+ * Read what's in the client pipe. If nonblocking is set and read is EAGAIN,
|
||||
+ * pass a FLUSH bucket to the backend and read again in blocking mode.
|
||||
+ * @param r client request
|
||||
+ * @param backend backend connection
|
||||
+ * @param input_brigade input brigade to use/fill
|
||||
+ * @param block blocking or non-blocking mode
|
||||
+ * @param bytes_read number of bytes read
|
||||
+ * @param max_read maximum number of bytes to read
|
||||
+ * @return OK or HTTP_* error code
|
||||
+ * @note max_read is rounded up to APR_BUCKET_BUFF_SIZE
|
||||
+ */
|
||||
+PROXY_DECLARE(int) ap_proxy_prefetch_input(request_rec *r,
|
||||
+ proxy_conn_rec *backend,
|
||||
+ apr_bucket_brigade *input_brigade,
|
||||
+ apr_read_type_e block,
|
||||
+ apr_off_t *bytes_read,
|
||||
+ apr_off_t max_read);
|
||||
+
|
||||
+/**
|
||||
+ * Spool the client request body to memory, or disk above given limit.
|
||||
+ * @param r client request
|
||||
+ * @param backend backend connection
|
||||
+ * @param input_brigade input brigade to use/fill
|
||||
+ * @param bytes_spooled number of bytes spooled
|
||||
+ * @param max_mem_spool maximum number of in-memory bytes
|
||||
+ * @return OK or HTTP_* error code
|
||||
+ */
|
||||
+PROXY_DECLARE(int) ap_proxy_spool_input(request_rec *r,
|
||||
+ proxy_conn_rec *backend,
|
||||
+ apr_bucket_brigade *input_brigade,
|
||||
+ apr_off_t *bytes_spooled,
|
||||
+ apr_off_t max_mem_spool);
|
||||
+
|
||||
+/**
|
||||
+ * Read what's in the client pipe. If the read would block (EAGAIN),
|
||||
+ * pass a FLUSH bucket to the backend and read again in blocking mode.
|
||||
+ * @param r client request
|
||||
+ * @param backend backend connection
|
||||
+ * @param input_brigade brigade to use/fill
|
||||
+ * @param max_read maximum number of bytes to read
|
||||
+ * @return OK or HTTP_* error code
|
||||
+ */
|
||||
+PROXY_DECLARE(int) ap_proxy_read_input(request_rec *r,
|
||||
+ proxy_conn_rec *backend,
|
||||
+ apr_bucket_brigade *input_brigade,
|
||||
+ apr_off_t max_read);
|
||||
+
|
||||
/**
|
||||
* @param bucket_alloc bucket allocator
|
||||
* @param r request
|
||||
diff --git a/modules/proxy/mod_proxy_fcgi.c b/modules/proxy/mod_proxy_fcgi.c
|
||||
index 2e97408..f9cf716 100644
|
||||
--- a/modules/proxy/mod_proxy_fcgi.c
|
||||
+++ b/modules/proxy/mod_proxy_fcgi.c
|
||||
@@ -521,7 +521,8 @@ static int handle_headers(request_rec *r, int *state,
|
||||
static apr_status_t dispatch(proxy_conn_rec *conn, proxy_dir_conf *conf,
|
||||
request_rec *r, apr_pool_t *setaside_pool,
|
||||
apr_uint16_t request_id, const char **err,
|
||||
- int *bad_request, int *has_responded)
|
||||
+ int *bad_request, int *has_responded,
|
||||
+ apr_bucket_brigade *input_brigade)
|
||||
{
|
||||
apr_bucket_brigade *ib, *ob;
|
||||
int seen_end_of_headers = 0, done = 0, ignore_body = 0;
|
||||
@@ -583,9 +584,26 @@ static apr_status_t dispatch(proxy_conn_rec *conn, proxy_dir_conf *conf,
|
||||
int last_stdin = 0;
|
||||
char *iobuf_cursor;
|
||||
|
||||
- rv = ap_get_brigade(r->input_filters, ib,
|
||||
- AP_MODE_READBYTES, APR_BLOCK_READ,
|
||||
- iobuf_size);
|
||||
+ if (APR_BRIGADE_EMPTY(input_brigade)) {
|
||||
+ rv = ap_get_brigade(r->input_filters, ib,
|
||||
+ AP_MODE_READBYTES, APR_BLOCK_READ,
|
||||
+ iobuf_size);
|
||||
+ }
|
||||
+ else {
|
||||
+ apr_bucket *e;
|
||||
+ APR_BRIGADE_CONCAT(ib, input_brigade);
|
||||
+ rv = apr_brigade_partition(ib, iobuf_size, &e);
|
||||
+ if (rv == APR_SUCCESS) {
|
||||
+ while (e != APR_BRIGADE_SENTINEL(ib)
|
||||
+ && APR_BUCKET_IS_METADATA(e)) {
|
||||
+ e = APR_BUCKET_NEXT(e);
|
||||
+ }
|
||||
+ apr_brigade_split_ex(ib, e, input_brigade);
|
||||
+ }
|
||||
+ else if (rv == APR_INCOMPLETE) {
|
||||
+ rv = APR_SUCCESS;
|
||||
+ }
|
||||
+ }
|
||||
if (rv != APR_SUCCESS) {
|
||||
*err = "reading input brigade";
|
||||
*bad_request = 1;
|
||||
@@ -924,7 +942,8 @@ static int fcgi_do_request(apr_pool_t *p, request_rec *r,
|
||||
conn_rec *origin,
|
||||
proxy_dir_conf *conf,
|
||||
apr_uri_t *uri,
|
||||
- char *url, char *server_portstr)
|
||||
+ char *url, char *server_portstr,
|
||||
+ apr_bucket_brigade *input_brigade)
|
||||
{
|
||||
/* Request IDs are arbitrary numbers that we assign to a
|
||||
* single request. This would allow multiplex/pipelining of
|
||||
@@ -960,7 +979,8 @@ static int fcgi_do_request(apr_pool_t *p, request_rec *r,
|
||||
|
||||
/* Step 3: Read records from the back end server and handle them. */
|
||||
rv = dispatch(conn, conf, r, temp_pool, request_id,
|
||||
- &err, &bad_request, &has_responded);
|
||||
+ &err, &bad_request, &has_responded,
|
||||
+ input_brigade);
|
||||
if (rv != APR_SUCCESS) {
|
||||
/* If the client aborted the connection during retrieval or (partially)
|
||||
* sending the response, don't return a HTTP_SERVICE_UNAVAILABLE, since
|
||||
@@ -996,6 +1016,8 @@ static int fcgi_do_request(apr_pool_t *p, request_rec *r,
|
||||
|
||||
#define FCGI_SCHEME "FCGI"
|
||||
|
||||
+#define MAX_MEM_SPOOL 16384
|
||||
+
|
||||
/*
|
||||
* This handles fcgi:(dest) URLs
|
||||
*/
|
||||
@@ -1008,6 +1030,8 @@ static int proxy_fcgi_handler(request_rec *r, proxy_worker *worker,
|
||||
char server_portstr[32];
|
||||
conn_rec *origin = NULL;
|
||||
proxy_conn_rec *backend = NULL;
|
||||
+ apr_bucket_brigade *input_brigade;
|
||||
+ apr_off_t input_bytes = 0;
|
||||
apr_uri_t *uri;
|
||||
|
||||
proxy_dir_conf *dconf = ap_get_module_config(r->per_dir_config,
|
||||
@@ -1050,6 +1074,101 @@ static int proxy_fcgi_handler(request_rec *r, proxy_worker *worker,
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
+ /* We possibly reuse input data prefetched in previous call(s), e.g. for a
|
||||
+ * balancer fallback scenario.
|
||||
+ */
|
||||
+ apr_pool_userdata_get((void **)&input_brigade, "proxy-fcgi-input", p);
|
||||
+ if (input_brigade == NULL) {
|
||||
+ const char *old_te = apr_table_get(r->headers_in, "Transfer-Encoding");
|
||||
+ const char *old_cl = NULL;
|
||||
+ if (old_te) {
|
||||
+ apr_table_unset(r->headers_in, "Content-Length");
|
||||
+ }
|
||||
+ else {
|
||||
+ old_cl = apr_table_get(r->headers_in, "Content-Length");
|
||||
+ }
|
||||
+
|
||||
+ input_brigade = apr_brigade_create(p, r->connection->bucket_alloc);
|
||||
+ apr_pool_userdata_setn(input_brigade, "proxy-fcgi-input", NULL, p);
|
||||
+
|
||||
+ /* Prefetch (nonlocking) the request body so to increase the chance
|
||||
+ * to get the whole (or enough) body and determine Content-Length vs
|
||||
+ * chunked or spooled. By doing this before connecting or reusing the
|
||||
+ * backend, we want to minimize the delay between this connection is
|
||||
+ * considered alive and the first bytes sent (should the client's link
|
||||
+ * be slow or some input filter retain the data). This is a best effort
|
||||
+ * to prevent the backend from closing (from under us) what it thinks is
|
||||
+ * an idle connection, hence to reduce to the minimum the unavoidable
|
||||
+ * local is_socket_connected() vs remote keepalive race condition.
|
||||
+ */
|
||||
+ status = ap_proxy_prefetch_input(r, backend, input_brigade,
|
||||
+ APR_NONBLOCK_READ, &input_bytes,
|
||||
+ MAX_MEM_SPOOL);
|
||||
+ if (status != OK) {
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * The request body is streamed by default, using either C-L or
|
||||
+ * chunked T-E, like this:
|
||||
+ *
|
||||
+ * The whole body (including no body) was received on prefetch, i.e.
|
||||
+ * the input brigade ends with EOS => C-L = input_bytes.
|
||||
+ *
|
||||
+ * C-L is known and reliable, i.e. only protocol filters in the input
|
||||
+ * chain thus none should change the body => use C-L from client.
|
||||
+ *
|
||||
+ * The administrator has not "proxy-sendcl" which prevents T-E => use
|
||||
+ * T-E and chunks.
|
||||
+ *
|
||||
+ * Otherwise we need to determine and set a content-length, so spool
|
||||
+ * the entire request body to memory/temporary file (MAX_MEM_SPOOL),
|
||||
+ * such that we finally know its length => C-L = input_bytes.
|
||||
+ */
|
||||
+ if (!APR_BRIGADE_EMPTY(input_brigade)
|
||||
+ && APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) {
|
||||
+ /* The whole thing fit, so our decision is trivial, use the input
|
||||
+ * bytes for the Content-Length. If we expected no body, and read
|
||||
+ * no body, do not set the Content-Length.
|
||||
+ */
|
||||
+ if (old_cl || old_te || input_bytes) {
|
||||
+ apr_table_setn(r->headers_in, "Content-Length",
|
||||
+ apr_off_t_toa(p, input_bytes));
|
||||
+ if (old_te) {
|
||||
+ apr_table_unset(r->headers_in, "Transfer-Encoding");
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ else if (old_cl && r->input_filters == r->proto_input_filters) {
|
||||
+ /* Streaming is possible by preserving the existing C-L */
|
||||
+ }
|
||||
+ else if (!apr_table_get(r->subprocess_env, "proxy-sendcl")) {
|
||||
+ /* Streaming is possible using T-E: chunked */
|
||||
+ }
|
||||
+ else {
|
||||
+ /* No streaming, C-L is the only option so spool to memory/file */
|
||||
+ apr_bucket_brigade *tmp_bb;
|
||||
+ apr_off_t remaining_bytes = 0;
|
||||
+
|
||||
+ AP_DEBUG_ASSERT(MAX_MEM_SPOOL >= input_bytes);
|
||||
+ tmp_bb = apr_brigade_create(p, r->connection->bucket_alloc);
|
||||
+ status = ap_proxy_spool_input(r, backend, tmp_bb, &remaining_bytes,
|
||||
+ MAX_MEM_SPOOL - input_bytes);
|
||||
+ if (status != OK) {
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+
|
||||
+ APR_BRIGADE_CONCAT(input_brigade, tmp_bb);
|
||||
+ input_bytes += remaining_bytes;
|
||||
+
|
||||
+ apr_table_setn(r->headers_in, "Content-Length",
|
||||
+ apr_off_t_toa(p, input_bytes));
|
||||
+ if (old_te) {
|
||||
+ apr_table_unset(r->headers_in, "Transfer-Encoding");
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
/* This scheme handler does not reuse connections by default, to
|
||||
* avoid tying up a fastcgi that isn't expecting to work on
|
||||
* parallel requests. But if the user went out of their way to
|
||||
@@ -1074,7 +1193,7 @@ static int proxy_fcgi_handler(request_rec *r, proxy_worker *worker,
|
||||
|
||||
/* Step Three: Process the Request */
|
||||
status = fcgi_do_request(p, r, backend, origin, dconf, uri, url,
|
||||
- server_portstr);
|
||||
+ server_portstr, input_brigade);
|
||||
|
||||
cleanup:
|
||||
ap_proxy_release_connection(FCGI_SCHEME, backend, r->server);
|
||||
diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c
|
||||
index df10997..7f67f26 100644
|
||||
--- a/modules/proxy/mod_proxy_http.c
|
||||
+++ b/modules/proxy/mod_proxy_http.c
|
||||
@@ -266,50 +266,6 @@ typedef struct {
|
||||
prefetch_nonblocking:1;
|
||||
} proxy_http_req_t;
|
||||
|
||||
-/* Read what's in the client pipe. If nonblocking is set and read is EAGAIN,
|
||||
- * pass a FLUSH bucket to the backend and read again in blocking mode.
|
||||
- */
|
||||
-static int stream_reqbody_read(proxy_http_req_t *req, apr_bucket_brigade *bb,
|
||||
- int nonblocking)
|
||||
-{
|
||||
- request_rec *r = req->r;
|
||||
- proxy_conn_rec *p_conn = req->backend;
|
||||
- apr_bucket_alloc_t *bucket_alloc = req->bucket_alloc;
|
||||
- apr_read_type_e block = nonblocking ? APR_NONBLOCK_READ : APR_BLOCK_READ;
|
||||
- apr_status_t status;
|
||||
- int rv;
|
||||
-
|
||||
- for (;;) {
|
||||
- status = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES,
|
||||
- block, HUGE_STRING_LEN);
|
||||
- if (block == APR_BLOCK_READ
|
||||
- || (!APR_STATUS_IS_EAGAIN(status)
|
||||
- && (status != APR_SUCCESS || !APR_BRIGADE_EMPTY(bb)))) {
|
||||
- break;
|
||||
- }
|
||||
-
|
||||
- /* Flush and retry (blocking) */
|
||||
- apr_brigade_cleanup(bb);
|
||||
- rv = ap_proxy_pass_brigade(bucket_alloc, r, p_conn, req->origin, bb, 1);
|
||||
- if (rv != OK) {
|
||||
- return rv;
|
||||
- }
|
||||
- block = APR_BLOCK_READ;
|
||||
- }
|
||||
-
|
||||
- if (status != APR_SUCCESS) {
|
||||
- conn_rec *c = r->connection;
|
||||
- ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(02608)
|
||||
- "read request body failed to %pI (%s)"
|
||||
- " from %s (%s)", p_conn->addr,
|
||||
- p_conn->hostname ? p_conn->hostname: "",
|
||||
- c->client_ip, c->remote_host ? c->remote_host: "");
|
||||
- return ap_map_http_request_error(status, HTTP_BAD_REQUEST);
|
||||
- }
|
||||
-
|
||||
- return OK;
|
||||
-}
|
||||
-
|
||||
static int stream_reqbody(proxy_http_req_t *req)
|
||||
{
|
||||
request_rec *r = req->r;
|
||||
@@ -328,7 +284,8 @@ static int stream_reqbody(proxy_http_req_t *req)
|
||||
do {
|
||||
if (APR_BRIGADE_EMPTY(input_brigade)
|
||||
&& APR_BRIGADE_EMPTY(header_brigade)) {
|
||||
- rv = stream_reqbody_read(req, input_brigade, 1);
|
||||
+ rv = ap_proxy_read_input(r, p_conn, input_brigade,
|
||||
+ HUGE_STRING_LEN);
|
||||
if (rv != OK) {
|
||||
return rv;
|
||||
}
|
||||
@@ -409,7 +366,7 @@ static int stream_reqbody(proxy_http_req_t *req)
|
||||
*/
|
||||
APR_BRIGADE_PREPEND(input_brigade, header_brigade);
|
||||
|
||||
- /* Flush here on EOS because we won't stream_reqbody_read() again */
|
||||
+ /* Flush here on EOS because we won't ap_proxy_read_input() again. */
|
||||
rv = ap_proxy_pass_brigade(bucket_alloc, r, p_conn, origin,
|
||||
input_brigade, seen_eos);
|
||||
if (rv != OK) {
|
||||
@@ -427,137 +384,6 @@ static int stream_reqbody(proxy_http_req_t *req)
|
||||
return OK;
|
||||
}
|
||||
|
||||
-static int spool_reqbody_cl(proxy_http_req_t *req, apr_off_t *bytes_spooled)
|
||||
-{
|
||||
- apr_pool_t *p = req->p;
|
||||
- request_rec *r = req->r;
|
||||
- int seen_eos = 0, rv = OK;
|
||||
- apr_status_t status = APR_SUCCESS;
|
||||
- apr_bucket_alloc_t *bucket_alloc = req->bucket_alloc;
|
||||
- apr_bucket_brigade *input_brigade = req->input_brigade;
|
||||
- apr_bucket_brigade *body_brigade;
|
||||
- apr_bucket *e;
|
||||
- apr_off_t bytes, fsize = 0;
|
||||
- apr_file_t *tmpfile = NULL;
|
||||
- apr_off_t limit;
|
||||
-
|
||||
- body_brigade = apr_brigade_create(p, bucket_alloc);
|
||||
- *bytes_spooled = 0;
|
||||
-
|
||||
- limit = ap_get_limit_req_body(r);
|
||||
-
|
||||
- do {
|
||||
- if (APR_BRIGADE_EMPTY(input_brigade)) {
|
||||
- rv = stream_reqbody_read(req, input_brigade, 0);
|
||||
- if (rv != OK) {
|
||||
- return rv;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- /* If this brigade contains EOS, either stop or remove it. */
|
||||
- if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) {
|
||||
- seen_eos = 1;
|
||||
- }
|
||||
-
|
||||
- apr_brigade_length(input_brigade, 1, &bytes);
|
||||
-
|
||||
- if (*bytes_spooled + bytes > MAX_MEM_SPOOL) {
|
||||
- /*
|
||||
- * LimitRequestBody does not affect Proxy requests (Should it?).
|
||||
- * Let it take effect if we decide to store the body in a
|
||||
- * temporary file on disk.
|
||||
- */
|
||||
- if (limit && (*bytes_spooled + bytes > limit)) {
|
||||
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01088)
|
||||
- "Request body is larger than the configured "
|
||||
- "limit of %" APR_OFF_T_FMT, limit);
|
||||
- return HTTP_REQUEST_ENTITY_TOO_LARGE;
|
||||
- }
|
||||
- /* can't spool any more in memory; write latest brigade to disk */
|
||||
- if (tmpfile == NULL) {
|
||||
- const char *temp_dir;
|
||||
- char *template;
|
||||
-
|
||||
- status = apr_temp_dir_get(&temp_dir, p);
|
||||
- if (status != APR_SUCCESS) {
|
||||
- ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01089)
|
||||
- "search for temporary directory failed");
|
||||
- return HTTP_INTERNAL_SERVER_ERROR;
|
||||
- }
|
||||
- apr_filepath_merge(&template, temp_dir,
|
||||
- "modproxy.tmp.XXXXXX",
|
||||
- APR_FILEPATH_NATIVE, p);
|
||||
- status = apr_file_mktemp(&tmpfile, template, 0, p);
|
||||
- if (status != APR_SUCCESS) {
|
||||
- ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01090)
|
||||
- "creation of temporary file in directory "
|
||||
- "%s failed", temp_dir);
|
||||
- return HTTP_INTERNAL_SERVER_ERROR;
|
||||
- }
|
||||
- }
|
||||
- for (e = APR_BRIGADE_FIRST(input_brigade);
|
||||
- e != APR_BRIGADE_SENTINEL(input_brigade);
|
||||
- e = APR_BUCKET_NEXT(e)) {
|
||||
- const char *data;
|
||||
- apr_size_t bytes_read, bytes_written;
|
||||
-
|
||||
- apr_bucket_read(e, &data, &bytes_read, APR_BLOCK_READ);
|
||||
- status = apr_file_write_full(tmpfile, data, bytes_read, &bytes_written);
|
||||
- if (status != APR_SUCCESS) {
|
||||
- const char *tmpfile_name;
|
||||
-
|
||||
- if (apr_file_name_get(&tmpfile_name, tmpfile) != APR_SUCCESS) {
|
||||
- tmpfile_name = "(unknown)";
|
||||
- }
|
||||
- ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01091)
|
||||
- "write to temporary file %s failed",
|
||||
- tmpfile_name);
|
||||
- return HTTP_INTERNAL_SERVER_ERROR;
|
||||
- }
|
||||
- AP_DEBUG_ASSERT(bytes_read == bytes_written);
|
||||
- fsize += bytes_written;
|
||||
- }
|
||||
- apr_brigade_cleanup(input_brigade);
|
||||
- }
|
||||
- else {
|
||||
-
|
||||
- /*
|
||||
- * Save input_brigade in body_brigade. (At least) in the SSL case
|
||||
- * input_brigade contains transient buckets whose data would get
|
||||
- * overwritten during the next call of ap_get_brigade in the loop.
|
||||
- * ap_save_brigade ensures these buckets to be set aside.
|
||||
- * Calling ap_save_brigade with NULL as filter is OK, because
|
||||
- * body_brigade already has been created and does not need to get
|
||||
- * created by ap_save_brigade.
|
||||
- */
|
||||
- status = ap_save_brigade(NULL, &body_brigade, &input_brigade, p);
|
||||
- if (status != APR_SUCCESS) {
|
||||
- return HTTP_INTERNAL_SERVER_ERROR;
|
||||
- }
|
||||
-
|
||||
- }
|
||||
-
|
||||
- *bytes_spooled += bytes;
|
||||
- } while (!seen_eos);
|
||||
-
|
||||
- APR_BRIGADE_CONCAT(input_brigade, body_brigade);
|
||||
- if (tmpfile) {
|
||||
- apr_brigade_insert_file(input_brigade, tmpfile, 0, fsize, p);
|
||||
- }
|
||||
- if (apr_table_get(r->subprocess_env, "proxy-sendextracrlf")) {
|
||||
- e = apr_bucket_immortal_create(CRLF_ASCII, 2, bucket_alloc);
|
||||
- APR_BRIGADE_INSERT_TAIL(input_brigade, e);
|
||||
- }
|
||||
- if (tmpfile) {
|
||||
- /* We dropped metadata buckets when spooling to tmpfile,
|
||||
- * terminate with EOS for stream_reqbody() to flush the
|
||||
- * whole in one go.
|
||||
- */
|
||||
- e = apr_bucket_eos_create(bucket_alloc);
|
||||
- APR_BRIGADE_INSERT_TAIL(input_brigade, e);
|
||||
- }
|
||||
- return OK;
|
||||
-}
|
||||
|
||||
static int ap_proxy_http_prefetch(proxy_http_req_t *req,
|
||||
apr_uri_t *uri, char *url)
|
||||
@@ -569,14 +395,12 @@ static int ap_proxy_http_prefetch(proxy_http_req_t *req,
|
||||
apr_bucket_alloc_t *bucket_alloc = req->bucket_alloc;
|
||||
apr_bucket_brigade *header_brigade = req->header_brigade;
|
||||
apr_bucket_brigade *input_brigade = req->input_brigade;
|
||||
- apr_bucket_brigade *temp_brigade;
|
||||
apr_bucket *e;
|
||||
- char *buf;
|
||||
apr_status_t status;
|
||||
+ char *buf;
|
||||
apr_off_t bytes_read = 0;
|
||||
apr_off_t bytes;
|
||||
int force10, rv;
|
||||
- apr_read_type_e block;
|
||||
conn_rec *origin = p_conn->connection;
|
||||
|
||||
if (apr_table_get(r->subprocess_env, "force-proxy-request-1.0")) {
|
||||
@@ -641,69 +465,12 @@ static int ap_proxy_http_prefetch(proxy_http_req_t *req,
|
||||
p_conn->close = 1;
|
||||
}
|
||||
|
||||
- /* Prefetch MAX_MEM_SPOOL bytes
|
||||
- *
|
||||
- * This helps us avoid any election of C-L v.s. T-E
|
||||
- * request bodies, since we are willing to keep in
|
||||
- * memory this much data, in any case. This gives
|
||||
- * us an instant C-L election if the body is of some
|
||||
- * reasonable size.
|
||||
- */
|
||||
- temp_brigade = apr_brigade_create(p, bucket_alloc);
|
||||
- block = req->prefetch_nonblocking ? APR_NONBLOCK_READ : APR_BLOCK_READ;
|
||||
-
|
||||
- /* Account for saved input, if any. */
|
||||
- apr_brigade_length(input_brigade, 0, &bytes_read);
|
||||
-
|
||||
- /* Ensure we don't hit a wall where we have a buffer too small
|
||||
- * for ap_get_brigade's filters to fetch us another bucket,
|
||||
- * surrender once we hit 80 bytes less than MAX_MEM_SPOOL
|
||||
- * (an arbitrary value).
|
||||
- */
|
||||
- while (bytes_read < MAX_MEM_SPOOL - 80
|
||||
- && (APR_BRIGADE_EMPTY(input_brigade)
|
||||
- || !APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade)))) {
|
||||
- status = ap_get_brigade(r->input_filters, temp_brigade,
|
||||
- AP_MODE_READBYTES, block,
|
||||
- MAX_MEM_SPOOL - bytes_read);
|
||||
- /* ap_get_brigade may return success with an empty brigade
|
||||
- * for a non-blocking read which would block
|
||||
- */
|
||||
- if (block == APR_NONBLOCK_READ
|
||||
- && ((status == APR_SUCCESS && APR_BRIGADE_EMPTY(temp_brigade))
|
||||
- || APR_STATUS_IS_EAGAIN(status))) {
|
||||
- break;
|
||||
- }
|
||||
- if (status != APR_SUCCESS) {
|
||||
- ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01095)
|
||||
- "prefetch request body failed to %pI (%s)"
|
||||
- " from %s (%s)",
|
||||
- p_conn->addr, p_conn->hostname ? p_conn->hostname: "",
|
||||
- c->client_ip, c->remote_host ? c->remote_host: "");
|
||||
- return ap_map_http_request_error(status, HTTP_BAD_REQUEST);
|
||||
- }
|
||||
-
|
||||
- apr_brigade_length(temp_brigade, 1, &bytes);
|
||||
- bytes_read += bytes;
|
||||
-
|
||||
- /*
|
||||
- * Save temp_brigade in input_brigade. (At least) in the SSL case
|
||||
- * temp_brigade contains transient buckets whose data would get
|
||||
- * overwritten during the next call of ap_get_brigade in the loop.
|
||||
- * ap_save_brigade ensures these buckets to be set aside.
|
||||
- * Calling ap_save_brigade with NULL as filter is OK, because
|
||||
- * input_brigade already has been created and does not need to get
|
||||
- * created by ap_save_brigade.
|
||||
- */
|
||||
- status = ap_save_brigade(NULL, &input_brigade, &temp_brigade, p);
|
||||
- if (status != APR_SUCCESS) {
|
||||
- ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01096)
|
||||
- "processing prefetched request body failed"
|
||||
- " to %pI (%s) from %s (%s)",
|
||||
- p_conn->addr, p_conn->hostname ? p_conn->hostname: "",
|
||||
- c->client_ip, c->remote_host ? c->remote_host: "");
|
||||
- return HTTP_INTERNAL_SERVER_ERROR;
|
||||
- }
|
||||
+ rv = ap_proxy_prefetch_input(r, req->backend, input_brigade,
|
||||
+ req->prefetch_nonblocking ? APR_NONBLOCK_READ
|
||||
+ : APR_BLOCK_READ,
|
||||
+ &bytes_read, MAX_MEM_SPOOL);
|
||||
+ if (rv != OK) {
|
||||
+ return rv;
|
||||
}
|
||||
|
||||
/* Use chunked request body encoding or send a content-length body?
|
||||
@@ -772,7 +539,7 @@ static int ap_proxy_http_prefetch(proxy_http_req_t *req,
|
||||
char *endstr;
|
||||
status = apr_strtoff(&req->cl_val, req->old_cl_val, &endstr, 10);
|
||||
if (status != APR_SUCCESS || *endstr || req->cl_val < 0) {
|
||||
- ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01085)
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01085)
|
||||
"could not parse request Content-Length (%s)",
|
||||
req->old_cl_val);
|
||||
return HTTP_BAD_REQUEST;
|
||||
@@ -812,7 +579,8 @@ static int ap_proxy_http_prefetch(proxy_http_req_t *req,
|
||||
/* If we have to spool the body, do it now, before connecting or
|
||||
* reusing the backend connection.
|
||||
*/
|
||||
- rv = spool_reqbody_cl(req, &bytes);
|
||||
+ rv = ap_proxy_spool_input(r, p_conn, input_brigade,
|
||||
+ &bytes, MAX_MEM_SPOOL);
|
||||
if (rv != OK) {
|
||||
return rv;
|
||||
}
|
||||
diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c
|
||||
index ab88d8f..973aa83 100644
|
||||
--- a/modules/proxy/proxy_util.c
|
||||
+++ b/modules/proxy/proxy_util.c
|
||||
@@ -3866,6 +3866,268 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p,
|
||||
return OK;
|
||||
}
|
||||
|
||||
+PROXY_DECLARE(int) ap_proxy_prefetch_input(request_rec *r,
|
||||
+ proxy_conn_rec *backend,
|
||||
+ apr_bucket_brigade *input_brigade,
|
||||
+ apr_read_type_e block,
|
||||
+ apr_off_t *bytes_read,
|
||||
+ apr_off_t max_read)
|
||||
+{
|
||||
+ apr_pool_t *p = r->pool;
|
||||
+ conn_rec *c = r->connection;
|
||||
+ apr_bucket_brigade *temp_brigade;
|
||||
+ apr_status_t status;
|
||||
+ apr_off_t bytes;
|
||||
+
|
||||
+ *bytes_read = 0;
|
||||
+ if (max_read < APR_BUCKET_BUFF_SIZE) {
|
||||
+ max_read = APR_BUCKET_BUFF_SIZE;
|
||||
+ }
|
||||
+
|
||||
+ /* Prefetch max_read bytes
|
||||
+ *
|
||||
+ * This helps us avoid any election of C-L v.s. T-E
|
||||
+ * request bodies, since we are willing to keep in
|
||||
+ * memory this much data, in any case. This gives
|
||||
+ * us an instant C-L election if the body is of some
|
||||
+ * reasonable size.
|
||||
+ */
|
||||
+ temp_brigade = apr_brigade_create(p, input_brigade->bucket_alloc);
|
||||
+
|
||||
+ /* Account for saved input, if any. */
|
||||
+ apr_brigade_length(input_brigade, 0, bytes_read);
|
||||
+
|
||||
+ /* Ensure we don't hit a wall where we have a buffer too small for
|
||||
+ * ap_get_brigade's filters to fetch us another bucket, surrender
|
||||
+ * once we hit 80 bytes (an arbitrary value) less than max_read.
|
||||
+ */
|
||||
+ while (*bytes_read < max_read - 80
|
||||
+ && (APR_BRIGADE_EMPTY(input_brigade)
|
||||
+ || !APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade)))) {
|
||||
+ status = ap_get_brigade(r->input_filters, temp_brigade,
|
||||
+ AP_MODE_READBYTES, block,
|
||||
+ max_read - *bytes_read);
|
||||
+ /* ap_get_brigade may return success with an empty brigade
|
||||
+ * for a non-blocking read which would block
|
||||
+ */
|
||||
+ if (block == APR_NONBLOCK_READ
|
||||
+ && ((status == APR_SUCCESS && APR_BRIGADE_EMPTY(temp_brigade))
|
||||
+ || APR_STATUS_IS_EAGAIN(status))) {
|
||||
+ break;
|
||||
+ }
|
||||
+ if (status != APR_SUCCESS) {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01095)
|
||||
+ "prefetch request body failed to %pI (%s)"
|
||||
+ " from %s (%s)", backend->addr,
|
||||
+ backend->hostname ? backend->hostname : "",
|
||||
+ c->client_ip, c->remote_host ? c->remote_host : "");
|
||||
+ return ap_map_http_request_error(status, HTTP_BAD_REQUEST);
|
||||
+ }
|
||||
+
|
||||
+ apr_brigade_length(temp_brigade, 1, &bytes);
|
||||
+ *bytes_read += bytes;
|
||||
+
|
||||
+ /*
|
||||
+ * Save temp_brigade in input_brigade. (At least) in the SSL case
|
||||
+ * temp_brigade contains transient buckets whose data would get
|
||||
+ * overwritten during the next call of ap_get_brigade in the loop.
|
||||
+ * ap_save_brigade ensures these buckets to be set aside.
|
||||
+ * Calling ap_save_brigade with NULL as filter is OK, because
|
||||
+ * input_brigade already has been created and does not need to get
|
||||
+ * created by ap_save_brigade.
|
||||
+ */
|
||||
+ status = ap_save_brigade(NULL, &input_brigade, &temp_brigade, p);
|
||||
+ if (status != APR_SUCCESS) {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01096)
|
||||
+ "processing prefetched request body failed"
|
||||
+ " to %pI (%s) from %s (%s)", backend->addr,
|
||||
+ backend->hostname ? backend->hostname : "",
|
||||
+ c->client_ip, c->remote_host ? c->remote_host : "");
|
||||
+ return HTTP_INTERNAL_SERVER_ERROR;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return OK;
|
||||
+}
|
||||
+
|
||||
+PROXY_DECLARE(int) ap_proxy_read_input(request_rec *r,
|
||||
+ proxy_conn_rec *backend,
|
||||
+ apr_bucket_brigade *bb,
|
||||
+ apr_off_t max_read)
|
||||
+{
|
||||
+ apr_bucket_alloc_t *bucket_alloc = bb->bucket_alloc;
|
||||
+ apr_read_type_e block = (backend->connection) ? APR_NONBLOCK_READ
|
||||
+ : APR_BLOCK_READ;
|
||||
+ apr_status_t status;
|
||||
+ int rv;
|
||||
+
|
||||
+ for (;;) {
|
||||
+ apr_brigade_cleanup(bb);
|
||||
+ status = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES,
|
||||
+ block, max_read);
|
||||
+ if (block == APR_BLOCK_READ
|
||||
+ || (!(status == APR_SUCCESS && APR_BRIGADE_EMPTY(bb))
|
||||
+ && !APR_STATUS_IS_EAGAIN(status))) {
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ /* Flush and retry (blocking) */
|
||||
+ apr_brigade_cleanup(bb);
|
||||
+ rv = ap_proxy_pass_brigade(bucket_alloc, r, backend,
|
||||
+ backend->connection, bb, 1);
|
||||
+ if (rv != OK) {
|
||||
+ return rv;
|
||||
+ }
|
||||
+ block = APR_BLOCK_READ;
|
||||
+ }
|
||||
+
|
||||
+ if (status != APR_SUCCESS) {
|
||||
+ conn_rec *c = r->connection;
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(02608)
|
||||
+ "read request body failed to %pI (%s)"
|
||||
+ " from %s (%s)", backend->addr,
|
||||
+ backend->hostname ? backend->hostname : "",
|
||||
+ c->client_ip, c->remote_host ? c->remote_host : "");
|
||||
+ return ap_map_http_request_error(status, HTTP_BAD_REQUEST);
|
||||
+ }
|
||||
+
|
||||
+ return OK;
|
||||
+}
|
||||
+
|
||||
+PROXY_DECLARE(int) ap_proxy_spool_input(request_rec *r,
|
||||
+ proxy_conn_rec *backend,
|
||||
+ apr_bucket_brigade *input_brigade,
|
||||
+ apr_off_t *bytes_spooled,
|
||||
+ apr_off_t max_mem_spool)
|
||||
+{
|
||||
+ apr_pool_t *p = r->pool;
|
||||
+ int seen_eos = 0, rv = OK;
|
||||
+ apr_status_t status = APR_SUCCESS;
|
||||
+ apr_bucket_alloc_t *bucket_alloc = input_brigade->bucket_alloc;
|
||||
+ apr_bucket_brigade *body_brigade;
|
||||
+ apr_bucket *e;
|
||||
+ apr_off_t bytes, fsize = 0;
|
||||
+ apr_file_t *tmpfile = NULL;
|
||||
+ apr_off_t limit;
|
||||
+
|
||||
+ *bytes_spooled = 0;
|
||||
+ body_brigade = apr_brigade_create(p, bucket_alloc);
|
||||
+
|
||||
+ limit = ap_get_limit_req_body(r);
|
||||
+
|
||||
+ do {
|
||||
+ if (APR_BRIGADE_EMPTY(input_brigade)) {
|
||||
+ rv = ap_proxy_read_input(r, backend, input_brigade,
|
||||
+ HUGE_STRING_LEN);
|
||||
+ if (rv != OK) {
|
||||
+ return rv;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* If this brigade contains EOS, either stop or remove it. */
|
||||
+ if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) {
|
||||
+ seen_eos = 1;
|
||||
+ }
|
||||
+
|
||||
+ apr_brigade_length(input_brigade, 1, &bytes);
|
||||
+
|
||||
+ if (*bytes_spooled + bytes > max_mem_spool) {
|
||||
+ /*
|
||||
+ * LimitRequestBody does not affect Proxy requests (Should it?).
|
||||
+ * Let it take effect if we decide to store the body in a
|
||||
+ * temporary file on disk.
|
||||
+ */
|
||||
+ if (limit && (*bytes_spooled + bytes > limit)) {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01088)
|
||||
+ "Request body is larger than the configured "
|
||||
+ "limit of %" APR_OFF_T_FMT, limit);
|
||||
+ return HTTP_REQUEST_ENTITY_TOO_LARGE;
|
||||
+ }
|
||||
+ /* can't spool any more in memory; write latest brigade to disk */
|
||||
+ if (tmpfile == NULL) {
|
||||
+ const char *temp_dir;
|
||||
+ char *template;
|
||||
+
|
||||
+ status = apr_temp_dir_get(&temp_dir, p);
|
||||
+ if (status != APR_SUCCESS) {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01089)
|
||||
+ "search for temporary directory failed");
|
||||
+ return HTTP_INTERNAL_SERVER_ERROR;
|
||||
+ }
|
||||
+ apr_filepath_merge(&template, temp_dir,
|
||||
+ "modproxy.tmp.XXXXXX",
|
||||
+ APR_FILEPATH_NATIVE, p);
|
||||
+ status = apr_file_mktemp(&tmpfile, template, 0, p);
|
||||
+ if (status != APR_SUCCESS) {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01090)
|
||||
+ "creation of temporary file in directory "
|
||||
+ "%s failed", temp_dir);
|
||||
+ return HTTP_INTERNAL_SERVER_ERROR;
|
||||
+ }
|
||||
+ }
|
||||
+ for (e = APR_BRIGADE_FIRST(input_brigade);
|
||||
+ e != APR_BRIGADE_SENTINEL(input_brigade);
|
||||
+ e = APR_BUCKET_NEXT(e)) {
|
||||
+ const char *data;
|
||||
+ apr_size_t bytes_read, bytes_written;
|
||||
+
|
||||
+ apr_bucket_read(e, &data, &bytes_read, APR_BLOCK_READ);
|
||||
+ status = apr_file_write_full(tmpfile, data, bytes_read, &bytes_written);
|
||||
+ if (status != APR_SUCCESS) {
|
||||
+ const char *tmpfile_name;
|
||||
+
|
||||
+ if (apr_file_name_get(&tmpfile_name, tmpfile) != APR_SUCCESS) {
|
||||
+ tmpfile_name = "(unknown)";
|
||||
+ }
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01091)
|
||||
+ "write to temporary file %s failed",
|
||||
+ tmpfile_name);
|
||||
+ return HTTP_INTERNAL_SERVER_ERROR;
|
||||
+ }
|
||||
+ AP_DEBUG_ASSERT(bytes_read == bytes_written);
|
||||
+ fsize += bytes_written;
|
||||
+ }
|
||||
+ apr_brigade_cleanup(input_brigade);
|
||||
+ }
|
||||
+ else {
|
||||
+
|
||||
+ /*
|
||||
+ * Save input_brigade in body_brigade. (At least) in the SSL case
|
||||
+ * input_brigade contains transient buckets whose data would get
|
||||
+ * overwritten during the next call of ap_get_brigade in the loop.
|
||||
+ * ap_save_brigade ensures these buckets to be set aside.
|
||||
+ * Calling ap_save_brigade with NULL as filter is OK, because
|
||||
+ * body_brigade already has been created and does not need to get
|
||||
+ * created by ap_save_brigade.
|
||||
+ */
|
||||
+ status = ap_save_brigade(NULL, &body_brigade, &input_brigade, p);
|
||||
+ if (status != APR_SUCCESS) {
|
||||
+ return HTTP_INTERNAL_SERVER_ERROR;
|
||||
+ }
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ *bytes_spooled += bytes;
|
||||
+ } while (!seen_eos);
|
||||
+
|
||||
+ APR_BRIGADE_CONCAT(input_brigade, body_brigade);
|
||||
+ if (tmpfile) {
|
||||
+ apr_brigade_insert_file(input_brigade, tmpfile, 0, fsize, p);
|
||||
+ }
|
||||
+ if (apr_table_get(r->subprocess_env, "proxy-sendextracrlf")) {
|
||||
+ e = apr_bucket_immortal_create(CRLF_ASCII, 2, bucket_alloc);
|
||||
+ APR_BRIGADE_INSERT_TAIL(input_brigade, e);
|
||||
+ }
|
||||
+ if (tmpfile) {
|
||||
+ /* We dropped metadata buckets when spooling to tmpfile,
|
||||
+ * terminate with EOS to allow for flushing in a one go.
|
||||
+ */
|
||||
+ e = apr_bucket_eos_create(bucket_alloc);
|
||||
+ APR_BRIGADE_INSERT_TAIL(input_brigade, e);
|
||||
+ }
|
||||
+ return OK;
|
||||
+}
|
||||
+
|
||||
PROXY_DECLARE(int) ap_proxy_pass_brigade(apr_bucket_alloc_t *bucket_alloc,
|
||||
request_rec *r, proxy_conn_rec *p_conn,
|
||||
conn_rec *origin, apr_bucket_brigade *bb,
|
@ -1,217 +0,0 @@
|
||||
diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c
|
||||
index 114b126..a25c7ae 100644
|
||||
--- a/modules/mappers/mod_rewrite.c
|
||||
+++ b/modules/mappers/mod_rewrite.c
|
||||
@@ -2343,9 +2343,16 @@ static APR_INLINE char *find_char_in_curlies(char *s, int c)
|
||||
* of an earlier expansion to include expansion specifiers that
|
||||
* are interpreted by a later expansion, producing results that
|
||||
* were not intended by the administrator.
|
||||
+ *
|
||||
+ * unsafe_qmark if not NULL will be set to 1 or 0 if a question mark
|
||||
+ * is found respectively in a literal or in a lookup/expansion (whether
|
||||
+ * it's the first or last qmark depends on [QSL]). Should be initialized
|
||||
+ * to -1 and remains so if no qmark is found.
|
||||
*/
|
||||
-static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry)
|
||||
+static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry,
|
||||
+ int *unsafe_qmark)
|
||||
{
|
||||
+#define EXPAND_SPECIALS "\\$%"
|
||||
result_list *result, *current;
|
||||
result_list sresult[SMALL_EXPANSION];
|
||||
unsigned spc = 0;
|
||||
@@ -2353,8 +2360,29 @@ static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry)
|
||||
char *p, *c;
|
||||
apr_pool_t *pool = ctx->r->pool;
|
||||
|
||||
- span = strcspn(input, "\\$%");
|
||||
inputlen = strlen(input);
|
||||
+ if (!unsafe_qmark) {
|
||||
+ span = strcspn(input, EXPAND_SPECIALS);
|
||||
+ }
|
||||
+ else {
|
||||
+ span = strcspn(input, EXPAND_SPECIALS "?");
|
||||
+ if (input[span] == '?') {
|
||||
+ /* this qmark is not from an expansion thus safe */
|
||||
+ *unsafe_qmark = 0;
|
||||
+
|
||||
+ /* keep tracking only if interested in the last qmark */
|
||||
+ if (entry && (entry->flags & RULEFLAG_QSLAST)) {
|
||||
+ do {
|
||||
+ span++;
|
||||
+ span += strcspn(input + span, EXPAND_SPECIALS "?");
|
||||
+ } while (input[span] == '?');
|
||||
+ }
|
||||
+ else {
|
||||
+ unsafe_qmark = NULL;
|
||||
+ span += strcspn(input + span, EXPAND_SPECIALS);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
|
||||
/* fast exit */
|
||||
if (inputlen == span) {
|
||||
@@ -2372,6 +2400,8 @@ static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry)
|
||||
|
||||
/* loop for specials */
|
||||
do {
|
||||
+ int expanded = 0;
|
||||
+
|
||||
/* prepare next entry */
|
||||
if (current->len) {
|
||||
current->next = (spc < SMALL_EXPANSION)
|
||||
@@ -2417,6 +2447,8 @@ static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry)
|
||||
current->len = span;
|
||||
current->string = p;
|
||||
outlen += span;
|
||||
+
|
||||
+ expanded = 1;
|
||||
p = endp + 1;
|
||||
}
|
||||
|
||||
@@ -2456,19 +2488,18 @@ static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry)
|
||||
}
|
||||
|
||||
/* reuse of key variable as result */
|
||||
- key = lookup_map(ctx->r, map, do_expand(key, ctx, entry));
|
||||
-
|
||||
+ key = lookup_map(ctx->r, map, do_expand(key, ctx, entry, NULL));
|
||||
if (!key && dflt && *dflt) {
|
||||
- key = do_expand(dflt, ctx, entry);
|
||||
+ key = do_expand(dflt, ctx, entry, NULL);
|
||||
}
|
||||
-
|
||||
- if (key) {
|
||||
+ if (key && *key) {
|
||||
span = strlen(key);
|
||||
current->len = span;
|
||||
current->string = key;
|
||||
outlen += span;
|
||||
}
|
||||
|
||||
+ expanded = 1;
|
||||
p = endp + 1;
|
||||
}
|
||||
}
|
||||
@@ -2498,8 +2529,9 @@ static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry)
|
||||
current->len = span;
|
||||
current->string = bri->source + bri->regmatch[n].rm_so;
|
||||
}
|
||||
-
|
||||
outlen += span;
|
||||
+
|
||||
+ expanded = 1;
|
||||
}
|
||||
|
||||
p += 2;
|
||||
@@ -2512,8 +2544,41 @@ static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry)
|
||||
++outlen;
|
||||
}
|
||||
|
||||
+ if (unsafe_qmark && expanded && current->len
|
||||
+ && memchr(current->string, '?', current->len)) {
|
||||
+ /* this qmark is from an expansion thus unsafe */
|
||||
+ *unsafe_qmark = 1;
|
||||
+
|
||||
+ /* keep tracking only if interested in the last qmark */
|
||||
+ if (!entry || !(entry->flags & RULEFLAG_QSLAST)) {
|
||||
+ unsafe_qmark = NULL;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
/* check the remainder */
|
||||
- if (*p && (span = strcspn(p, "\\$%")) > 0) {
|
||||
+ if (!unsafe_qmark) {
|
||||
+ span = strcspn(p, EXPAND_SPECIALS);
|
||||
+ }
|
||||
+ else {
|
||||
+ span = strcspn(p, EXPAND_SPECIALS "?");
|
||||
+ if (p[span] == '?') {
|
||||
+ /* this qmark is not from an expansion thus safe */
|
||||
+ *unsafe_qmark = 0;
|
||||
+
|
||||
+ /* keep tracking only if interested in the last qmark */
|
||||
+ if (entry && (entry->flags & RULEFLAG_QSLAST)) {
|
||||
+ do {
|
||||
+ span++;
|
||||
+ span += strcspn(p + span, EXPAND_SPECIALS "?");
|
||||
+ } while (p[span] == '?');
|
||||
+ }
|
||||
+ else {
|
||||
+ unsafe_qmark = NULL;
|
||||
+ span += strcspn(p + span, EXPAND_SPECIALS);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ if (span > 0) {
|
||||
if (current->len) {
|
||||
current->next = (spc < SMALL_EXPANSION)
|
||||
? &(sresult[spc++])
|
||||
@@ -2558,7 +2623,7 @@ static void do_expand_env(data_item *env, rewrite_ctx *ctx)
|
||||
char *name, *val;
|
||||
|
||||
while (env) {
|
||||
- name = do_expand(env->data, ctx, NULL);
|
||||
+ name = do_expand(env->data, ctx, NULL, NULL);
|
||||
if (*name == '!') {
|
||||
name++;
|
||||
apr_table_unset(ctx->r->subprocess_env, name);
|
||||
@@ -2685,7 +2750,7 @@ static void add_cookie(request_rec *r, char *s)
|
||||
static void do_expand_cookie(data_item *cookie, rewrite_ctx *ctx)
|
||||
{
|
||||
while (cookie) {
|
||||
- add_cookie(ctx->r, do_expand(cookie->data, ctx, NULL));
|
||||
+ add_cookie(ctx->r, do_expand(cookie->data, ctx, NULL, NULL));
|
||||
cookie = cookie->next;
|
||||
}
|
||||
|
||||
@@ -3964,7 +4029,7 @@ static int apply_rewrite_cond(rewritecond_entry *p, rewrite_ctx *ctx)
|
||||
int basis;
|
||||
|
||||
if (p->ptype != CONDPAT_AP_EXPR)
|
||||
- input = do_expand(p->input, ctx, NULL);
|
||||
+ input = do_expand(p->input, ctx, NULL, NULL);
|
||||
|
||||
switch (p->ptype) {
|
||||
case CONDPAT_FILE_EXISTS:
|
||||
@@ -4128,7 +4193,7 @@ static APR_INLINE void force_type_handler(rewriterule_entry *p,
|
||||
char *expanded;
|
||||
|
||||
if (p->forced_mimetype) {
|
||||
- expanded = do_expand(p->forced_mimetype, ctx, p);
|
||||
+ expanded = do_expand(p->forced_mimetype, ctx, p, NULL);
|
||||
|
||||
if (*expanded) {
|
||||
ap_str_tolower(expanded);
|
||||
@@ -4142,7 +4207,7 @@ static APR_INLINE void force_type_handler(rewriterule_entry *p,
|
||||
}
|
||||
|
||||
if (p->forced_handler) {
|
||||
- expanded = do_expand(p->forced_handler, ctx, p);
|
||||
+ expanded = do_expand(p->forced_handler, ctx, p, NULL);
|
||||
|
||||
if (*expanded) {
|
||||
ap_str_tolower(expanded);
|
||||
@@ -4279,12 +4344,18 @@ static rule_return_type apply_rewrite_rule(rewriterule_entry *p,
|
||||
|
||||
/* expand the result */
|
||||
if (!(p->flags & RULEFLAG_NOSUB)) {
|
||||
- newuri = do_expand(p->output, ctx, p);
|
||||
+ int unsafe_qmark = -1;
|
||||
+
|
||||
+ if (p->flags & RULEFLAG_UNSAFE_ALLOW3F) {
|
||||
+ newuri = do_expand(p->output, ctx, p, NULL);
|
||||
+ }
|
||||
+ else {
|
||||
+ newuri = do_expand(p->output, ctx, p, &unsafe_qmark);
|
||||
+ }
|
||||
rewritelog((r, 2, ctx->perdir, "rewrite '%s' -> '%s'", ctx->uri,
|
||||
newuri));
|
||||
- if (!(p->flags & RULEFLAG_UNSAFE_ALLOW3F) &&
|
||||
- ap_strcasestr(r->unparsed_uri, "%3f") &&
|
||||
- ap_strchr_c(newuri, '?')) {
|
||||
+
|
||||
+ if (unsafe_qmark > 0) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO()
|
||||
"Unsafe URL with %%3f URL rewritten without "
|
||||
"UnsafeAllow3F");
|
@ -1,188 +0,0 @@
|
||||
diff --git a/modules/ssl/ssl_engine_io.c b/modules/ssl/ssl_engine_io.c
|
||||
index 018b667..4e3875a 100644
|
||||
--- a/modules/ssl/ssl_engine_io.c
|
||||
+++ b/modules/ssl/ssl_engine_io.c
|
||||
@@ -1598,18 +1598,32 @@ static apr_status_t ssl_io_filter_input(ap_filter_t *f,
|
||||
}
|
||||
|
||||
|
||||
-/* ssl_io_filter_output() produces one SSL/TLS message per bucket
|
||||
+/* ssl_io_filter_output() produces one SSL/TLS record per bucket
|
||||
* passed down the output filter stack. This results in a high
|
||||
- * overhead (network packets) for any output comprising many small
|
||||
- * buckets. SSI page applied through the HTTP chunk filter, for
|
||||
- * example, may produce many brigades containing small buckets -
|
||||
- * [chunk-size CRLF] [chunk-data] [CRLF].
|
||||
+ * overhead (more network packets & TLS processing) for any output
|
||||
+ * comprising many small buckets. SSI output passed through the HTTP
|
||||
+ * chunk filter, for example, may produce many brigades containing
|
||||
+ * small buckets - [chunk-size CRLF] [chunk-data] [CRLF].
|
||||
*
|
||||
- * The coalescing filter merges many small buckets into larger buckets
|
||||
- * where possible, allowing the SSL I/O output filter to handle them
|
||||
- * more efficiently. */
|
||||
+ * Sending HTTP response headers as a separate TLS record to the
|
||||
+ * response body also reveals information to a network observer (the
|
||||
+ * size of headers) which can be significant.
|
||||
+ *
|
||||
+ * The coalescing filter merges data buckets with the aim of producing
|
||||
+ * fewer, larger TLS records - without copying/buffering all content
|
||||
+ * and introducing unnecessary overhead.
|
||||
+ *
|
||||
+ * ### This buffering could be probably be done more comprehensively
|
||||
+ * ### in ssl_io_filter_output itself.
|
||||
+ *
|
||||
+ * ### Another possible performance optimisation in particular for the
|
||||
+ * ### [HEAP] [FILE] HTTP response case is using a brigade rather than
|
||||
+ * ### a char array to buffer; using apr_brigade_write() to append
|
||||
+ * ### will use already-allocated memory from the HEAP, reducing # of
|
||||
+ * ### copies.
|
||||
+ */
|
||||
|
||||
-#define COALESCE_BYTES (2048)
|
||||
+#define COALESCE_BYTES (AP_IOBUFSIZE)
|
||||
|
||||
struct coalesce_ctx {
|
||||
char buffer[COALESCE_BYTES];
|
||||
@@ -1622,11 +1636,12 @@ static apr_status_t ssl_io_filter_coalesce(ap_filter_t *f,
|
||||
apr_bucket *e, *upto;
|
||||
apr_size_t bytes = 0;
|
||||
struct coalesce_ctx *ctx = f->ctx;
|
||||
+ apr_size_t buffered = ctx ? ctx->bytes : 0; /* space used on entry */
|
||||
unsigned count = 0;
|
||||
|
||||
/* The brigade consists of zero-or-more small data buckets which
|
||||
- * can be coalesced (the prefix), followed by the remainder of the
|
||||
- * brigade.
|
||||
+ * can be coalesced (referred to as the "prefix"), followed by the
|
||||
+ * remainder of the brigade.
|
||||
*
|
||||
* Find the last bucket - if any - of that prefix. count gives
|
||||
* the number of buckets in the prefix. The "prefix" must contain
|
||||
@@ -1641,24 +1656,97 @@ static apr_status_t ssl_io_filter_coalesce(ap_filter_t *f,
|
||||
e != APR_BRIGADE_SENTINEL(bb)
|
||||
&& !APR_BUCKET_IS_METADATA(e)
|
||||
&& e->length != (apr_size_t)-1
|
||||
- && e->length < COALESCE_BYTES
|
||||
- && (bytes + e->length) < COALESCE_BYTES
|
||||
- && (ctx == NULL
|
||||
- || bytes + ctx->bytes + e->length < COALESCE_BYTES);
|
||||
+ && e->length <= COALESCE_BYTES
|
||||
+ && (buffered + bytes + e->length) <= COALESCE_BYTES;
|
||||
e = APR_BUCKET_NEXT(e)) {
|
||||
if (e->length) count++; /* don't count zero-length buckets */
|
||||
bytes += e->length;
|
||||
}
|
||||
+
|
||||
+ /* If there is room remaining and the next bucket is a data
|
||||
+ * bucket, try to include it in the prefix to coalesce. For a
|
||||
+ * typical [HEAP] [FILE] HTTP response brigade, this handles
|
||||
+ * merging the headers and the start of the body into a single TLS
|
||||
+ * record. */
|
||||
+ if (bytes + buffered > 0
|
||||
+ && bytes + buffered < COALESCE_BYTES
|
||||
+ && e != APR_BRIGADE_SENTINEL(bb)
|
||||
+ && !APR_BUCKET_IS_METADATA(e)) {
|
||||
+ apr_status_t rv = APR_SUCCESS;
|
||||
+
|
||||
+ /* For an indeterminate length bucket (PIPE/CGI/...), try a
|
||||
+ * non-blocking read to have it morph into a HEAP. If the
|
||||
+ * read fails with EAGAIN, it is harmless to try a split
|
||||
+ * anyway, split is ENOTIMPL for most PIPE-like buckets. */
|
||||
+ if (e->length == (apr_size_t)-1) {
|
||||
+ const char *discard;
|
||||
+ apr_size_t ignore;
|
||||
+
|
||||
+ rv = apr_bucket_read(e, &discard, &ignore, APR_NONBLOCK_READ);
|
||||
+ if (rv != APR_SUCCESS && !APR_STATUS_IS_EAGAIN(rv)) {
|
||||
+ ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, f->c, APLOGNO(10232)
|
||||
+ "coalesce failed to read from %s bucket",
|
||||
+ e->type->name);
|
||||
+ return AP_FILTER_ERROR;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (rv == APR_SUCCESS) {
|
||||
+ /* If the read above made the bucket morph, it may now fit
|
||||
+ * entirely within the buffer. Otherwise, split it so it does
|
||||
+ * fit. */
|
||||
+ if (e->length > COALESCE_BYTES
|
||||
+ || e->length + buffered + bytes > COALESCE_BYTES) {
|
||||
+ rv = apr_bucket_split(e, COALESCE_BYTES - (buffered + bytes));
|
||||
+ }
|
||||
+
|
||||
+ if (rv == APR_SUCCESS && e->length == 0) {
|
||||
+ /* As above, don't count in the prefix if the bucket is
|
||||
+ * now zero-length. */
|
||||
+ }
|
||||
+ else if (rv == APR_SUCCESS) {
|
||||
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, f->c,
|
||||
+ "coalesce: adding %" APR_SIZE_T_FMT " bytes "
|
||||
+ "from split %s bucket, total %" APR_SIZE_T_FMT,
|
||||
+ e->length, e->type->name, bytes + buffered);
|
||||
+
|
||||
+ count++;
|
||||
+ bytes += e->length;
|
||||
+ e = APR_BUCKET_NEXT(e);
|
||||
+ }
|
||||
+ else if (rv != APR_ENOTIMPL) {
|
||||
+ ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, f->c, APLOGNO(10233)
|
||||
+ "coalesce: failed to split data bucket");
|
||||
+ return AP_FILTER_ERROR;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* The prefix is zero or more buckets. upto now points to the
|
||||
+ * bucket AFTER the end of the prefix, which may be the brigade
|
||||
+ * sentinel. */
|
||||
upto = e;
|
||||
|
||||
- /* Coalesce the prefix, if:
|
||||
- * a) more than one bucket is found to coalesce, or
|
||||
- * b) the brigade contains only a single data bucket, or
|
||||
- * c) the data bucket is not last but we have buffered data already.
|
||||
+ /* Coalesce the prefix, if any of the following are true:
|
||||
+ *
|
||||
+ * a) the prefix is more than one bucket
|
||||
+ * OR
|
||||
+ * b) the prefix is the entire brigade, which is a single bucket
|
||||
+ * AND the prefix length is smaller than the buffer size,
|
||||
+ * OR
|
||||
+ * c) the prefix is a single bucket
|
||||
+ * AND there is buffered data from a previous pass.
|
||||
+ *
|
||||
+ * The aim with (b) is to buffer a small bucket so it can be
|
||||
+ * coalesced with future invocations of this filter. e.g. three
|
||||
+ * calls each with a single 100 byte HEAP bucket should get
|
||||
+ * coalesced together. But an invocation with a 8192 byte HEAP
|
||||
+ * should pass through untouched.
|
||||
*/
|
||||
if (bytes > 0
|
||||
&& (count > 1
|
||||
- || (upto == APR_BRIGADE_SENTINEL(bb))
|
||||
+ || (upto == APR_BRIGADE_SENTINEL(bb)
|
||||
+ && bytes < COALESCE_BYTES)
|
||||
|| (ctx && ctx->bytes > 0))) {
|
||||
/* If coalescing some bytes, ensure a context has been
|
||||
* created. */
|
||||
@@ -1669,7 +1757,8 @@ static apr_status_t ssl_io_filter_coalesce(ap_filter_t *f,
|
||||
|
||||
ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, f->c,
|
||||
"coalesce: have %" APR_SIZE_T_FMT " bytes, "
|
||||
- "adding %" APR_SIZE_T_FMT " more", ctx->bytes, bytes);
|
||||
+ "adding %" APR_SIZE_T_FMT " more (buckets=%u)",
|
||||
+ ctx->bytes, bytes, count);
|
||||
|
||||
/* Iterate through the prefix segment. For non-fatal errors
|
||||
* in this loop it is safe to break out and fall back to the
|
||||
@@ -1684,7 +1773,8 @@ static apr_status_t ssl_io_filter_coalesce(ap_filter_t *f,
|
||||
if (APR_BUCKET_IS_METADATA(e)
|
||||
|| e->length == (apr_size_t)-1) {
|
||||
ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, f->c, APLOGNO(02012)
|
||||
- "unexpected bucket type during coalesce");
|
||||
+ "unexpected %s bucket during coalesce",
|
||||
+ e->type->name);
|
||||
break; /* non-fatal error; break out */
|
||||
}
|
||||
|
@ -1,194 +0,0 @@
|
||||
diff --git a/docs/manual/mod/mod_session.html.en b/docs/manual/mod/mod_session.html.en
|
||||
index 6834f8e..9f8301f 100644
|
||||
--- a/docs/manual/mod/mod_session.html.en
|
||||
+++ b/docs/manual/mod/mod_session.html.en
|
||||
@@ -82,6 +82,7 @@
|
||||
<li><img alt="" src="../images/down.gif" /> <a href="#sessionheader">SessionHeader</a></li>
|
||||
<li><img alt="" src="../images/down.gif" /> <a href="#sessioninclude">SessionInclude</a></li>
|
||||
<li><img alt="" src="../images/down.gif" /> <a href="#sessionmaxage">SessionMaxAge</a></li>
|
||||
+<li><img alt="" src="../images/down.gif" /> <a href="#sessionexpiryupdateinterval">SessionExpiryUpdateInterval</a></li>
|
||||
</ul>
|
||||
<h3>Bugfix checklist</h3><ul class="seealso"><li><a href="https://www.apache.org/dist/httpd/CHANGES_2.4">httpd changelog</a></li><li><a href="https://bz.apache.org/bugzilla/buglist.cgi?bug_status=__open__&list_id=144532&product=Apache%20httpd-2&query_format=specific&order=changeddate%20DESC%2Cpriority%2Cbug_severity&component=mod_session">Known issues</a></li><li><a href="https://bz.apache.org/bugzilla/enter_bug.cgi?product=Apache%20httpd-2&component=mod_session">Report a bug</a></li></ul><h3>See also</h3>
|
||||
<ul class="seealso">
|
||||
@@ -482,6 +483,37 @@ AuthName realm
|
||||
|
||||
<p>Setting the maxage to zero disables session expiry.</p>
|
||||
|
||||
+</div>
|
||||
+<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
|
||||
+<div class="directive-section"><h2><a name="SessionExpiryUpdateInterval" id="sessionexpiryupdateinterval">SessionExpiryUpdateInterval</a> <a name="sessionexpiryupdateinterval" id="sessionexpiryupdateinterval">Directive</a></h2>
|
||||
+<table class="directive">
|
||||
+<tr><th><a href="directive-dict.html#Description">Description:</a></th><td>Define the number of seconds a session's expiry may change without the session being updated</td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Syntax">Syntax:</a></th><td><code>SessionExpiryUpdateInterval <var>interval</var></code></td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Default">Default:</a></th><td><code>SessionExpiryUpdateInterval 0 (always update)</code></td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Context">Context:</a></th><td>server config, virtual host, directory, .htaccess</td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Module">Module:</a></th><td>mod_session</td></tr>
|
||||
+</table>
|
||||
+ <p>The <code class="directive">SessionExpiryUpdateInterval</code> directive allows
|
||||
+ sessions to avoid the cost associated with writing the session each request
|
||||
+ when only the expiry time has changed. This can be used to make a website
|
||||
+ more efficient or reduce load on a database when using
|
||||
+ <module>mod_session_dbd</module>. The session is always written if the data
|
||||
+ stored in the session has changed or the expiry has changed by more than the
|
||||
+ configured interval.</p>
|
||||
+
|
||||
+ <p>Setting the interval to zero disables this directive, and the session
|
||||
+ expiry is refreshed for each request.</p>
|
||||
+
|
||||
+ <p>This directive only has an effect when combined with <code class="directive"><a href="../mod/mod_session.html#sessionmaxage">SessionMaxAge</a></code> to enable session
|
||||
+ expiry. Sessions without an expiry are only written when the data stored in
|
||||
+ the session has changed.</p>
|
||||
+
|
||||
+ <div class="warning"><h3>Warning</h3>
|
||||
+ <p>Because the session expiry may not be refreshed with each request, it's
|
||||
+ possible for sessions to expire up to <var>interval</var> seconds early.
|
||||
+ Using a small interval usually provides sufficient savings while having a
|
||||
+ minimal effect on expiry resolution.</p></div>
|
||||
+
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottomlang">
|
||||
diff --git a/modules/session/mod_session.c b/modules/session/mod_session.c
|
||||
index d517020..10e6396 100644
|
||||
--- a/modules/session/mod_session.c
|
||||
+++ b/modules/session/mod_session.c
|
||||
@@ -177,6 +177,7 @@ static apr_status_t ap_session_save(request_rec * r, session_rec * z)
|
||||
{
|
||||
if (z) {
|
||||
apr_time_t now = apr_time_now();
|
||||
+ apr_time_t initialExpiry = z->expiry;
|
||||
int rv = 0;
|
||||
|
||||
session_dir_conf *dconf = ap_get_module_config(r->per_dir_config,
|
||||
@@ -207,6 +208,17 @@ static apr_status_t ap_session_save(request_rec * r, session_rec * z)
|
||||
z->expiry = now + z->maxage * APR_USEC_PER_SEC;
|
||||
}
|
||||
|
||||
+ /* don't save if the only change is the expiry by a small amount */
|
||||
+ if (!z->dirty && dconf->expiry_update_time
|
||||
+ && (z->expiry - initialExpiry < dconf->expiry_update_time)) {
|
||||
+ return APR_SUCCESS;
|
||||
+ }
|
||||
+
|
||||
+ /* also don't save sessions that didn't change at all */
|
||||
+ if (!z->dirty && !z->maxage) {
|
||||
+ return APR_SUCCESS;
|
||||
+ }
|
||||
+
|
||||
/* encode the session */
|
||||
rv = ap_run_session_encode(r, z);
|
||||
if (OK != rv) {
|
||||
@@ -553,6 +565,10 @@ static void *merge_session_dir_config(apr_pool_t * p, void *basev, void *addv)
|
||||
new->env_set = add->env_set || base->env_set;
|
||||
new->includes = apr_array_append(p, base->includes, add->includes);
|
||||
new->excludes = apr_array_append(p, base->excludes, add->excludes);
|
||||
+ new->expiry_update_time = (add->expiry_update_set == 0)
|
||||
+ ? base->expiry_update_time
|
||||
+ : add->expiry_update_time;
|
||||
+ new->expiry_update_set = add->expiry_update_set || base->expiry_update_set;
|
||||
|
||||
return new;
|
||||
}
|
||||
@@ -622,6 +638,21 @@ static const char *add_session_exclude(cmd_parms * cmd, void *dconf, const char
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+static const char *
|
||||
+ set_session_expiry_update(cmd_parms * parms, void *dconf, const char *arg)
|
||||
+{
|
||||
+ session_dir_conf *conf = dconf;
|
||||
+
|
||||
+ conf->expiry_update_time = atoi(arg);
|
||||
+ if (conf->expiry_update_time < 0) {
|
||||
+ return "SessionExpiryUpdateInterval must be positive or nul";
|
||||
+ }
|
||||
+ conf->expiry_update_time = apr_time_from_sec(conf->expiry_update_time);
|
||||
+ conf->expiry_update_set = 1;
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
|
||||
static const command_rec session_cmds[] =
|
||||
{
|
||||
@@ -637,6 +668,9 @@ static const command_rec session_cmds[] =
|
||||
"URL prefixes to include in the session. Defaults to all URLs"),
|
||||
AP_INIT_TAKE1("SessionExclude", add_session_exclude, NULL, RSRC_CONF|OR_AUTHCFG,
|
||||
"URL prefixes to exclude from the session. Defaults to no URLs"),
|
||||
+ AP_INIT_TAKE1("SessionExpiryUpdateInterval", set_session_expiry_update, NULL, RSRC_CONF|OR_AUTHCFG,
|
||||
+ "time interval for which a session's expiry time may change "
|
||||
+ "without having to be rewritten. Zero to disable"),
|
||||
{NULL}
|
||||
};
|
||||
|
||||
diff --git a/modules/session/mod_session.h b/modules/session/mod_session.h
|
||||
index a6dd5e9..bdeb532 100644
|
||||
--- a/modules/session/mod_session.h
|
||||
+++ b/modules/session/mod_session.h
|
||||
@@ -115,6 +115,9 @@ typedef struct {
|
||||
* URLs included if empty */
|
||||
apr_array_header_t *excludes; /* URL prefixes to be excluded. No
|
||||
* URLs excluded if empty */
|
||||
+ apr_time_t expiry_update_time; /* seconds the session expiry may change and
|
||||
+ * not have to be rewritten */
|
||||
+ int expiry_update_set;
|
||||
} session_dir_conf;
|
||||
|
||||
/**
|
||||
diff --git a/modules/session/mod_session_cookie.c b/modules/session/mod_session_cookie.c
|
||||
index 6a02322..4aa75e4 100644
|
||||
--- a/modules/session/mod_session_cookie.c
|
||||
+++ b/modules/session/mod_session_cookie.c
|
||||
@@ -60,9 +60,6 @@ static apr_status_t session_cookie_save(request_rec * r, session_rec * z)
|
||||
session_cookie_dir_conf *conf = ap_get_module_config(r->per_dir_config,
|
||||
&session_cookie_module);
|
||||
|
||||
- /* don't cache auth protected pages */
|
||||
- apr_table_addn(r->headers_out, "Cache-Control", "no-cache");
|
||||
-
|
||||
/* create RFC2109 compliant cookie */
|
||||
if (conf->name_set) {
|
||||
if (z->encoded && z->encoded[0]) {
|
||||
@@ -162,6 +159,9 @@ static apr_status_t session_cookie_load(request_rec * r, session_rec ** z)
|
||||
/* put the session in the notes so we don't have to parse it again */
|
||||
apr_table_setn(m->notes, note, (char *)zz);
|
||||
|
||||
+ /* don't cache auth protected pages */
|
||||
+ apr_table_addn(r->headers_out, "Cache-Control", "no-cache, private");
|
||||
+
|
||||
return OK;
|
||||
|
||||
}
|
||||
diff --git a/modules/session/mod_session_dbd.c b/modules/session/mod_session_dbd.c
|
||||
index 0be7306..f683da2 100644
|
||||
--- a/modules/session/mod_session_dbd.c
|
||||
+++ b/modules/session/mod_session_dbd.c
|
||||
@@ -245,6 +245,9 @@ static apr_status_t session_dbd_load(request_rec * r, session_rec ** z)
|
||||
/* put the session in the notes so we don't have to parse it again */
|
||||
apr_table_setn(m->notes, note, (char *)zz);
|
||||
|
||||
+ /* don't cache pages with a session */
|
||||
+ apr_table_addn(r->headers_out, "Cache-Control", "no-cache, private");
|
||||
+
|
||||
return OK;
|
||||
|
||||
}
|
||||
@@ -409,9 +412,6 @@ static apr_status_t session_dbd_save(request_rec * r, session_rec * z)
|
||||
if (conf->name_set || conf->name2_set) {
|
||||
char *oldkey = NULL, *newkey = NULL;
|
||||
|
||||
- /* don't cache pages with a session */
|
||||
- apr_table_addn(r->headers_out, "Cache-Control", "no-cache");
|
||||
-
|
||||
/* if the session is new or changed, make a new session ID */
|
||||
if (z->uuid) {
|
||||
oldkey = apr_pcalloc(r->pool, APR_UUID_FORMATTED_LENGTH + 1);
|
||||
@@ -458,7 +458,7 @@ static apr_status_t session_dbd_save(request_rec * r, session_rec * z)
|
||||
else if (conf->peruser) {
|
||||
|
||||
/* don't cache pages with a session */
|
||||
- apr_table_addn(r->headers_out, "Cache-Control", "no-cache");
|
||||
+ apr_table_addn(r->headers_out, "Cache-Control", "no-cache, private");
|
||||
|
||||
if (r->user) {
|
||||
ret = dbd_save(r, r->user, r->user, z->encoded, z->expiry);
|
@ -1,123 +0,0 @@
|
||||
diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c
|
||||
index 1d201d9..0c4bf1f 100644
|
||||
--- a/modules/ssl/ssl_engine_config.c
|
||||
+++ b/modules/ssl/ssl_engine_config.c
|
||||
@@ -75,6 +75,10 @@ SSLModConfigRec *ssl_config_global_create(server_rec *s)
|
||||
mc->stapling_refresh_mutex = NULL;
|
||||
#endif
|
||||
|
||||
+#ifdef HAVE_OPENSSL_KEYLOG
|
||||
+ mc->keylog_file = NULL;
|
||||
+#endif
|
||||
+
|
||||
apr_pool_userdata_set(mc, SSL_MOD_CONFIG_KEY,
|
||||
apr_pool_cleanup_null,
|
||||
pool);
|
||||
diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c
|
||||
index ef631c1..b286053 100644
|
||||
--- a/modules/ssl/ssl_engine_init.c
|
||||
+++ b/modules/ssl/ssl_engine_init.c
|
||||
@@ -437,6 +437,28 @@ apr_status_t ssl_init_Module(apr_pool_t *p, apr_pool_t *plog,
|
||||
init_bio_methods();
|
||||
#endif
|
||||
|
||||
+#ifdef HAVE_OPENSSL_KEYLOG
|
||||
+ {
|
||||
+ const char *logfn = getenv("SSLKEYLOGFILE");
|
||||
+
|
||||
+ if (logfn) {
|
||||
+ rv = apr_file_open(&mc->keylog_file, logfn,
|
||||
+ APR_FOPEN_CREATE|APR_FOPEN_WRITE|APR_FOPEN_APPEND|APR_FOPEN_LARGEFILE,
|
||||
+ APR_FPROT_UREAD|APR_FPROT_UWRITE,
|
||||
+ mc->pPool);
|
||||
+ if (rv) {
|
||||
+ ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, s, APLOGNO(10226)
|
||||
+ "Could not open log file '%s' configured via SSLKEYLOGFILE",
|
||||
+ logfn);
|
||||
+ return rv;
|
||||
+ }
|
||||
+
|
||||
+ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, APLOGNO(10227)
|
||||
+ "Init: Logging SSL private key material to %s", logfn);
|
||||
+ }
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -796,6 +818,12 @@ static apr_status_t ssl_init_ctx_protocol(server_rec *s,
|
||||
* https://github.com/openssl/openssl/issues/7178 */
|
||||
SSL_CTX_clear_mode(ctx, SSL_MODE_AUTO_RETRY);
|
||||
#endif
|
||||
+
|
||||
+#ifdef HAVE_OPENSSL_KEYLOG
|
||||
+ if (mctx->sc->mc->keylog_file) {
|
||||
+ SSL_CTX_set_keylog_callback(ctx, modssl_callback_keylog);
|
||||
+ }
|
||||
+#endif
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c
|
||||
index 6611610..7058865 100644
|
||||
--- a/modules/ssl/ssl_engine_kernel.c
|
||||
+++ b/modules/ssl/ssl_engine_kernel.c
|
||||
@@ -2719,3 +2719,17 @@ int ssl_callback_SRPServerParams(SSL *ssl, int *ad, void *arg)
|
||||
}
|
||||
|
||||
#endif /* HAVE_SRP */
|
||||
+
|
||||
+
|
||||
+#ifdef HAVE_OPENSSL_KEYLOG
|
||||
+/* Callback used with SSL_CTX_set_keylog_callback. */
|
||||
+void modssl_callback_keylog(const SSL *ssl, const char *line)
|
||||
+{
|
||||
+ conn_rec *conn = SSL_get_app_data(ssl);
|
||||
+ SSLSrvConfigRec *sc = mySrvConfig(conn->base_server);
|
||||
+
|
||||
+ if (sc && sc->mc->keylog_file) {
|
||||
+ apr_file_printf(sc->mc->keylog_file, "%s\n", line);
|
||||
+ }
|
||||
+}
|
||||
+#endif
|
||||
diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h
|
||||
index 0fac5d1..2514407 100644
|
||||
--- a/modules/ssl/ssl_private.h
|
||||
+++ b/modules/ssl/ssl_private.h
|
||||
@@ -250,6 +250,10 @@ void free_bio_methods(void);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER)
|
||||
+#define HAVE_OPENSSL_KEYLOG
|
||||
+#endif
|
||||
+
|
||||
/* mod_ssl headers */
|
||||
#include "ssl_util_ssl.h"
|
||||
|
||||
@@ -617,6 +621,12 @@ typedef struct {
|
||||
apr_global_mutex_t *stapling_cache_mutex;
|
||||
apr_global_mutex_t *stapling_refresh_mutex;
|
||||
#endif
|
||||
+
|
||||
+#ifdef HAVE_OPENSSL_KEYLOG
|
||||
+ /* Used for logging if SSLKEYLOGFILE is set at startup. */
|
||||
+ apr_file_t *keylog_file;
|
||||
+#endif
|
||||
+
|
||||
} SSLModConfigRec;
|
||||
|
||||
/** Structure representing configured filenames for certs and keys for
|
||||
@@ -970,6 +980,11 @@ int ssl_stapling_init_cert(server_rec *, apr_pool_t *, apr_pool_t *,
|
||||
int ssl_callback_SRPServerParams(SSL *, int *, void *);
|
||||
#endif
|
||||
|
||||
+#ifdef HAVE_OPENSSL_KEYLOG
|
||||
+/* Callback used with SSL_CTX_set_keylog_callback. */
|
||||
+void modssl_callback_keylog(const SSL *ssl, const char *line);
|
||||
+#endif
|
||||
+
|
||||
/** I/O */
|
||||
void ssl_io_filter_init(conn_rec *, request_rec *r, SSL *);
|
||||
void ssl_io_filter_register(apr_pool_t *);
|
@ -1,178 +0,0 @@
|
||||
diff --git a/docs/manual/mod/mod_usertrack.html.en b/docs/manual/mod/mod_usertrack.html.en
|
||||
index b212747..d2da9b9 100644
|
||||
--- a/docs/manual/mod/mod_usertrack.html.en
|
||||
+++ b/docs/manual/mod/mod_usertrack.html.en
|
||||
@@ -47,7 +47,10 @@
|
||||
<ul id="toc">
|
||||
<li><img alt="" src="../images/down.gif" /> <a href="#cookiedomain">CookieDomain</a></li>
|
||||
<li><img alt="" src="../images/down.gif" /> <a href="#cookieexpires">CookieExpires</a></li>
|
||||
+<li><img alt="" src="../images/down.gif" /> <a href="#cookiehttponly">CookieHTTPOnly</a></li>
|
||||
<li><img alt="" src="../images/down.gif" /> <a href="#cookiename">CookieName</a></li>
|
||||
+<li><img alt="" src="../images/down.gif" /> <a href="#cookiesamesite">CookieSameSite</a></li>
|
||||
+<li><img alt="" src="../images/down.gif" /> <a href="#cookiesecure">CookieSecure</a></li>
|
||||
<li><img alt="" src="../images/down.gif" /> <a href="#cookiestyle">CookieStyle</a></li>
|
||||
<li><img alt="" src="../images/down.gif" /> <a href="#cookietracking">CookieTracking</a></li>
|
||||
</ul>
|
||||
@@ -127,6 +130,22 @@ CustomLog "logs/clickstream.log" usertrack</pre>
|
||||
<pre class="prettyprint lang-config">CookieExpires "3 weeks"</pre>
|
||||
|
||||
|
||||
+</div>
|
||||
+<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
|
||||
+<div class="directive-section"><h2><a name="CookieHTTPOnly" id="CookieHTTPOnly">CookieHTTPOnly</a> <a name="cookiehttponly" id="cookiehttponly">Directive</a></h2>
|
||||
+<table class="directive">
|
||||
+<tbody><tr><th><a href="directive-dict.html#Description">Description:</a></th><td>Adds the 'HTTPOnly' attribute to the cookie</td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Syntax">Syntax:</a></th><td><code>CookieHTTPOnly on|off</code></td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Default">Default:</a></th><td><code>CookieHTTPOnly off</code></td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Context">Context:</a></th><td>server config, virtual host, directory, .htaccess</td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Override">Override:</a></th><td>FileInfo</td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Status">Status:</a></th><td>Extension</td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Module">Module:</a></th><td>mod_usertrack</td></tr>
|
||||
+</tbody></table>
|
||||
+ <p>When set to 'ON', the 'HTTPOnly' cookie attribute is added to this
|
||||
+ modules tracking cookie. This attribute instructs browsers to block javascript
|
||||
+ from reading the value of the cookie.</p>
|
||||
+
|
||||
</div>
|
||||
<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
|
||||
<div class="directive-section"><h2><a name="CookieName" id="CookieName">CookieName</a> <a name="cookiename" id="cookiename">Directive</a></h2>
|
||||
@@ -150,6 +169,45 @@ CustomLog "logs/clickstream.log" usertrack</pre>
|
||||
<pre class="prettyprint lang-config">CookieName clicktrack</pre>
|
||||
|
||||
|
||||
+</div>
|
||||
+<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
|
||||
+<div class="directive-section"><h2><a name="CookieSameSite" id="CookieSameSite">CookieSameSite</a> <a name="cookiesamesite" id="cookiesamesite">Directive</a></h2>
|
||||
+<table class="directive">
|
||||
+<tbody><tr><th><a href="directive-dict.html#Description">Description:</a></th><td>Adds the 'SameSite' attribute to the cookie</td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Syntax">Syntax:</a></th><td><code>CookieSameSite None|Lax|Strict</code></td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Default">Default:</a></th><td><code>unset</code></td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Context">Context:</a></th><td>server config, virtual host, directory, .htaccess</td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Override">Override:</a></th><td>FileInfo</td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Status">Status:</a></th><td>Extension</td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Module">Module:</a></th><td>mod_usertrack</td></tr>
|
||||
+</tbody></table>
|
||||
+ <p>When set to 'None', 'Lax', or 'Strict', the 'SameSite' cookie attribute
|
||||
+ is added to this modules tracking cookie with the corresponding value.
|
||||
+ This attribute instructs browser on how to treat the cookie when it is
|
||||
+ requested in a cross-site context.</p>
|
||||
+
|
||||
+ <div class="note">
|
||||
+ <p>A value of 'None' sets 'SameSite=None', which is the most liberal setting. To
|
||||
+ omit this attribute, omit the directive entirely.</p>
|
||||
+ </div>
|
||||
+
|
||||
+
|
||||
+</div>
|
||||
+<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
|
||||
+<div class="directive-section"><h2><a name="CookieSecure" id="CookieSecure">CookieSecure</a> <a name="cookiesecure" id="cookiesecure">Directive</a></h2>
|
||||
+<table class="directive">
|
||||
+<tbody><tr><th><a href="directive-dict.html#Description">Description:</a></th><td>Adds the 'Secure' attribute to the cookie</td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Syntax">Syntax:</a></th><td><code>CookieSecure on|off</code></td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Default">Default:</a></th><td><code>CookieSecure off</code></td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Context">Context:</a></th><td>server config, virtual host, directory, .htaccess</td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Override">Override:</a></th><td>FileInfo</td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Status">Status:</a></th><td>Extension</td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Module">Module:</a></th><td>mod_usertrack</td></tr>
|
||||
+</tbody></table>
|
||||
+ <p>When set to 'ON', the 'Secure' cookie attribute is added to this
|
||||
+ modules tracking cookie. This attribute instructs browsers to only
|
||||
+ transmit the cookie over HTTPS.</p>
|
||||
+
|
||||
</div>
|
||||
<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
|
||||
<div class="directive-section"><h2><a name="CookieStyle" id="CookieStyle">CookieStyle</a> <a name="cookiestyle" id="cookiestyle">Directive</a></h2>
|
||||
diff --git a/modules/metadata/mod_usertrack.c b/modules/metadata/mod_usertrack.c
|
||||
index 73a9f45..65759c2 100644
|
||||
--- a/modules/metadata/mod_usertrack.c
|
||||
+++ b/modules/metadata/mod_usertrack.c
|
||||
@@ -86,6 +86,9 @@ typedef struct {
|
||||
const char *cookie_domain;
|
||||
char *regexp_string; /* used to compile regexp; save for debugging */
|
||||
ap_regex_t *regexp; /* used to find usertrack cookie in cookie header */
|
||||
+ int is_secure;
|
||||
+ int is_httponly;
|
||||
+ const char *samesite;
|
||||
} cookie_dir_rec;
|
||||
|
||||
/* Make Cookie: Now we have to generate something that is going to be
|
||||
@@ -143,6 +146,21 @@ static void make_cookie(request_rec *r)
|
||||
: ""),
|
||||
NULL);
|
||||
}
|
||||
+ if (dcfg->samesite != NULL) {
|
||||
+ new_cookie = apr_pstrcat(r->pool, new_cookie, "; ",
|
||||
+ dcfg->samesite,
|
||||
+ NULL);
|
||||
+ }
|
||||
+ if (dcfg->is_secure) {
|
||||
+ new_cookie = apr_pstrcat(r->pool, new_cookie, "; Secure",
|
||||
+ NULL);
|
||||
+ }
|
||||
+ if (dcfg->is_httponly) {
|
||||
+ new_cookie = apr_pstrcat(r->pool, new_cookie, "; HttpOnly",
|
||||
+ NULL);
|
||||
+ }
|
||||
+
|
||||
+
|
||||
|
||||
apr_table_addn(r->err_headers_out,
|
||||
(dcfg->style == CT_COOKIE2 ? "Set-Cookie2" : "Set-Cookie"),
|
||||
@@ -269,6 +287,7 @@ static void *make_cookie_dir(apr_pool_t *p, char *d)
|
||||
dcfg->cookie_domain = NULL;
|
||||
dcfg->style = CT_UNSET;
|
||||
dcfg->enabled = 0;
|
||||
+ /* calloc'ed to disabled: samesite, is_secure, is_httponly */
|
||||
|
||||
/* In case the user does not use the CookieName directive,
|
||||
* we need to compile the regexp for the default cookie name. */
|
||||
@@ -429,6 +448,31 @@ static const char *set_cookie_style(cmd_parms *cmd, void *mconfig,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * SameSite enabled disabled
|
||||
+ */
|
||||
+
|
||||
+static const char *set_samesite_value(cmd_parms *cmd, void *mconfig,
|
||||
+ const char *name)
|
||||
+{
|
||||
+ cookie_dir_rec *dcfg;
|
||||
+
|
||||
+ dcfg = (cookie_dir_rec *) mconfig;
|
||||
+
|
||||
+ if (strcasecmp(name, "strict") == 0) {
|
||||
+ dcfg->samesite = "SameSite=Strict";
|
||||
+ } else if (strcasecmp(name, "lax") == 0) {
|
||||
+ dcfg->samesite = "SameSite=Lax";
|
||||
+ } else if (strcasecmp(name, "none") == 0) {
|
||||
+ dcfg->samesite = "SameSite=None";
|
||||
+ } else {
|
||||
+ return "CookieSameSite accepts 'Strict', 'Lax', or 'None'";
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
static const command_rec cookie_log_cmds[] = {
|
||||
AP_INIT_TAKE1("CookieExpires", set_cookie_exp, NULL, OR_FILEINFO,
|
||||
"an expiry date code"),
|
||||
@@ -440,6 +484,17 @@ static const command_rec cookie_log_cmds[] = {
|
||||
"whether or not to enable cookies"),
|
||||
AP_INIT_TAKE1("CookieName", set_cookie_name, NULL, OR_FILEINFO,
|
||||
"name of the tracking cookie"),
|
||||
+ AP_INIT_FLAG("CookieTracking", set_cookie_enable, NULL, OR_FILEINFO,
|
||||
+ "whether or not to enable cookies"),
|
||||
+ AP_INIT_TAKE1("CookieSameSite", set_samesite_value, NULL, OR_FILEINFO,
|
||||
+ "SameSite setting"),
|
||||
+ AP_INIT_FLAG("CookieSecure", ap_set_flag_slot,
|
||||
+ (void *)APR_OFFSETOF(cookie_dir_rec, is_secure), OR_FILEINFO,
|
||||
+ "is cookie secure"),
|
||||
+ AP_INIT_FLAG("CookieHttpOnly", ap_set_flag_slot,
|
||||
+ (void *)APR_OFFSETOF(cookie_dir_rec, is_httponly),OR_FILEINFO,
|
||||
+ "is cookie http only"),
|
||||
+
|
||||
{NULL}
|
||||
};
|
||||
|
@ -1,8 +1,8 @@
|
||||
diff --git a/support/apxs.in b/support/apxs.in
|
||||
index ad1287f..efcfcf6 100644
|
||||
index b2705fa..c331631 100644
|
||||
--- a/support/apxs.in
|
||||
+++ b/support/apxs.in
|
||||
@@ -25,7 +25,18 @@ package apxs;
|
||||
@@ -35,7 +35,18 @@ if ($ddi >= 0) {
|
||||
|
||||
my %config_vars = ();
|
||||
|
||||
@ -19,10 +19,10 @@ index ad1287f..efcfcf6 100644
|
||||
+
|
||||
+my $installbuilddir = $libdir . "/httpd/build";
|
||||
+
|
||||
get_config_vars("$installbuilddir/config_vars.mk",\%config_vars);
|
||||
get_config_vars($destdir . "$installbuilddir/config_vars.mk",\%config_vars);
|
||||
|
||||
# read the configuration variables once
|
||||
@@ -275,7 +286,7 @@ if ($opt_g) {
|
||||
@@ -285,7 +296,7 @@ if ($opt_g) {
|
||||
$data =~ s|%NAME%|$name|sg;
|
||||
$data =~ s|%TARGET%|$CFG_TARGET|sg;
|
||||
$data =~ s|%PREFIX%|$prefix|sg;
|
||||
@ -31,7 +31,7 @@ index ad1287f..efcfcf6 100644
|
||||
|
||||
my ($mkf, $mods, $src) = ($data =~ m|^(.+)-=#=-\n(.+)-=#=-\n(.+)|s);
|
||||
|
||||
@@ -453,11 +464,11 @@ if ($opt_c) {
|
||||
@@ -463,11 +474,11 @@ if ($opt_c) {
|
||||
my $ldflags = "$CFG_LDFLAGS";
|
||||
if ($opt_p == 1) {
|
||||
|
||||
@ -45,7 +45,7 @@ index ad1287f..efcfcf6 100644
|
||||
chomp($apu_libs);
|
||||
}
|
||||
|
||||
@@ -672,8 +683,8 @@ __DATA__
|
||||
@@ -682,8 +693,8 @@ __DATA__
|
||||
|
||||
builddir=.
|
||||
top_srcdir=%PREFIX%
|
@ -13,7 +13,7 @@ index 6b92151..4c42a8e 100644
|
||||
|
||||
/* A linked-list of authn providers. */
|
||||
diff --git a/modules/cache/mod_cache.c b/modules/cache/mod_cache.c
|
||||
index 56a09f5..41015b5 100644
|
||||
index 3b9aa4f..8268503 100644
|
||||
--- a/modules/cache/mod_cache.c
|
||||
+++ b/modules/cache/mod_cache.c
|
||||
@@ -1455,6 +1455,11 @@ static apr_status_t cache_save_filter(ap_filter_t *f, apr_bucket_brigade *in)
|
@ -1,15 +1,8 @@
|
||||
|
||||
Bump up the core size limit if CoreDumpDirectory is
|
||||
configured.
|
||||
|
||||
Upstream-Status: Was discussed but there are competing desires;
|
||||
there are portability oddities here too.
|
||||
|
||||
diff --git a/server/core.c b/server/core.c
|
||||
index aa62e15..ec74029 100644
|
||||
index 79b2a82..dc0f17a 100644
|
||||
--- a/server/core.c
|
||||
+++ b/server/core.c
|
||||
@@ -4952,6 +4952,25 @@ static int core_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *pte
|
||||
@@ -4996,6 +4996,25 @@ static int core_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *pte
|
||||
}
|
||||
apr_pool_cleanup_register(pconf, NULL, ap_mpm_end_gen_helper,
|
||||
apr_pool_cleanup_null);
|
@ -1,13 +1,8 @@
|
||||
|
||||
Link straight against .la files.
|
||||
|
||||
Upstream-Status: vendor specific
|
||||
|
||||
diff --git a/configure.in b/configure.in
|
||||
index 9feaceb..82bfeef 100644
|
||||
index f8f9442..f276550 100644
|
||||
--- a/configure.in
|
||||
+++ b/configure.in
|
||||
@@ -784,9 +784,9 @@ APACHE_SUBST(INSTALL_SUEXEC)
|
||||
@@ -786,9 +786,9 @@ APACHE_SUBST(INSTALL_SUEXEC)
|
||||
|
||||
dnl APR should go after the other libs, so the right symbols can be picked up
|
||||
if test x${apu_found} != xobsolete; then
|
62
SOURCES/httpd-2.4.43-enable-sslv3.patch
Normal file
62
SOURCES/httpd-2.4.43-enable-sslv3.patch
Normal file
@ -0,0 +1,62 @@
|
||||
diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c
|
||||
index 979489c..3d6443b 100644
|
||||
--- a/modules/ssl/ssl_engine_config.c
|
||||
+++ b/modules/ssl/ssl_engine_config.c
|
||||
@@ -1485,6 +1485,10 @@ static const char *ssl_cmd_protocol_parse(cmd_parms *parms,
|
||||
#endif
|
||||
else if (strcEQ(w, "all")) {
|
||||
thisopt = SSL_PROTOCOL_ALL;
|
||||
+#ifndef OPENSSL_NO_SSL3
|
||||
+ /* by default, ALL kw doesn't turn on SSLv3 */
|
||||
+ thisopt &= ~SSL_PROTOCOL_SSLV3;
|
||||
+#endif
|
||||
}
|
||||
else {
|
||||
return apr_pstrcat(parms->temp_pool,
|
||||
diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c
|
||||
index b0fcf81..ab6f263 100644
|
||||
--- a/modules/ssl/ssl_engine_init.c
|
||||
+++ b/modules/ssl/ssl_engine_init.c
|
||||
@@ -568,6 +568,28 @@ static apr_status_t ssl_init_ctx_tls_extensions(server_rec *s,
|
||||
}
|
||||
#endif
|
||||
|
||||
+/*
|
||||
+ * Enable/disable SSLProtocol. If the mod_ssl enables protocol
|
||||
+ * which is disabled by default by OpenSSL, show a warning.
|
||||
+ * "option" is for example SSL_OP_NO_SSLv3.
|
||||
+ */
|
||||
+static void ssl_set_ctx_protocol_option(server_rec *s,
|
||||
+ SSL_CTX *ctx,
|
||||
+ long option,
|
||||
+ int enabled,
|
||||
+ const char *name)
|
||||
+{
|
||||
+ if (!enabled) {
|
||||
+ SSL_CTX_set_options(ctx, option);
|
||||
+ }
|
||||
+ else if (SSL_CTX_get_options(ctx) & option) {
|
||||
+ SSL_CTX_clear_options(ctx, option);
|
||||
+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(02904)
|
||||
+ "Allowing SSLProtocol %s even though it is disabled "
|
||||
+ "by OpenSSL by default on this system", name);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static apr_status_t ssl_init_ctx_protocol(server_rec *s,
|
||||
apr_pool_t *p,
|
||||
apr_pool_t *ptemp,
|
||||
@@ -735,9 +757,13 @@ static apr_status_t ssl_init_ctx_protocol(server_rec *s,
|
||||
}
|
||||
if (prot == TLS1_1_VERSION && protocol & SSL_PROTOCOL_TLSV1) {
|
||||
prot = TLS1_VERSION;
|
||||
+ ssl_set_ctx_protocol_option(s, ctx, SSL_OP_NO_TLSv1,
|
||||
+ protocol & SSL_PROTOCOL_TLSV1, "TLSv1");
|
||||
}
|
||||
#ifndef OPENSSL_NO_SSL3
|
||||
if (prot == TLS1_VERSION && protocol & SSL_PROTOCOL_SSLV3) {
|
||||
+ ssl_set_ctx_protocol_option(s, ctx, SSL_OP_NO_SSLv3,
|
||||
+ protocol & SSL_PROTOCOL_SSLV3, "SSLv3");
|
||||
prot = SSL3_VERSION;
|
||||
}
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user