c8-beta-stream-2.4
imports/c8-beta-stream-2.4/httpd-2.4.37-64.module+el8.10.0+21332+dfb1b40e
commit
b358660041
@ -0,0 +1,2 @@
|
||||
SOURCES/apache-poweredby.png
|
||||
SOURCES/httpd-2.4.37.tar.bz2
|
@ -0,0 +1,2 @@
|
||||
3a7449d6cff00e5ccb3ed8571f34c0528555d38f SOURCES/apache-poweredby.png
|
||||
4a38471de821288b0300148016f2b03dfee8adf2 SOURCES/httpd-2.4.37.tar.bz2
|
@ -0,0 +1,68 @@
|
||||
#
|
||||
# This file loads most of the modules included with the Apache HTTP
|
||||
# Server itself.
|
||||
#
|
||||
|
||||
LoadModule access_compat_module modules/mod_access_compat.so
|
||||
LoadModule actions_module modules/mod_actions.so
|
||||
LoadModule alias_module modules/mod_alias.so
|
||||
LoadModule allowmethods_module modules/mod_allowmethods.so
|
||||
LoadModule auth_basic_module modules/mod_auth_basic.so
|
||||
LoadModule auth_digest_module modules/mod_auth_digest.so
|
||||
LoadModule authn_anon_module modules/mod_authn_anon.so
|
||||
LoadModule authn_core_module modules/mod_authn_core.so
|
||||
LoadModule authn_dbd_module modules/mod_authn_dbd.so
|
||||
LoadModule authn_dbm_module modules/mod_authn_dbm.so
|
||||
LoadModule authn_file_module modules/mod_authn_file.so
|
||||
LoadModule authn_socache_module modules/mod_authn_socache.so
|
||||
LoadModule authz_core_module modules/mod_authz_core.so
|
||||
LoadModule authz_dbd_module modules/mod_authz_dbd.so
|
||||
LoadModule authz_dbm_module modules/mod_authz_dbm.so
|
||||
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
|
||||
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
|
||||
LoadModule data_module modules/mod_data.so
|
||||
LoadModule dbd_module modules/mod_dbd.so
|
||||
LoadModule deflate_module modules/mod_deflate.so
|
||||
LoadModule dir_module modules/mod_dir.so
|
||||
LoadModule dumpio_module modules/mod_dumpio.so
|
||||
LoadModule echo_module modules/mod_echo.so
|
||||
LoadModule env_module modules/mod_env.so
|
||||
LoadModule expires_module modules/mod_expires.so
|
||||
LoadModule ext_filter_module modules/mod_ext_filter.so
|
||||
LoadModule filter_module modules/mod_filter.so
|
||||
LoadModule headers_module modules/mod_headers.so
|
||||
LoadModule include_module modules/mod_include.so
|
||||
LoadModule info_module modules/mod_info.so
|
||||
LoadModule log_config_module modules/mod_log_config.so
|
||||
LoadModule logio_module modules/mod_logio.so
|
||||
LoadModule macro_module modules/mod_macro.so
|
||||
LoadModule mime_magic_module modules/mod_mime_magic.so
|
||||
LoadModule mime_module modules/mod_mime.so
|
||||
LoadModule negotiation_module modules/mod_negotiation.so
|
||||
LoadModule remoteip_module modules/mod_remoteip.so
|
||||
LoadModule reqtimeout_module modules/mod_reqtimeout.so
|
||||
LoadModule request_module modules/mod_request.so
|
||||
LoadModule rewrite_module modules/mod_rewrite.so
|
||||
LoadModule setenvif_module modules/mod_setenvif.so
|
||||
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_shmcb_module modules/mod_socache_shmcb.so
|
||||
LoadModule status_module modules/mod_status.so
|
||||
LoadModule substitute_module modules/mod_substitute.so
|
||||
LoadModule suexec_module modules/mod_suexec.so
|
||||
LoadModule unique_id_module modules/mod_unique_id.so
|
||||
LoadModule unixd_module modules/mod_unixd.so
|
||||
LoadModule userdir_module modules/mod_userdir.so
|
||||
LoadModule version_module modules/mod_version.so
|
||||
LoadModule vhost_alias_module modules/mod_vhost_alias.so
|
||||
LoadModule watchdog_module modules/mod_watchdog.so
|
||||
|
@ -0,0 +1,3 @@
|
||||
LoadModule dav_module modules/mod_dav.so
|
||||
LoadModule dav_fs_module modules/mod_dav_fs.so
|
||||
LoadModule dav_lock_module modules/mod_dav_lock.so
|
@ -0,0 +1 @@
|
||||
LoadModule lua_module modules/mod_lua.so
|
@ -0,0 +1,23 @@
|
||||
# Select the MPM module which should be used by uncommenting exactly
|
||||
# one of the following LoadModule lines. See the httpd.conf(5) man
|
||||
# page for more information on changing the MPM.
|
||||
|
||||
# prefork MPM: Implements a non-threaded, pre-forking web server
|
||||
# See: http://httpd.apache.org/docs/2.4/mod/prefork.html
|
||||
#
|
||||
# NOTE: If enabling prefork, the httpd_graceful_shutdown SELinux
|
||||
# boolean should be enabled, to allow graceful stop/shutdown.
|
||||
#
|
||||
#LoadModule mpm_prefork_module modules/mod_mpm_prefork.so
|
||||
|
||||
# worker MPM: Multi-Processing Module implementing a hybrid
|
||||
# multi-threaded multi-process web server
|
||||
# See: http://httpd.apache.org/docs/2.4/mod/worker.html
|
||||
#
|
||||
#LoadModule mpm_worker_module modules/mod_mpm_worker.so
|
||||
|
||||
# event MPM: A variant of the worker MPM with the goal of consuming
|
||||
# threads only for connections with active processing
|
||||
# See: http://httpd.apache.org/docs/2.4/mod/event.html
|
||||
#
|
||||
#LoadModule mpm_event_module modules/mod_mpm_event.so
|
@ -0,0 +1,18 @@
|
||||
#
|
||||
# This file lists modules included with the Apache HTTP Server
|
||||
# which are not enabled by default.
|
||||
#
|
||||
|
||||
#LoadModule asis_module modules/mod_asis.so
|
||||
#LoadModule buffer_module modules/mod_buffer.so
|
||||
#LoadModule heartbeat_module modules/mod_heartbeat.so
|
||||
#LoadModule heartmonitor_module modules/mod_heartmonitor.so
|
||||
#LoadModule usertrack_module modules/mod_usertrack.so
|
||||
#LoadModule dialup_module modules/mod_dialup.so
|
||||
#LoadModule charset_lite_module modules/mod_charset_lite.so
|
||||
#LoadModule log_debug_module modules/mod_log_debug.so
|
||||
#LoadModule log_forensic_module modules/mod_log_forensic.so
|
||||
#LoadModule ratelimit_module modules/mod_ratelimit.so
|
||||
#LoadModule reflector_module modules/mod_reflector.so
|
||||
#LoadModule sed_module modules/mod_sed.so
|
||||
#LoadModule speling_module modules/mod_speling.so
|
@ -0,0 +1,18 @@
|
||||
# This file configures all the proxy modules:
|
||||
LoadModule proxy_module modules/mod_proxy.so
|
||||
LoadModule lbmethod_bybusyness_module modules/mod_lbmethod_bybusyness.so
|
||||
LoadModule lbmethod_byrequests_module modules/mod_lbmethod_byrequests.so
|
||||
LoadModule lbmethod_bytraffic_module modules/mod_lbmethod_bytraffic.so
|
||||
LoadModule lbmethod_heartbeat_module modules/mod_lbmethod_heartbeat.so
|
||||
LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
|
||||
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
|
||||
LoadModule proxy_connect_module modules/mod_proxy_connect.so
|
||||
LoadModule proxy_express_module modules/mod_proxy_express.so
|
||||
LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so
|
||||
LoadModule proxy_fdpass_module modules/mod_proxy_fdpass.so
|
||||
LoadModule proxy_ftp_module modules/mod_proxy_ftp.so
|
||||
LoadModule proxy_http_module modules/mod_proxy_http.so
|
||||
LoadModule proxy_hcheck_module modules/mod_proxy_hcheck.so
|
||||
LoadModule proxy_scgi_module modules/mod_proxy_scgi.so
|
||||
LoadModule proxy_uwsgi_module modules/mod_proxy_uwsgi.so
|
||||
LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
|
@ -0,0 +1,3 @@
|
||||
# This file configures mod_proxy_html and mod_xml2enc:
|
||||
LoadModule xml2enc_module modules/mod_xml2enc.so
|
||||
LoadModule proxy_html_module modules/mod_proxy_html.so
|
@ -0,0 +1 @@
|
||||
LoadModule ssl_module modules/mod_ssl.so
|
@ -0,0 +1,2 @@
|
||||
# This file configures systemd module:
|
||||
LoadModule systemd_module modules/mod_systemd.so
|
@ -0,0 +1,14 @@
|
||||
# This configuration file loads a CGI module appropriate to the MPM
|
||||
# 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>
|
||||
LoadModule cgid_module modules/mod_cgid.so
|
||||
</IfModule>
|
||||
<IfModule mpm_prefork_module>
|
||||
LoadModule cgi_module modules/mod_cgi.so
|
||||
</IfModule>
|
||||
|
@ -0,0 +1,3 @@
|
||||
# This file configures the LDAP modules:
|
||||
LoadModule ldap_module modules/mod_ldap.so
|
||||
LoadModule authnz_ldap_module modules/mod_authnz_ldap.so
|
@ -0,0 +1,6 @@
|
||||
LoadModule session_module modules/mod_session.so
|
||||
LoadModule session_cookie_module modules/mod_session_cookie.so
|
||||
LoadModule session_dbd_module modules/mod_session_dbd.so
|
||||
LoadModule auth_form_module modules/mod_auth_form.so
|
||||
|
||||
#LoadModule session_crypto_module modules/mod_session_crypto.so
|
@ -0,0 +1,5 @@
|
||||
# This file is part of mod_ssl. It enables listening on port 443 when
|
||||
# socket activation is used.
|
||||
|
||||
[Socket]
|
||||
ListenStream=443
|
@ -0,0 +1,9 @@
|
||||
|
||||
This directory holds configuration files for the Apache HTTP Server;
|
||||
any files in this directory which have the ".conf" extension will be
|
||||
processed as httpd configuration files. The directory is used in
|
||||
addition to the directory /etc/httpd/conf.modules.d/, which contains
|
||||
configuration files necessary to load modules.
|
||||
|
||||
Files are processed in sorted order. See httpd.conf(5) for more
|
||||
information.
|
@ -0,0 +1,10 @@
|
||||
|
||||
This directory holds configuration files for the Apache HTTP Server;
|
||||
any files in this directory which have the ".conf" extension will be
|
||||
processed as httpd configuration files. This directory contains
|
||||
configuration fragments necessary only to load modules.
|
||||
Administrators should use the directory "/etc/httpd/conf.d" to modify
|
||||
the configuration of httpd, or any modules.
|
||||
|
||||
Files are processed in sorted order and should have a two digit
|
||||
numeric prefix. See httpd.conf(5) for more information.
|
@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
exec /sbin/apachectl configtest "$@"
|
@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
exec /sbin/apachectl graceful "$@"
|
@ -0,0 +1,24 @@
|
||||
# Layout used in Fedora httpd packaging.
|
||||
<Layout Fedora>
|
||||
prefix: /etc/httpd
|
||||
localstatedir: /var
|
||||
exec_prefix: /usr
|
||||
bindir: ${exec_prefix}/bin
|
||||
sbindir: ${exec_prefix}/sbin
|
||||
libdir: ${exec_prefix}/lib
|
||||
libexecdir: ${exec_prefix}/libexec
|
||||
mandir: ${exec_prefix}/man
|
||||
sysconfdir: /etc/httpd/conf
|
||||
datadir: ${exec_prefix}/share/httpd
|
||||
installbuilddir: ${libdir}/httpd/build
|
||||
errordir: ${datadir}/error
|
||||
iconsdir: ${datadir}/icons
|
||||
htdocsdir: ${localstatedir}/www/html
|
||||
manualdir: ${datadir}/manual
|
||||
cgidir: ${localstatedir}/www/cgi-bin
|
||||
includedir: ${exec_prefix}/include/httpd
|
||||
runtimedir: ${prefix}/run
|
||||
logfiledir: ${localstatedir}/log/httpd
|
||||
statedir: ${prefix}/state
|
||||
proxycachedir: ${localstatedir}/cache/httpd/proxy
|
||||
</Layout>
|
@ -0,0 +1,11 @@
|
||||
[Unit]
|
||||
Description=Disk Cache Cleaning Daemon for the Apache HTTP Server
|
||||
After=httpd.service
|
||||
Documentation=man:htcacheclean.service(8)
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
User=apache
|
||||
PIDFile=/run/httpd/htcacheclean/pid
|
||||
EnvironmentFile=/etc/sysconfig/htcacheclean
|
||||
ExecStart=/usr/sbin/htcacheclean -P /run/httpd/htcacheclean/pid -d $INTERVAL -p $CACHE_ROOT -l $LIMIT $OPTIONS
|
@ -0,0 +1,123 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
|
||||
|
||||
]>
|
||||
<!--
|
||||
Copyright 2018 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 overning permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<refentry>
|
||||
<refentryinfo>
|
||||
<title>htcacheclean systemd unit</title>
|
||||
<productname>httpd</productname>
|
||||
<author><contrib>Author</contrib><surname>Orton</surname><firstname>Joe</firstname><email>jorton@redhat.com</email></author>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>htcacheclean.service</refentrytitle>
|
||||
<manvolnum>8</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>htcacheclean.service</refname>
|
||||
<refpurpose>htcacheclean unit file for systemd</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<para>
|
||||
<filename>/usr/lib/systemd/system/htcacheclean.service</filename>
|
||||
</para>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para>This manual page describes the <command>systemd</command>
|
||||
unit file for the <command>htcacheclean</command> daemon. This
|
||||
unit file provides a service which runs
|
||||
<command>htcacheclean</command> in daemon mode,
|
||||
periodically cleaning the disk cache root to ensure disk space
|
||||
usage is within configured limits.</para>
|
||||
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Options</title>
|
||||
|
||||
<para>The service is configured by configuration file
|
||||
<filename>/etc/sysconfig/htcacheclean</filename>. The following
|
||||
variables are used, following standard <command>systemd</command>
|
||||
<varname>EnvironmentFile=</varname> syntax:</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><varname>INTERVAL=</varname></term>
|
||||
|
||||
<listitem><para>Sets the interval between cache clean runs, in
|
||||
minutes. By default this is configured as
|
||||
<emphasis>15</emphasis>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>CACHE_ROOT=</varname></term>
|
||||
|
||||
<listitem><para>Sets the directory name used for the cache
|
||||
root. By default this is configured as
|
||||
<filename>/var/cache/httpd/proxy</filename>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>LIMIT=</varname></term>
|
||||
|
||||
<listitem><para>Sets the total disk cache space limit, in
|
||||
bytes. Use a <emphasis>K</emphasis> or <emphasis>M</emphasis>
|
||||
suffix to signify kilobytes or megabytes. By default this is
|
||||
set to <emphasis>100M</emphasis>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>OPTIONS=</varname></term>
|
||||
|
||||
<listitem><para>Any other options to pass to
|
||||
<command>htcacheclean</command>.</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Files</title>
|
||||
|
||||
<para><filename>/usr/lib/systemd/system/htcacheclean.service</filename>,
|
||||
<filename>/etc/sysconfig/htcacheclean</filename></para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See also</title>
|
||||
|
||||
<para>
|
||||
<citerefentry><refentrytitle>htcacheclean</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>httpd</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>httpd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
||||
|
||||
<!-- LocalWords: systemd httpd htcacheclean
|
||||
-->
|
@ -0,0 +1,16 @@
|
||||
#
|
||||
# Configuration options for systemd service, htcacheclean.service.
|
||||
# See htcacheclean(8) for more information on available options.
|
||||
#
|
||||
|
||||
# Interval between cache clean runs, in minutes
|
||||
INTERVAL=15
|
||||
|
||||
# Default cache root.
|
||||
CACHE_ROOT=/var/cache/httpd/proxy
|
||||
|
||||
# Cache size limit in bytes (K=Kbytes, M=Mbytes)
|
||||
LIMIT=100M
|
||||
|
||||
# Any other options...
|
||||
OPTIONS=
|
@ -0,0 +1,58 @@
|
||||
diff --git a/support/apxs.in b/support/apxs.in
|
||||
index ad1287f..efcfcf6 100644
|
||||
--- a/support/apxs.in
|
||||
+++ b/support/apxs.in
|
||||
@@ -25,7 +25,18 @@ package apxs;
|
||||
|
||||
my %config_vars = ();
|
||||
|
||||
-my $installbuilddir = "@exp_installbuilddir@";
|
||||
+# Awful hack to make apxs libdir-agnostic:
|
||||
+my $pkg_config = "/usr/bin/pkg-config";
|
||||
+if (! -x "$pkg_config") {
|
||||
+ error("$pkg_config not found!");
|
||||
+ exit(1);
|
||||
+}
|
||||
+
|
||||
+my $libdir = `pkg-config --variable=libdir apr-1`;
|
||||
+chomp $libdir;
|
||||
+
|
||||
+my $installbuilddir = $libdir . "/httpd/build";
|
||||
+
|
||||
get_config_vars("$installbuilddir/config_vars.mk",\%config_vars);
|
||||
|
||||
# read the configuration variables once
|
||||
@@ -275,7 +286,7 @@ if ($opt_g) {
|
||||
$data =~ s|%NAME%|$name|sg;
|
||||
$data =~ s|%TARGET%|$CFG_TARGET|sg;
|
||||
$data =~ s|%PREFIX%|$prefix|sg;
|
||||
- $data =~ s|%INSTALLBUILDDIR%|$installbuilddir|sg;
|
||||
+ $data =~ s|%LIBDIR%|$libdir|sg;
|
||||
|
||||
my ($mkf, $mods, $src) = ($data =~ m|^(.+)-=#=-\n(.+)-=#=-\n(.+)|s);
|
||||
|
||||
@@ -453,11 +464,11 @@ if ($opt_c) {
|
||||
my $ldflags = "$CFG_LDFLAGS";
|
||||
if ($opt_p == 1) {
|
||||
|
||||
- my $apr_libs=`$apr_config --cflags --ldflags --link-libtool --libs`;
|
||||
+ my $apr_libs=`$apr_config --cflags --ldflags --link-libtool`;
|
||||
chomp($apr_libs);
|
||||
my $apu_libs="";
|
||||
if ($apr_major_version < 2) {
|
||||
- $apu_libs=`$apu_config --ldflags --link-libtool --libs`;
|
||||
+ $apu_libs=`$apu_config --ldflags --link-libtool`;
|
||||
chomp($apu_libs);
|
||||
}
|
||||
|
||||
@@ -672,8 +683,8 @@ __DATA__
|
||||
|
||||
builddir=.
|
||||
top_srcdir=%PREFIX%
|
||||
-top_builddir=%PREFIX%
|
||||
-include %INSTALLBUILDDIR%/special.mk
|
||||
+top_builddir=%LIBDIR%/httpd
|
||||
+include %LIBDIR%/httpd/build/special.mk
|
||||
|
||||
# the used tools
|
||||
APACHECTL=apachectl
|
@ -0,0 +1,29 @@
|
||||
|
||||
- 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
|
@ -0,0 +1,81 @@
|
||||
diff --git a/server/util_script.c b/server/util_script.c
|
||||
index 4121ae0..b7f8674 100644
|
||||
--- a/server/util_script.c
|
||||
+++ b/server/util_script.c
|
||||
@@ -92,9 +92,21 @@ static void add_unless_null(apr_table_t *table, const char *name, const char *va
|
||||
}
|
||||
}
|
||||
|
||||
-static void env2env(apr_table_t *table, const char *name)
|
||||
+/* Sets variable @name in table @dest from r->subprocess_env if
|
||||
+ * available, else from the environment, else from @fallback if
|
||||
+ * non-NULL. */
|
||||
+static void env2env(apr_table_t *dest, request_rec *r,
|
||||
+ const char *name, const char *fallback)
|
||||
{
|
||||
- add_unless_null(table, name, getenv(name));
|
||||
+ const char *val;
|
||||
+
|
||||
+ val = apr_table_get(r->subprocess_env, name);
|
||||
+ if (!val)
|
||||
+ val = apr_pstrdup(r->pool, getenv(name));
|
||||
+ if (!val)
|
||||
+ val = apr_pstrdup(r->pool, fallback);
|
||||
+ if (val)
|
||||
+ apr_table_addn(dest, name, val);
|
||||
}
|
||||
|
||||
AP_DECLARE(char **) ap_create_environment(apr_pool_t *p, apr_table_t *t)
|
||||
@@ -211,37 +223,29 @@ AP_DECLARE(void) ap_add_common_vars(request_rec *r)
|
||||
add_unless_null(e, http2env(r, hdrs[i].key), hdrs[i].val);
|
||||
}
|
||||
|
||||
- env_temp = apr_table_get(r->subprocess_env, "PATH");
|
||||
- if (env_temp == NULL) {
|
||||
- env_temp = getenv("PATH");
|
||||
- }
|
||||
- if (env_temp == NULL) {
|
||||
- env_temp = DEFAULT_PATH;
|
||||
- }
|
||||
- apr_table_addn(e, "PATH", apr_pstrdup(r->pool, env_temp));
|
||||
-
|
||||
+ env2env(e, r, "PATH", DEFAULT_PATH);
|
||||
#if defined(WIN32)
|
||||
- env2env(e, "SystemRoot");
|
||||
- env2env(e, "COMSPEC");
|
||||
- env2env(e, "PATHEXT");
|
||||
- env2env(e, "WINDIR");
|
||||
+ env2env(e, r, "SystemRoot", NULL);
|
||||
+ env2env(e, r, "COMSPEC", NULL);
|
||||
+ env2env(e, r, "PATHEXT", NULL);
|
||||
+ env2env(e, r, "WINDIR", NULL);
|
||||
#elif defined(OS2)
|
||||
- env2env(e, "COMSPEC");
|
||||
- env2env(e, "ETC");
|
||||
- env2env(e, "DPATH");
|
||||
- env2env(e, "PERLLIB_PREFIX");
|
||||
+ env2env(e, r, "COMSPEC", NULL);
|
||||
+ env2env(e, r, "ETC", NULL);
|
||||
+ env2env(e, r, "DPATH", NULL);
|
||||
+ env2env(e, r, "PERLLIB_PREFIX", NULL);
|
||||
#elif defined(BEOS)
|
||||
- env2env(e, "LIBRARY_PATH");
|
||||
+ env2env(e, r, "LIBRARY_PATH", NULL);
|
||||
#elif defined(DARWIN)
|
||||
- env2env(e, "DYLD_LIBRARY_PATH");
|
||||
+ env2env(e, r, "DYLD_LIBRARY_PATH", NULL);
|
||||
#elif defined(_AIX)
|
||||
- env2env(e, "LIBPATH");
|
||||
+ env2env(e, r, "LIBPATH", NULL);
|
||||
#elif defined(__HPUX__)
|
||||
/* HPUX PARISC 2.0W knows both, otherwise redundancy is harmless */
|
||||
- env2env(e, "SHLIB_PATH");
|
||||
- env2env(e, "LD_LIBRARY_PATH");
|
||||
+ env2env(e, r, "SHLIB_PATH", NULL);
|
||||
+ env2env(e, r, "LD_LIBRARY_PATH", NULL);
|
||||
#else /* Some Unix */
|
||||
- env2env(e, "LD_LIBRARY_PATH");
|
||||
+ env2env(e, r, "LD_LIBRARY_PATH", NULL);
|
||||
#endif
|
||||
|
||||
apr_table_addn(e, "SERVER_SIGNATURE", ap_psignature("", r));
|
@ -0,0 +1,300 @@
|
||||
diff --git a/server/listen.c b/server/listen.c
|
||||
index a8e9e6f..1a6c1d3 100644
|
||||
--- a/server/listen.c
|
||||
+++ b/server/listen.c
|
||||
@@ -34,6 +34,10 @@
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
+#ifdef HAVE_SYSTEMD
|
||||
+#include <systemd/sd-daemon.h>
|
||||
+#endif
|
||||
+
|
||||
/* we know core's module_index is 0 */
|
||||
#undef APLOG_MODULE_INDEX
|
||||
#define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX
|
||||
@@ -59,9 +63,12 @@ static int ap_listenbacklog;
|
||||
static int ap_listencbratio;
|
||||
static int send_buffer_size;
|
||||
static int receive_buffer_size;
|
||||
+#ifdef HAVE_SYSTEMD
|
||||
+static int use_systemd = -1;
|
||||
+#endif
|
||||
|
||||
/* TODO: make_sock is just begging and screaming for APR abstraction */
|
||||
-static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server)
|
||||
+static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server, int do_bind_listen)
|
||||
{
|
||||
apr_socket_t *s = server->sd;
|
||||
int one = 1;
|
||||
@@ -94,20 +101,6 @@ static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server)
|
||||
return stat;
|
||||
}
|
||||
|
||||
-#if APR_HAVE_IPV6
|
||||
- if (server->bind_addr->family == APR_INET6) {
|
||||
- stat = apr_socket_opt_set(s, APR_IPV6_V6ONLY, v6only_setting);
|
||||
- if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
|
||||
- ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p, APLOGNO(00069)
|
||||
- "make_sock: for address %pI, apr_socket_opt_set: "
|
||||
- "(IPV6_V6ONLY)",
|
||||
- server->bind_addr);
|
||||
- apr_socket_close(s);
|
||||
- return stat;
|
||||
- }
|
||||
- }
|
||||
-#endif
|
||||
-
|
||||
/*
|
||||
* To send data over high bandwidth-delay connections at full
|
||||
* speed we must force the TCP window to open wide enough to keep the
|
||||
@@ -169,21 +162,37 @@ static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server)
|
||||
}
|
||||
#endif
|
||||
|
||||
- if ((stat = apr_socket_bind(s, server->bind_addr)) != APR_SUCCESS) {
|
||||
- ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, stat, p, APLOGNO(00072)
|
||||
- "make_sock: could not bind to address %pI",
|
||||
- server->bind_addr);
|
||||
- apr_socket_close(s);
|
||||
- return stat;
|
||||
- }
|
||||
+ if (do_bind_listen) {
|
||||
+#if APR_HAVE_IPV6
|
||||
+ if (server->bind_addr->family == APR_INET6) {
|
||||
+ stat = apr_socket_opt_set(s, APR_IPV6_V6ONLY, v6only_setting);
|
||||
+ if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
|
||||
+ ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p, APLOGNO(00069)
|
||||
+ "make_sock: for address %pI, apr_socket_opt_set: "
|
||||
+ "(IPV6_V6ONLY)",
|
||||
+ server->bind_addr);
|
||||
+ apr_socket_close(s);
|
||||
+ return stat;
|
||||
+ }
|
||||
+ }
|
||||
+#endif
|
||||
|
||||
- if ((stat = apr_socket_listen(s, ap_listenbacklog)) != APR_SUCCESS) {
|
||||
- ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_ERR, stat, p, APLOGNO(00073)
|
||||
- "make_sock: unable to listen for connections "
|
||||
- "on address %pI",
|
||||
- server->bind_addr);
|
||||
- apr_socket_close(s);
|
||||
- return stat;
|
||||
+ if ((stat = apr_socket_bind(s, server->bind_addr)) != APR_SUCCESS) {
|
||||
+ ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, stat, p, APLOGNO(00072)
|
||||
+ "make_sock: could not bind to address %pI",
|
||||
+ server->bind_addr);
|
||||
+ apr_socket_close(s);
|
||||
+ return stat;
|
||||
+ }
|
||||
+
|
||||
+ if ((stat = apr_socket_listen(s, ap_listenbacklog)) != APR_SUCCESS) {
|
||||
+ ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_ERR, stat, p, APLOGNO(00073)
|
||||
+ "make_sock: unable to listen for connections "
|
||||
+ "on address %pI",
|
||||
+ server->bind_addr);
|
||||
+ apr_socket_close(s);
|
||||
+ return stat;
|
||||
+ }
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
@@ -315,6 +324,123 @@ static int find_listeners(ap_listen_rec **from, ap_listen_rec **to,
|
||||
return found;
|
||||
}
|
||||
|
||||
+#ifdef HAVE_SYSTEMD
|
||||
+
|
||||
+static int find_systemd_socket(process_rec * process, apr_port_t port) {
|
||||
+ int fdcount, fd;
|
||||
+ int sdc = sd_listen_fds(0);
|
||||
+
|
||||
+ if (sdc < 0) {
|
||||
+ ap_log_perror(APLOG_MARK, APLOG_CRIT, sdc, process->pool, APLOGNO(02486)
|
||||
+ "find_systemd_socket: Error parsing enviroment, sd_listen_fds returned %d",
|
||||
+ sdc);
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ if (sdc == 0) {
|
||||
+ ap_log_perror(APLOG_MARK, APLOG_CRIT, sdc, process->pool, APLOGNO(02487)
|
||||
+ "find_systemd_socket: At least one socket must be set.");
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ fdcount = atoi(getenv("LISTEN_FDS"));
|
||||
+ for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + fdcount; fd++) {
|
||||
+ if (sd_is_socket_inet(fd, 0, 0, -1, port) > 0) {
|
||||
+ return fd;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return -1;
|
||||
+}
|
||||
+
|
||||
+static apr_status_t alloc_systemd_listener(process_rec * process,
|
||||
+ int fd, const char *proto,
|
||||
+ ap_listen_rec **out_rec)
|
||||
+{
|
||||
+ apr_status_t rv;
|
||||
+ struct sockaddr sa;
|
||||
+ socklen_t len = sizeof(struct sockaddr);
|
||||
+ apr_os_sock_info_t si;
|
||||
+ ap_listen_rec *rec;
|
||||
+ *out_rec = NULL;
|
||||
+
|
||||
+ memset(&si, 0, sizeof(si));
|
||||
+
|
||||
+ rv = getsockname(fd, &sa, &len);
|
||||
+
|
||||
+ if (rv != 0) {
|
||||
+ rv = apr_get_netos_error();
|
||||
+ ap_log_perror(APLOG_MARK, APLOG_CRIT, rv, process->pool, APLOGNO(02489)
|
||||
+ "getsockname on %d failed.", fd);
|
||||
+ return rv;
|
||||
+ }
|
||||
+
|
||||
+ si.os_sock = &fd;
|
||||
+ si.family = sa.sa_family;
|
||||
+ si.local = &sa;
|
||||
+ si.type = SOCK_STREAM;
|
||||
+ si.protocol = APR_PROTO_TCP;
|
||||
+
|
||||
+ rec = apr_palloc(process->pool, sizeof(ap_listen_rec));
|
||||
+ rec->active = 0;
|
||||
+ rec->next = 0;
|
||||
+
|
||||
+
|
||||
+ rv = apr_os_sock_make(&rec->sd, &si, process->pool);
|
||||
+ if (rv != APR_SUCCESS) {
|
||||
+ ap_log_perror(APLOG_MARK, APLOG_CRIT, rv, process->pool, APLOGNO(02490)
|
||||
+ "apr_os_sock_make on %d failed.", fd);
|
||||
+ return rv;
|
||||
+ }
|
||||
+
|
||||
+ rv = apr_socket_addr_get(&rec->bind_addr, APR_LOCAL, rec->sd);
|
||||
+ if (rv != APR_SUCCESS) {
|
||||
+ ap_log_perror(APLOG_MARK, APLOG_CRIT, rv, process->pool, APLOGNO(02491)
|
||||
+ "apr_socket_addr_get on %d failed.", fd);
|
||||
+ return rv;
|
||||
+ }
|
||||
+
|
||||
+ rec->protocol = apr_pstrdup(process->pool, proto);
|
||||
+
|
||||
+ *out_rec = rec;
|
||||
+
|
||||
+ return make_sock(process->pool, rec, 0);
|
||||
+}
|
||||
+
|
||||
+static const char *set_systemd_listener(process_rec *process, apr_port_t port,
|
||||
+ const char *proto)
|
||||
+{
|
||||
+ ap_listen_rec *last, *new;
|
||||
+ apr_status_t rv;
|
||||
+ int fd = find_systemd_socket(process, port);
|
||||
+ if (fd < 0) {
|
||||
+ return "Systemd socket activation is used, but this port is not "
|
||||
+ "configured in systemd";
|
||||
+ }
|
||||
+
|
||||
+ last = ap_listeners;
|
||||
+ while (last && last->next) {
|
||||
+ last = last->next;
|
||||
+ }
|
||||
+
|
||||
+ rv = alloc_systemd_listener(process, fd, proto, &new);
|
||||
+ if (rv != APR_SUCCESS) {
|
||||
+ return "Failed to setup socket passed by systemd using socket activation";
|
||||
+ }
|
||||
+
|
||||
+ if (last == NULL) {
|
||||
+ ap_listeners = last = new;
|
||||
+ }
|
||||
+ else {
|
||||
+ last->next = new;
|
||||
+ last = new;
|
||||
+ }
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+#endif /* HAVE_SYSTEMD */
|
||||
+
|
||||
static const char *alloc_listener(process_rec *process, const char *addr,
|
||||
apr_port_t port, const char* proto,
|
||||
void *slave)
|
||||
@@ -495,7 +621,7 @@ static int open_listeners(apr_pool_t *pool)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
- if (make_sock(pool, lr) == APR_SUCCESS) {
|
||||
+ if (make_sock(pool, lr, 1) == APR_SUCCESS) {
|
||||
++num_open;
|
||||
}
|
||||
else {
|
||||
@@ -607,8 +733,28 @@ AP_DECLARE(int) ap_setup_listeners(server_rec *s)
|
||||
}
|
||||
}
|
||||
|
||||
- if (open_listeners(s->process->pool)) {
|
||||
- return 0;
|
||||
+#ifdef HAVE_SYSTEMD
|
||||
+ if (use_systemd) {
|
||||
+ const char *userdata_key = "ap_open_systemd_listeners";
|
||||
+ void *data;
|
||||
+ /* clear the enviroment on our second run
|
||||
+ * so that none of our future children get confused.
|
||||
+ */
|
||||
+ apr_pool_userdata_get(&data, userdata_key, s->process->pool);
|
||||
+ if (!data) {
|
||||
+ apr_pool_userdata_set((const void *)1, userdata_key,
|
||||
+ apr_pool_cleanup_null, s->process->pool);
|
||||
+ }
|
||||
+ else {
|
||||
+ sd_listen_fds(1);
|
||||
+ }
|
||||
+ }
|
||||
+ else
|
||||
+#endif
|
||||
+ {
|
||||
+ if (open_listeners(s->process->pool)) {
|
||||
+ return 0;
|
||||
+ }
|
||||
}
|
||||
|
||||
for (lr = ap_listeners; lr; lr = lr->next) {
|
||||
@@ -698,7 +844,7 @@ AP_DECLARE(apr_status_t) ap_duplicate_listeners(apr_pool_t *p, server_rec *s,
|
||||
duplr->bind_addr);
|
||||
return stat;
|
||||
}
|
||||
- make_sock(p, duplr);
|
||||
+ make_sock(p, duplr, 1);
|
||||
#if AP_NONBLOCK_WHEN_MULTI_LISTEN
|
||||
use_nonblock = (ap_listeners && ap_listeners->next);
|
||||
stat = apr_socket_opt_set(duplr->sd, APR_SO_NONBLOCK, use_nonblock);
|
||||
@@ -825,6 +971,11 @@ AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy,
|
||||
if (argc < 1 || argc > 2) {
|
||||
return "Listen requires 1 or 2 arguments.";
|
||||
}
|
||||
+#ifdef HAVE_SYSTEMD
|
||||
+ if (use_systemd == -1) {
|
||||
+ use_systemd = sd_listen_fds(0) > 0;
|
||||
+ }
|
||||
+#endif
|
||||
|
||||
rv = apr_parse_addr_port(&host, &scope_id, &port, argv[0], cmd->pool);
|
||||
if (rv != APR_SUCCESS) {
|
||||
@@ -856,6 +1007,12 @@ AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy,
|
||||
ap_str_tolower(proto);
|
||||
}
|
||||
|
||||
+#ifdef HAVE_SYSTEMD
|
||||
+ if (use_systemd) {
|
||||
+ return set_systemd_listener(cmd->server->process, port, proto);
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
return alloc_listener(cmd->server->process, host, port, proto, NULL);
|
||||
}
|
||||
|
@ -0,0 +1,16 @@
|
||||
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;
|
@ -0,0 +1,22 @@
|
||||
|
||||
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
|
@ -0,0 +1,19 @@
|
||||
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);
|
@ -0,0 +1,113 @@
|
||||
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
|
||||
|
@ -0,0 +1,82 @@
|
||||
diff --git a/modules/cache/cache_util.h b/modules/cache/cache_util.h
|
||||
index 6b92151..4c42a8e 100644
|
||||
--- a/modules/cache/cache_util.h
|
||||
+++ b/modules/cache/cache_util.h
|
||||
@@ -195,6 +195,9 @@ typedef struct {
|
||||
unsigned int store_nostore_set:1;
|
||||
unsigned int enable_set:1;
|
||||
unsigned int disable_set:1;
|
||||
+ /* treat maxex as hard limit */
|
||||
+ unsigned int hardmaxex:1;
|
||||
+ unsigned int hardmaxex_set:1;
|
||||
} cache_dir_conf;
|
||||
|
||||
/* A linked-list of authn providers. */
|
||||
diff --git a/modules/cache/mod_cache.c b/modules/cache/mod_cache.c
|
||||
index 56a09f5..41015b5 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)
|
||||
exp = date + dconf->defex;
|
||||
}
|
||||
}
|
||||
+ /* else, forcibly cap the expiry date if required */
|
||||
+ else if (dconf->hardmaxex && (date + dconf->maxex) < exp) {
|
||||
+ exp = date + dconf->maxex;
|
||||
+ }
|
||||
+
|
||||
info->expire = exp;
|
||||
|
||||
/* We found a stale entry which wasn't really stale. */
|
||||
@@ -1954,7 +1959,9 @@ static void *create_dir_config(apr_pool_t *p, char *dummy)
|
||||
|
||||
/* array of providers for this URL space */
|
||||
dconf->cacheenable = apr_array_make(p, 10, sizeof(struct cache_enable));
|
||||
-
|
||||
+ /* flag; treat maxex as hard limit */
|
||||
+ dconf->hardmaxex = 0;
|
||||
+ dconf->hardmaxex_set = 0;
|
||||
return dconf;
|
||||
}
|
||||
|
||||
@@ -2004,7 +2011,10 @@ static void *merge_dir_config(apr_pool_t *p, void *basev, void *addv) {
|
||||
new->enable_set = add->enable_set || base->enable_set;
|
||||
new->disable = (add->disable_set == 0) ? base->disable : add->disable;
|
||||
new->disable_set = add->disable_set || base->disable_set;
|
||||
-
|
||||
+ new->hardmaxex =
|
||||
+ (add->hardmaxex_set == 0)
|
||||
+ ? base->hardmaxex
|
||||
+ : add->hardmaxex;
|
||||
return new;
|
||||
}
|
||||
|
||||
@@ -2332,12 +2342,18 @@ static const char *add_cache_disable(cmd_parms *parms, void *dummy,
|
||||
}
|
||||
|
||||
static const char *set_cache_maxex(cmd_parms *parms, void *dummy,
|
||||
- const char *arg)
|
||||
+ const char *arg, const char *hard)
|
||||
{
|
||||
cache_dir_conf *dconf = (cache_dir_conf *)dummy;
|
||||
|
||||
dconf->maxex = (apr_time_t) (atol(arg) * MSEC_ONE_SEC);
|
||||
dconf->maxex_set = 1;
|
||||
+
|
||||
+ if (hard && strcasecmp(hard, "hard") == 0) {
|
||||
+ dconf->hardmaxex = 1;
|
||||
+ dconf->hardmaxex_set = 1;
|
||||
+ }
|
||||
+
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -2545,7 +2561,7 @@ static const command_rec cache_cmds[] =
|
||||
"caching is enabled"),
|
||||
AP_INIT_TAKE1("CacheDisable", add_cache_disable, NULL, RSRC_CONF|ACCESS_CONF,
|
||||
"A partial URL prefix below which caching is disabled"),
|
||||
- AP_INIT_TAKE1("CacheMaxExpire", set_cache_maxex, NULL, RSRC_CONF|ACCESS_CONF,
|
||||
+ AP_INIT_TAKE12("CacheMaxExpire", set_cache_maxex, NULL, RSRC_CONF|ACCESS_CONF,
|
||||
"The maximum time in seconds to cache a document"),
|
||||
AP_INIT_TAKE1("CacheMinExpire", set_cache_minex, NULL, RSRC_CONF|ACCESS_CONF,
|
||||
"The minimum time in seconds to cache a document"),
|
@ -0,0 +1,37 @@
|
||||
|
||||
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
|
||||
--- 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
|
||||
}
|
||||
apr_pool_cleanup_register(pconf, NULL, ap_mpm_end_gen_helper,
|
||||
apr_pool_cleanup_null);
|
||||
+
|
||||
+#ifdef RLIMIT_CORE
|
||||
+ if (ap_coredumpdir_configured) {
|
||||
+ struct rlimit lim;
|
||||
+
|
||||
+ if (getrlimit(RLIMIT_CORE, &lim) == 0 && lim.rlim_cur == 0) {
|
||||
+ lim.rlim_cur = lim.rlim_max;
|
||||
+ if (setrlimit(RLIMIT_CORE, &lim) == 0) {
|
||||
+ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL,
|
||||
+ "core dump file size limit raised to %lu bytes",
|
||||
+ lim.rlim_cur);
|
||||
+ } else {
|
||||
+ ap_log_error(APLOG_MARK, APLOG_NOTICE, errno, NULL,
|
||||
+ "core dump file size is zero, setrlimit failed");
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
return OK;
|
||||
}
|
||||
|
@ -0,0 +1,21 @@
|
||||
|
||||
Link straight against .la files.
|
||||
|
||||
Upstream-Status: vendor specific
|
||||
|
||||
diff --git a/configure.in b/configure.in
|
||||
index 9feaceb..82bfeef 100644
|
||||
--- a/configure.in
|
||||
+++ b/configure.in
|
||||
@@ -784,9 +784,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
|
||||
- AP_LIBS="$AP_LIBS `$apu_config --avoid-ldap --link-libtool --libs`"
|
||||
+ AP_LIBS="$AP_LIBS `$apu_config --avoid-ldap --link-libtool`"
|
||||
fi
|
||||
-AP_LIBS="$AP_LIBS `$apr_config --link-libtool --libs`"
|
||||
+AP_LIBS="$AP_LIBS `$apr_config --link-libtool`"
|
||||
APACHE_SUBST(AP_LIBS)
|
||||
APACHE_SUBST(AP_BUILD_SRCLIB_DIRS)
|
||||
APACHE_SUBST(AP_CLEAN_SRCLIB_DIRS)
|
@ -0,0 +1,77 @@
|
||||
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 ""'
|
@ -0,0 +1,125 @@
|
||||
diff --git a/include/ap_listen.h b/include/ap_listen.h
|
||||
index 58c2574..1a53292 100644
|
||||
--- a/include/ap_listen.h
|
||||
+++ b/include/ap_listen.h
|
||||
@@ -137,6 +137,9 @@ AP_DECLARE_NONSTD(const char *) ap_set_listenbacklog(cmd_parms *cmd, void *dummy
|
||||
AP_DECLARE_NONSTD(const char *) ap_set_listencbratio(cmd_parms *cmd, void *dummy, const char *arg);
|
||||
AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy,
|
||||
int argc, char *const argv[]);
|
||||
+AP_DECLARE_NONSTD(const char *) ap_set_freelistener(cmd_parms *cmd, void *dummy,
|
||||
+ int argc, char *const argv[]);
|
||||
+
|
||||
AP_DECLARE_NONSTD(const char *) ap_set_send_buffer_size(cmd_parms *cmd, void *dummy,
|
||||
const char *arg);
|
||||
AP_DECLARE_NONSTD(const char *) ap_set_receive_buffer_size(cmd_parms *cmd,
|
||||
@@ -150,6 +153,8 @@ AP_INIT_TAKE1("ListenCoresBucketsRatio", ap_set_listencbratio, NULL, RSRC_CONF,
|
||||
"Ratio between the number of CPU cores (online) and the number of listeners buckets"), \
|
||||
AP_INIT_TAKE_ARGV("Listen", ap_set_listener, NULL, RSRC_CONF, \
|
||||
"A port number or a numeric IP address and a port number, and an optional protocol"), \
|
||||
+AP_INIT_TAKE_ARGV("ListenFree", ap_set_freelistener, NULL, RSRC_CONF, \
|
||||
+ "A port number or a numeric IP address and a port number, and an optional protocol"), \
|
||||
AP_INIT_TAKE1("SendBufferSize", ap_set_send_buffer_size, NULL, RSRC_CONF, \
|
||||
"Send buffer size in bytes"), \
|
||||
AP_INIT_TAKE1("ReceiveBufferSize", ap_set_receive_buffer_size, NULL, \
|
||||
diff --git a/server/listen.c b/server/listen.c
|
||||
index 1a6c1d3..d375fee 100644
|
||||
--- a/server/listen.c
|
||||
+++ b/server/listen.c
|
||||
@@ -63,6 +63,7 @@ static int ap_listenbacklog;
|
||||
static int ap_listencbratio;
|
||||
static int send_buffer_size;
|
||||
static int receive_buffer_size;
|
||||
+static int ap_listenfreebind;
|
||||
#ifdef HAVE_SYSTEMD
|
||||
static int use_systemd = -1;
|
||||
#endif
|
||||
@@ -162,6 +163,21 @@ static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server, int do_bind_
|
||||
}
|
||||
#endif
|
||||
|
||||
+
|
||||
+#if defined(APR_SO_FREEBIND)
|
||||
+ if (ap_listenfreebind) {
|
||||
+ if (apr_socket_opt_set(s, APR_SO_FREEBIND, one) < 0) {
|
||||
+ stat = apr_get_netos_error();
|
||||
+ ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p, APLOGNO(02182)
|
||||
+ "make_sock: apr_socket_opt_set: "
|
||||
+ "error setting APR_SO_FREEBIND");
|
||||
+ apr_socket_close(s);
|
||||
+ return stat;
|
||||
+ }
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
+
|
||||
if (do_bind_listen) {
|
||||
#if APR_HAVE_IPV6
|
||||
if (server->bind_addr->family == APR_INET6) {
|
||||
@@ -956,6 +972,7 @@ AP_DECLARE(void) ap_listen_pre_config(void)
|
||||
}
|
||||
}
|
||||
|
||||
+
|
||||
AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy,
|
||||
int argc, char *const argv[])
|
||||
{
|
||||
@@ -1016,6 +1033,14 @@ AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy,
|
||||
return alloc_listener(cmd->server->process, host, port, proto, NULL);
|
||||
}
|
||||
|
||||
+AP_DECLARE_NONSTD(const char *) ap_set_freelistener(cmd_parms *cmd, void *dummy,
|
||||
+ int argc,
|
||||
+ char *const argv[])
|
||||
+{
|
||||
+ ap_listenfreebind = 1;
|
||||
+ return ap_set_listener(cmd, dummy, argc, argv);
|
||||
+}
|
||||
+
|
||||
AP_DECLARE_NONSTD(const char *) ap_set_listenbacklog(cmd_parms *cmd,
|
||||
void *dummy,
|
||||
const char *arg)
|
||||
diff --git a/docs/manual/mod/mpm_common.html.en b/docs/manual/mod/mpm_common.html.en
|
||||
index 5d688e4..eb66c19 100644
|
||||
--- a/docs/manual/mod/mpm_common.html.en
|
||||
+++ b/docs/manual/mod/mpm_common.html.en
|
||||
@@ -42,6 +42,7 @@ more than one multi-processing module (MPM)</td></tr>
|
||||
<li><img alt="" src="../images/down.gif" /> <a href="#enableexceptionhook">EnableExceptionHook</a></li>
|
||||
<li><img alt="" src="../images/down.gif" /> <a href="#gracefulshutdowntimeout">GracefulShutdownTimeout</a></li>
|
||||
<li><img alt="" src="../images/down.gif" /> <a href="#listen">Listen</a></li>
|
||||
+<li><img alt="" src="../images/down.gif" /> <a href="#listenfree">ListenFree</a></li>
|
||||
<li><img alt="" src="../images/down.gif" /> <a href="#listenbacklog">ListenBackLog</a></li>
|
||||
<li><img alt="" src="../images/down.gif" /> <a href="#listencoresbucketsratio">ListenCoresBucketsRatio</a></li>
|
||||
<li><img alt="" src="../images/down.gif" /> <a href="#maxconnectionsperchild">MaxConnectionsPerChild</a></li>
|
||||
@@ -233,6 +234,31 @@ discussion of the <code>Address already in use</code> error message,
|
||||
including other causes.</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
+
|
||||
+<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
|
||||
+<div class="directive-section"><h2><a name="ListenFree" id="ListenFree">ListenFree</a> <a name="listenfree" id="listenfree">Directive</a></h2>
|
||||
+<table class="directive">
|
||||
+<tr><th><a href="directive-dict.html#Description">Description:</a></th><td>IP addresses and ports that the server
|
||||
+listens to. Doesn't require IP address to be up</td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Syntax">Syntax:</a></th><td><code>ListenFree [<var>IP-address</var>:]<var>portnumber</var> [<var>protocol</var>]</code></td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Context">Context:</a></th><td>server config</td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Status">Status:</a></th><td>MPM</td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Module">Module:</a></th><td><code class="module"><a href="../mod/event.html">event</a></code>, <code class="module"><a href="../mod/worker.html">worker</a></code>, <code class="module"><a href="../mod/prefork.html">prefork</a></code>, <code class="module"><a href="../mod/mpm_winnt.html">mpm_winnt</a></code>, <code class="module"><a href="../mod/mpm_netware.html">mpm_netware</a></code>, <code class="module"><a href="../mod/mpmt_os2.html">mpmt_os2</a></code></td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Compatibility">Compatibility:</a></th><td>This directive is currently available only in Red Hat Enterprise Linux</td></tr>
|
||||
+</table>
|
||||
+ <p>The <code class="directive">ListenFree</code> directive is
|
||||
+ identical to the <code class="directive">Listen</code> directive.
|
||||
+ The only difference is in the usage of the IP_FREEBIND socket
|
||||
+ option, which is enabled by default with <code class="directive">ListenFree</code>.
|
||||
+ If IP_FREEBIND is enabled, it allows httpd to bind to an IP
|
||||
+ address that is nonlocal or does not (yet) exist. This allows httpd to
|
||||
+ listen on a socket without requiring the underlying network interface
|
||||
+ or the specified dynamic IP address to be up at the time when httpd
|
||||
+ is trying to bind to it.
|
||||
+ </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="ListenBackLog" id="ListenBackLog">ListenBackLog</a> <a name="listenbacklog" id="listenbacklog">Directive</a></h2>
|
||||
<table class="directive">
|
||||
|
@ -0,0 +1,46 @@
|
||||
diff --git a/server/core.c b/server/core.c
|
||||
index cb8e463..daf76b3 100644
|
||||
--- a/server/core.c
|
||||
+++ b/server/core.c
|
||||
@@ -3430,6 +3430,7 @@ enum server_token_type {
|
||||
SrvTk_MINIMAL, /* eg: Apache/2.0.41 */
|
||||
SrvTk_OS, /* eg: Apache/2.0.41 (UNIX) */
|
||||
SrvTk_FULL, /* eg: Apache/2.0.41 (UNIX) PHP/4.2.2 FooBar/1.2b */
|
||||
+ SrvTk_FULL_RELEASE, /* eg: Apache/2.0.41 (UNIX) (Release 32.el7) PHP/4.2.2 FooBar/1.2b */
|
||||
SrvTk_PRODUCT_ONLY /* eg: Apache */
|
||||
};
|
||||
static enum server_token_type ap_server_tokens = SrvTk_FULL;
|
||||
@@ -3506,7 +3507,10 @@ static void set_banner(apr_pool_t *pconf)
|
||||
else if (ap_server_tokens == SrvTk_MAJOR) {
|
||||
ap_add_version_component(pconf, AP_SERVER_BASEPRODUCT "/" AP_SERVER_MAJORVERSION);
|
||||
}
|
||||
- else {
|
||||
+ else if (ap_server_tokens == SrvTk_FULL_RELEASE) {
|
||||
+ ap_add_version_component(pconf, AP_SERVER_BASEVERSION " (" PLATFORM ") (Release @RELEASE@)");
|
||||
+ }
|
||||
+ else {
|
||||
ap_add_version_component(pconf, AP_SERVER_BASEVERSION " (" PLATFORM ")");
|
||||
}
|
||||
|
||||
@@ -3514,7 +3518,7 @@ static void set_banner(apr_pool_t *pconf)
|
||||
* Lock the server_banner string if we're not displaying
|
||||
* the full set of tokens
|
||||
*/
|
||||
- if (ap_server_tokens != SrvTk_FULL) {
|
||||
+ if (ap_server_tokens != SrvTk_FULL && ap_server_tokens != SrvTk_FULL_RELEASE) {
|
||||
banner_locked++;
|
||||
}
|
||||
server_description = AP_SERVER_BASEVERSION " (" PLATFORM ")";
|
||||
@@ -3547,8 +3551,11 @@ static const char *set_serv_tokens(cmd_parms *cmd, void *dummy,
|
||||
else if (!strcasecmp(arg, "Full")) {
|
||||
ap_server_tokens = SrvTk_FULL;
|
||||
}
|
||||
+ else if (!strcasecmp(arg, "Full-Release")) {
|
||||
+ ap_server_tokens = SrvTk_FULL_RELEASE;
|
||||
+ }
|
||||
else {
|
||||
- return "ServerTokens takes 1 argument: 'Prod(uctOnly)', 'Major', 'Minor', 'Min(imal)', 'OS', or 'Full'";
|
||||
+ return "ServerTokens takes 1 argument: 'Prod(uctOnly)', 'Major', 'Minor', 'Min(imal)', 'OS', 'Full' or 'Full-Release'";
|
||||
}
|
||||
|
||||
return NULL;
|
@ -0,0 +1,15 @@
|
||||
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. */
|
@ -0,0 +1,16 @@
|
||||
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 ?
|
@ -0,0 +1,140 @@
|
||||
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)
|
@ -0,0 +1,96 @@
|
||||
diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c
|
||||
index 19cb611..79d5219 100644
|
||||
--- a/modules/ssl/ssl_engine_init.c
|
||||
+++ b/modules/ssl/ssl_engine_init.c
|
||||
@@ -2070,70 +2070,18 @@ int ssl_proxy_section_post_config(apr_pool_t *p, apr_pool_t *plog,
|
||||
return OK;
|
||||
}
|
||||
|
||||
-static int ssl_init_FindCAList_X509NameCmp(const X509_NAME * const *a,
|
||||
- const X509_NAME * const *b)
|
||||
-{
|
||||
- return(X509_NAME_cmp(*a, *b));
|
||||
-}
|
||||
-
|
||||
-static void ssl_init_PushCAList(STACK_OF(X509_NAME) *ca_list,
|
||||
- server_rec *s, apr_pool_t *ptemp,
|
||||
- const char *file)
|
||||
-{
|
||||
- int n;
|
||||
- STACK_OF(X509_NAME) *sk;
|
||||
-
|
||||
- sk = (STACK_OF(X509_NAME) *)
|
||||
- SSL_load_client_CA_file(file);
|
||||
-
|
||||
- if (!sk) {
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
- for (n = 0; n < sk_X509_NAME_num(sk); n++) {
|
||||
- X509_NAME *name = sk_X509_NAME_value(sk, n);
|
||||
-
|
||||
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02209)
|
||||
- "CA certificate: %s",
|
||||
- modssl_X509_NAME_to_string(ptemp, name, 0));
|
||||
-
|
||||
- /*
|
||||
- * note that SSL_load_client_CA_file() checks for duplicates,
|
||||
- * but since we call it multiple times when reading a directory
|
||||
- * we must also check for duplicates ourselves.
|
||||
- */
|
||||
-
|
||||
- if (sk_X509_NAME_find(ca_list, name) < 0) {
|
||||
- /* this will be freed when ca_list is */
|
||||
- sk_X509_NAME_push(ca_list, name);
|
||||
- }
|
||||
- else {
|
||||
- /* need to free this ourselves, else it will leak */
|
||||
- X509_NAME_free(name);
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- sk_X509_NAME_free(sk);
|
||||
-}
|
||||
-
|
||||
STACK_OF(X509_NAME) *ssl_init_FindCAList(server_rec *s,
|
||||
apr_pool_t *ptemp,
|
||||
const char *ca_file,
|
||||
const char *ca_path)
|
||||
{
|
||||
- STACK_OF(X509_NAME) *ca_list;
|
||||
-
|
||||
- /*
|
||||
- * Start with a empty stack/list where new
|
||||
- * entries get added in sorted order.
|
||||
- */
|
||||
- ca_list = sk_X509_NAME_new(ssl_init_FindCAList_X509NameCmp);
|
||||
+ STACK_OF(X509_NAME) *ca_list = sk_X509_NAME_new_null();;
|
||||
|
||||
/*
|
||||
* Process CA certificate bundle file
|
||||
*/
|
||||
if (ca_file) {
|
||||
- ssl_init_PushCAList(ca_list, s, ptemp, ca_file);
|
||||
+ SSL_add_file_cert_subjects_to_stack(ca_list, ca_file);
|
||||
/*
|
||||
* If ca_list is still empty after trying to load ca_file
|
||||
* then the file failed to load, and users should hear about that.
|
||||
@@ -2168,17 +2116,12 @@ STACK_OF(X509_NAME) *ssl_init_FindCAList(server_rec *s,
|
||||
continue; /* don't try to load directories */
|
||||
}
|
||||
file = apr_pstrcat(ptemp, ca_path, "/", direntry.name, NULL);
|
||||
- ssl_init_PushCAList(ca_list, s, ptemp, file);
|
||||
+ SSL_add_file_cert_subjects_to_stack(ca_list, file);
|
||||
}
|
||||
|
||||
apr_dir_close(dir);
|
||||
}
|
||||
|
||||
- /*
|
||||
- * Cleanup
|
||||
- */
|
||||
- (void) sk_X509_NAME_set_cmp_func(ca_list, NULL);
|
||||
-
|
||||
return ca_list;
|
||||
}
|
||||
|
@ -0,0 +1,708 @@
|
||||
# ./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,
|
@ -0,0 +1,22 @@
|
||||
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) {
|
@ -0,0 +1,65 @@
|
||||
|
||||
Log the SELinux context at startup.
|
||||
|
||||
Upstream-Status: unlikely to be any interest in this upstream
|
||||
|
||||
diff --git a/configure.in b/configure.in
|
||||
index eedba50..a208b53 100644
|
||||
--- a/configure.in
|
||||
+++ b/configure.in
|
||||
@@ -484,6 +484,11 @@ getloadavg
|
||||
dnl confirm that a void pointer is large enough to store a long integer
|
||||
APACHE_CHECK_VOID_PTR_LEN
|
||||
|
||||
+AC_CHECK_LIB(selinux, is_selinux_enabled, [
|
||||
+ AC_DEFINE(HAVE_SELINUX, 1, [Defined if SELinux is supported])
|
||||
+ APR_ADDTO(HTTPD_LIBS, [-lselinux])
|
||||
+])
|
||||
+
|
||||
AC_CACHE_CHECK([for gettid()], ac_cv_gettid,
|
||||
[AC_TRY_RUN(#define _GNU_SOURCE
|
||||
#include <unistd.h>
|
||||
diff --git a/server/core.c b/server/core.c
|
||||
index ec74029..cb8e463 100644
|
||||
--- a/server/core.c
|
||||
+++ b/server/core.c
|
||||
@@ -59,6 +59,10 @@
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
+#ifdef HAVE_SELINUX
|
||||
+#include <selinux/selinux.h>
|
||||
+#endif
|
||||
+
|
||||
/* LimitRequestBody handling */
|
||||
#define AP_LIMIT_REQ_BODY_UNSET ((apr_off_t) -1)
|
||||
#define AP_DEFAULT_LIMIT_REQ_BODY ((apr_off_t) 0)
|
||||
@@ -4971,6 +4975,28 @@ static int core_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *pte
|
||||
}
|
||||
#endif
|
||||
|
||||
+#ifdef HAVE_SELINUX
|
||||
+ {
|
||||
+ static int already_warned = 0;
|
||||
+ int is_enabled = is_selinux_enabled() > 0;
|
||||
+
|
||||
+ if (is_enabled && !already_warned) {
|
||||
+ security_context_t con;
|
||||
+
|
||||
+ if (getcon(&con) == 0) {
|
||||
+
|
||||
+ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL,
|
||||
+ "SELinux policy enabled; "
|
||||
+ "httpd running as context %s", con);
|
||||
+
|
||||
+ already_warned = 1;
|
||||
+
|
||||
+ freecon(con);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
return OK;
|
||||
}
|
||||
|
@ -0,0 +1,31 @@
|
||||
diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c
|
||||
index 4cfd2d0..6ac55bd 100644
|
||||
--- a/modules/ssl/ssl_engine_config.c
|
||||
+++ b/modules/ssl/ssl_engine_config.c
|
||||
@@ -776,9 +776,11 @@ const char *ssl_cmd_SSLCipherSuite(cmd_parms *cmd,
|
||||
}
|
||||
|
||||
if (!strcmp("SSL", arg1)) {
|
||||
- /* always disable null and export ciphers */
|
||||
- arg2 = apr_pstrcat(cmd->pool, arg2, ":!aNULL:!eNULL:!EXP", NULL);
|
||||
if (cmd->path) {
|
||||
+ /* Disable null and export ciphers by default, except for PROFILE=
|
||||
+ * configs where the parser doesn't cope. */
|
||||
+ if (strncmp(arg2, "PROFILE=", 8) != 0)
|
||||
+ arg2 = apr_pstrcat(cmd->pool, arg2, ":!aNULL:!eNULL:!EXP", NULL);
|
||||
dc->szCipherSuite = arg2;
|
||||
}
|
||||
else {
|
||||
@@ -1542,8 +1544,10 @@ const char *ssl_cmd_SSLProxyCipherSuite(cmd_parms *cmd,
|
||||
}
|
||||
|
||||
if (!strcmp("SSL", arg1)) {
|
||||
- /* always disable null and export ciphers */
|
||||
- arg2 = apr_pstrcat(cmd->pool, arg2, ":!aNULL:!eNULL:!EXP", NULL);
|
||||
+ /* Disable null and export ciphers by default, except for PROFILE=
|
||||
+ * configs where the parser doesn't cope. */
|
||||
+ if (strncmp(arg2, "PROFILE=", 8) != 0)
|
||||
+ arg2 = apr_pstrcat(cmd->pool, arg2, ":!aNULL:!eNULL:!EXP", NULL);
|
||||
dc->proxy->auth.cipher_suite = arg2;
|
||||
return NULL;
|
||||
}
|
@ -0,0 +1,245 @@
|
||||
--- 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,
|
||||
+};
|
@ -0,0 +1,20 @@
|
||||
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 ' ':
|
@ -0,0 +1,39 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,207 @@
|
||||
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;
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
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;
|
||||
}
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
--- 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);
|
@ -0,0 +1,235 @@
|
||||
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 }
|
||||
};
|
||||
|
@ -0,0 +1,192 @@
|
||||
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));
|
@ -0,0 +1,66 @@
|
||||
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,
|
@ -0,0 +1,91 @@
|
||||
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);
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
--- 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);
|
@ -0,0 +1,12 @@
|
||||
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;
|
||||
}
|
||||
|
@ -0,0 +1,68 @@
|
||||
--- 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);
|
@ -0,0 +1,21 @@
|
||||
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;
|
@ -0,0 +1,14 @@
|
||||
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);
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
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;
|
||||
}
|
||||
|
@ -0,0 +1,44 @@
|
||||
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));
|
||||
}
|
||||
}
|
@ -0,0 +1,706 @@
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
@ -0,0 +1,13 @@
|
||||
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 {
|
@ -0,0 +1,45 @@
|
||||
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 */
|
@ -0,0 +1,21 @@
|
||||
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++;
|
||||
}
|
@ -0,0 +1,126 @@
|
||||
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;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,315 @@
|
||||
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.
|
@ -0,0 +1,12 @@
|
||||
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);
|
@ -0,0 +1,70 @@
|
||||
--- 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;
|
||||
}
|
@ -0,0 +1,154 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,103 @@
|
||||
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);
|
@ -0,0 +1,377 @@
|
||||
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);
|
@ -0,0 +1,26 @@
|
||||
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);
|
@ -0,0 +1,47 @@
|
||||
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;
|
||||
|
@ -0,0 +1,22 @@
|
||||
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] != '*')
|
@ -0,0 +1,90 @@
|
||||
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)
|
@ -0,0 +1,541 @@
|
||||
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:
|
@ -0,0 +1,233 @@
|
||||
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;
|
||||
}
|
||||
}
|
@ -0,0 +1,229 @@
|
||||
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,
|
@ -0,0 +1,23 @@
|
||||
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 {
|
@ -0,0 +1,129 @@
|
||||
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;
|
@ -0,0 +1,586 @@
|
||||
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.
|
||||
*/
|
@ -0,0 +1,89 @@
|
||||
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
|
||||
+++ b/modules/proxy/mod_proxy_uwsgi.c
|
||||
@@ -304,18 +304,16 @@ static int uwsgi_response(request_rec *r, proxy_conn_rec * backend,
|
||||
pass_bb = apr_brigade_create(r->pool, c->bucket_alloc);
|
||||
|
||||
len = ap_getline(buffer, sizeof(buffer), rp, 1);
|
||||
-
|
||||
if (len <= 0) {
|
||||
- /* oops */
|
||||
+ /* invalid or empty */
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
-
|
||||
backend->worker->s->read += len;
|
||||
-
|
||||
- if (len >= sizeof(buffer) - 1) {
|
||||
- /* oops */
|
||||
+ if ((apr_size_t)len >= sizeof(buffer)) {
|
||||
+ /* too long */
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
+
|
||||
/* Position of http status code */
|
||||
if (apr_date_checkmask(buffer, "HTTP/#.# ###*")) {
|
||||
status_start = 9;
|
||||
@@ -324,8 +322,8 @@ static int uwsgi_response(request_rec *r, proxy_conn_rec * backend,
|
||||
status_start = 7;
|
||||
}
|
||||
else {
|
||||
- /* oops */
|
||||
- return HTTP_INTERNAL_SERVER_ERROR;
|
||||
+ /* not HTTP */
|
||||
+ return HTTP_BAD_GATEWAY;
|
||||
}
|
||||
status_end = status_start + 3;
|
||||
|
||||
@@ -345,21 +343,44 @@ static int uwsgi_response(request_rec *r, proxy_conn_rec * backend,
|
||||
}
|
||||
r->status_line = apr_pstrdup(r->pool, &buffer[status_start]);
|
||||
|
||||
- /* start parsing headers */
|
||||
+ /* parse headers */
|
||||
while ((len = ap_getline(buffer, sizeof(buffer), rp, 1)) > 0) {
|
||||
+ if ((apr_size_t)len >= sizeof(buffer)) {
|
||||
+ /* too long */
|
||||
+ len = -1;
|
||||
+ break;
|
||||
+ }
|
||||
value = strchr(buffer, ':');
|
||||
- /* invalid header skip */
|
||||
- if (!value)
|
||||
- continue;
|
||||
- *value = '\0';
|
||||
- ++value;
|
||||
+ if (!value) {
|
||||
+ /* invalid header */
|
||||
+ len = -1;
|
||||
+ break;
|
||||
+ }
|
||||
+ *value++ = '\0';
|
||||
+ if (*ap_scan_http_token(buffer)) {
|
||||
+ /* invalid name */
|
||||
+ len = -1;
|
||||
+ break;
|
||||
+ }
|
||||
while (apr_isspace(*value))
|
||||
++value;
|
||||
for (end = &value[strlen(value) - 1];
|
||||
end > value && apr_isspace(*end); --end)
|
||||
*end = '\0';
|
||||
+ if (*ap_scan_http_field_content(value)) {
|
||||
+ /* invalid value */
|
||||
+ len = -1;
|
||||
+ break;
|
||||
+ }
|
||||
apr_table_add(r->headers_out, buffer, value);
|
||||
}
|
||||
+ if (len < 0) {
|
||||
+ /* Reset headers, but not to NULL because things below the chain expect
|
||||
+ * this to be non NULL e.g. the ap_content_length_filter.
|
||||
+ */
|
||||
+ r->headers_out = apr_table_make(r->pool, 1);
|
||||
+ return HTTP_BAD_GATEWAY;
|
||||
+ }
|
||||
|
||||
if ((buf = apr_table_get(r->headers_out, "Content-Type"))) {
|
||||
ap_set_content_type(r, apr_pstrdup(r->pool, buf));
|
@ -0,0 +1,11 @@
|
||||
--- 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) {
|
@ -0,0 +1,92 @@
|
||||
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. */
|
@ -0,0 +1,225 @@
|
||||
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;
|
||||
|
@ -0,0 +1,42 @@
|
||||
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");
|
@ -0,0 +1,199 @@
|
||||
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,
|
@ -0,0 +1,13 @@
|
||||
diff --git a/support/htcacheclean.c b/support/htcacheclean.c
|
||||
index 8692377..fde34c9 100644
|
||||
--- a/support/htcacheclean.c
|
||||
+++ b/support/htcacheclean.c
|
||||
@@ -557,8 +557,6 @@ static int list_urls(char *path, apr_pool_t *pool, apr_off_t round)
|
||||
}
|
||||
}
|
||||
}
|
||||
-
|
||||
- break;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
diff --git a/modules/loggers/config.m4 b/modules/loggers/config.m4
|
||||
index 762e773e94..0848d2e377 100644
|
||||
--- a/modules/loggers/config.m4
|
||||
+++ b/modules/loggers/config.m4
|
||||
@@ -5,6 +5,8 @@ dnl APACHE_MODULE(name, helptext[, objects[, structname[, default[, config]]]])
|
||||
APACHE_MODPATH_INIT(loggers)
|
||||
|
||||
APACHE_MODULE(log_config, logging configuration. You won't be able to log requests to the server without this module., , , yes)
|
||||
+APR_ADDTO(MOD_LOG_CONFIG_LDADD, [$SYSTEMD_LIBS])
|
||||
+
|
||||
APACHE_MODULE(log_debug, configurable debug logging, , , most)
|
||||
APACHE_MODULE(log_forensic, forensic logging)
|
||||
|
||||
diff --git a/modules/loggers/mod_log_config.c b/modules/loggers/mod_log_config.c
|
||||
index 996c09cf49..50a056a2f8 100644
|
||||
--- a/modules/loggers/mod_log_config.c
|
||||
+++ b/modules/loggers/mod_log_config.c
|
||||
@@ -172,6 +172,10 @@
|
||||
#include <limits.h>
|
||||
#endif
|
||||
|
||||
+#ifdef HAVE_SYSTEMD
|
||||
+#include <systemd/sd-journal.h>
|
||||
+#endif
|
||||
+
|
||||
#define DEFAULT_LOG_FORMAT "%h %l %u %t \"%r\" %>s %b"
|
||||
|
||||
module AP_MODULE_DECLARE_DATA log_config_module;
|
||||
@@ -1638,6 +1642,25 @@ static apr_status_t ap_default_log_writer( request_rec *r,
|
||||
|
||||
return rv;
|
||||
}
|
||||
+
|
||||
+static apr_status_t wrap_journal_stream(apr_pool_t *p, apr_file_t **outfd,
|
||||
+ int priority)
|
||||
+{
|
||||
+#ifdef HAVE_SYSTEMD
|
||||
+ int fd;
|
||||
+
|
||||
+ fd = sd_journal_stream_fd("httpd", priority, 0);
|
||||
+ if (fd < 0) return fd;
|
||||
+
|
||||
+ /* This is an AF_UNIX socket fd so is more pipe-like than
|
||||
+ * file-like (the fd is neither seekable or readable), and use of
|
||||
+ * apr_os_pipe_put_ex() allows cleanup registration. */
|
||||
+ return apr_os_pipe_put_ex(outfd, &fd, 1, p);
|
||||
+#else
|
||||
+ return APR_ENOTIMPL;
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
static void *ap_default_log_writer_init(apr_pool_t *p, server_rec *s,
|
||||
const char* name)
|
||||
{
|
||||
@@ -1650,6 +1673,32 @@ static void *ap_default_log_writer_init(apr_pool_t *p, server_rec *s,
|
||||
}
|
||||
return ap_piped_log_write_fd(pl);
|
||||
}
|
||||
+ else if (strncasecmp(name, "journald:", 9) == 0) {
|
||||
+ int priority;
|
||||
+ const char *err = ap_parse_log_level(name + 9, &priority);
|
||||
+ apr_status_t rv;
|
||||
+ apr_file_t *fd;
|
||||
+
|
||||
+ if (err == NULL && priority > LOG_DEBUG) {
|
||||
+ err = "TRACE level debugging not supported with journald";
|
||||
+ }
|
||||
+
|
||||
+ if (err) {
|
||||
+ ap_log_error(APLOG_MARK, APLOG_ERR, APR_EBADPATH, s,
|
||||
+ "invalid journald log priority name %s: %s",
|
||||
+ name, err);
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ rv = wrap_journal_stream(p, &fd, priority);
|
||||
+ if (rv) {
|
||||
+ ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
|
||||
+ "could not open journald log stream");
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ return fd;
|
||||
+ }
|
||||
else {
|
||||
const char *fname = ap_server_root_relative(p, name);
|
||||
apr_file_t *fd;
|
@ -0,0 +1,544 @@
|
||||
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;
|
||||
}
|
||||
|
@ -0,0 +1,44 @@
|
||||
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
|
@ -0,0 +1,24 @@
|
||||
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 */
|
@ -0,0 +1,170 @@
|
||||
commit 84e6f25f67de9a9bddefdcdbfee3f251fead647e
|
||||
Author: Tomas Korbar <tkorbar@redhat.com>
|
||||
Date: Thu Jul 20 14:41:33 2023 +0200
|
||||
|
||||
Fix duplicate presence of keys printed by mod_status
|
||||
|
||||
diff --git a/modules/generators/mod_status.c b/modules/generators/mod_status.c
|
||||
index 5917953..5bada07 100644
|
||||
--- a/modules/generators/mod_status.c
|
||||
+++ b/modules/generators/mod_status.c
|
||||
@@ -186,7 +186,8 @@ static int status_handler(request_rec *r)
|
||||
apr_uint32_t up_time;
|
||||
ap_loadavg_t t;
|
||||
int j, i, res, written;
|
||||
- int ready;
|
||||
+ int idle;
|
||||
+ int graceful;
|
||||
int busy;
|
||||
unsigned long count;
|
||||
unsigned long lres, my_lres, conn_lres;
|
||||
@@ -203,6 +204,7 @@ static int status_handler(request_rec *r)
|
||||
char *stat_buffer;
|
||||
pid_t *pid_buffer, worker_pid;
|
||||
int *thread_idle_buffer = NULL;
|
||||
+ int *thread_graceful_buffer = NULL;
|
||||
int *thread_busy_buffer = NULL;
|
||||
clock_t tu, ts, tcu, tcs;
|
||||
clock_t gu, gs, gcu, gcs;
|
||||
@@ -231,7 +233,8 @@ static int status_handler(request_rec *r)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
- ready = 0;
|
||||
+ idle = 0;
|
||||
+ graceful = 0;
|
||||
busy = 0;
|
||||
count = 0;
|
||||
bcount = 0;
|
||||
@@ -250,6 +253,7 @@ static int status_handler(request_rec *r)
|
||||
stat_buffer = apr_palloc(r->pool, server_limit * thread_limit * sizeof(char));
|
||||
if (is_async) {
|
||||
thread_idle_buffer = apr_palloc(r->pool, server_limit * sizeof(int));
|
||||
+ thread_graceful_buffer = apr_palloc(r->pool, server_limit * sizeof(int));
|
||||
thread_busy_buffer = apr_palloc(r->pool, server_limit * sizeof(int));
|
||||
}
|
||||
|
||||
@@ -318,6 +322,7 @@ static int status_handler(request_rec *r)
|
||||
ps_record = ap_get_scoreboard_process(i);
|
||||
if (is_async) {
|
||||
thread_idle_buffer[i] = 0;
|
||||
+ thread_graceful_buffer[i] = 0;
|
||||
thread_busy_buffer[i] = 0;
|
||||
}
|
||||
for (j = 0; j < thread_limit; ++j) {
|
||||
@@ -336,18 +341,20 @@ static int status_handler(request_rec *r)
|
||||
&& ps_record->pid) {
|
||||
if (res == SERVER_READY) {
|
||||
if (ps_record->generation == mpm_generation)
|
||||
- ready++;
|
||||
+ idle++;
|
||||
if (is_async)
|
||||
thread_idle_buffer[i]++;
|
||||
}
|
||||
else if (res != SERVER_DEAD &&
|
||||
res != SERVER_STARTING &&
|
||||
res != SERVER_IDLE_KILL) {
|
||||
- busy++;
|
||||
- if (is_async) {
|
||||
- if (res == SERVER_GRACEFUL)
|
||||
- thread_idle_buffer[i]++;
|
||||
- else
|
||||
+ if (res == SERVER_GRACEFUL) {
|
||||
+ graceful++;
|
||||
+ if (is_async)
|
||||
+ thread_graceful_buffer[i]++;
|
||||
+ } else {
|
||||
+ busy++;
|
||||
+ if (is_async)
|
||||
thread_busy_buffer[i]++;
|
||||
}
|
||||
}
|
||||
@@ -548,10 +555,10 @@ static int status_handler(request_rec *r)
|
||||
} /* ap_extended_status */
|
||||
|
||||
if (!short_report)
|
||||
- ap_rprintf(r, "<dt>%d requests currently being processed, "
|
||||
- "%d idle workers</dt>\n", busy, ready);
|
||||
+ ap_rprintf(r, "<dt>%d requests currently being processed, %d workers gracefully restarting, "
|
||||
+ "%d idle workers</dt>\n", busy, graceful, idle);
|
||||
else
|
||||
- ap_rprintf(r, "BusyWorkers: %d\nIdleWorkers: %d\n", busy, ready);
|
||||
+ ap_rprintf(r, "BusyWorkers: %d\nGracefulWorkers: %d\nIdleWorkers: %d\n", busy, graceful, idle);
|
||||
|
||||
if (!short_report)
|
||||
ap_rputs("</dl>", r);
|
||||
@@ -559,11 +566,6 @@ static int status_handler(request_rec *r)
|
||||
if (is_async) {
|
||||
int write_completion = 0, lingering_close = 0, keep_alive = 0,
|
||||
connections = 0, stopping = 0, procs = 0;
|
||||
- /*
|
||||
- * These differ from 'busy' and 'ready' in how gracefully finishing
|
||||
- * threads are counted. XXX: How to make this clear in the html?
|
||||
- */
|
||||
- int busy_workers = 0, idle_workers = 0;
|
||||
if (!short_report)
|
||||
ap_rputs("\n\n<table rules=\"all\" cellpadding=\"1%\">\n"
|
||||
"<tr><th rowspan=\"2\">Slot</th>"
|
||||
@@ -573,7 +575,7 @@ static int status_handler(request_rec *r)
|
||||
"<th colspan=\"2\">Threads</th>"
|
||||
"<th colspan=\"3\">Async connections</th></tr>\n"
|
||||
"<tr><th>total</th><th>accepting</th>"
|
||||
- "<th>busy</th><th>idle</th>"
|
||||
+ "<th>busy</th><th>graceful</th><th>idle</th>"
|
||||
"<th>writing</th><th>keep-alive</th><th>closing</th></tr>\n", r);
|
||||
for (i = 0; i < server_limit; ++i) {
|
||||
ps_record = ap_get_scoreboard_process(i);
|
||||
@@ -582,8 +584,6 @@ static int status_handler(request_rec *r)
|
||||
write_completion += ps_record->write_completion;
|
||||
keep_alive += ps_record->keep_alive;
|
||||
lingering_close += ps_record->lingering_close;
|
||||
- busy_workers += thread_busy_buffer[i];
|
||||
- idle_workers += thread_idle_buffer[i];
|
||||
procs++;
|
||||
if (ps_record->quiescing) {
|
||||
stopping++;
|
||||
@@ -599,7 +599,7 @@ static int status_handler(request_rec *r)
|
||||
ap_rprintf(r, "<tr><td>%u</td><td>%" APR_PID_T_FMT "</td>"
|
||||
"<td>%s%s</td>"
|
||||
"<td>%u</td><td>%s</td>"
|
||||
- "<td>%u</td><td>%u</td>"
|
||||
+ "<td>%u</td><td>%u</td><td>%u</td>"
|
||||
"<td>%u</td><td>%u</td><td>%u</td>"
|
||||
"</tr>\n",
|
||||
i, ps_record->pid,
|
||||
@@ -607,6 +607,7 @@ static int status_handler(request_rec *r)
|
||||
ps_record->connections,
|
||||
ps_record->not_accepting ? "no" : "yes",
|
||||
thread_busy_buffer[i],
|
||||
+ thread_graceful_buffer[i],
|
||||
thread_idle_buffer[i],
|
||||
ps_record->write_completion,
|
||||
ps_record->keep_alive,
|
||||
@@ -618,25 +619,22 @@ static int status_handler(request_rec *r)
|
||||
ap_rprintf(r, "<tr><td>Sum</td>"
|
||||
"<td>%d</td><td>%d</td>"
|
||||
"<td>%d</td><td> </td>"
|
||||
- "<td>%d</td><td>%d</td>"
|
||||
+ "<td>%d</td><td>%d</td><td>%d</td>"
|
||||
"<td>%d</td><td>%d</td><td>%d</td>"
|
||||
"</tr>\n</table>\n",
|
||||
procs, stopping,
|
||||
connections,
|
||||
- busy_workers, idle_workers,
|
||||
+ busy, graceful, idle,
|
||||
write_completion, keep_alive, lingering_close);
|
||||
}
|
||||
else {
|
||||
ap_rprintf(r, "Processes: %d\n"
|
||||
"Stopping: %d\n"
|
||||
- "BusyWorkers: %d\n"
|
||||
- "IdleWorkers: %d\n"
|
||||
"ConnsTotal: %d\n"
|
||||
"ConnsAsyncWriting: %d\n"
|
||||
"ConnsAsyncKeepAlive: %d\n"
|
||||
"ConnsAsyncClosing: %d\n",
|
||||
procs, stopping,
|
||||
- busy_workers, idle_workers,
|
||||
connections,
|
||||
write_completion, keep_alive, lingering_close);
|
||||
}
|
@ -0,0 +1,143 @@
|
||||
diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c
|
||||
index d13c249..f383996 100644
|
||||
--- a/modules/proxy/mod_proxy.c
|
||||
+++ b/modules/proxy/mod_proxy.c
|
||||
@@ -1200,11 +1200,20 @@ static int proxy_handler(request_rec *r)
|
||||
/* handle the scheme */
|
||||
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01142)
|
||||
"Trying to run scheme_handler against proxy");
|
||||
+
|
||||
+ if (ents[i].creds) {
|
||||
+ apr_table_set(r->notes, "proxy-basic-creds", ents[i].creds);
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
|
||||
+ "Using proxy auth creds %s", ents[i].creds);
|
||||
+ }
|
||||
+
|
||||
access_status = proxy_run_scheme_handler(r, worker,
|
||||
conf, url,
|
||||
ents[i].hostname,
|
||||
ents[i].port);
|
||||
|
||||
+ if (ents[i].creds) apr_table_unset(r->notes, "proxy-basic-creds");
|
||||
+
|
||||
/* Did the scheme handler process the request? */
|
||||
if (access_status != DECLINED) {
|
||||
const char *cl_a;
|
||||
@@ -1621,8 +1630,8 @@ static void *merge_proxy_dir_config(apr_pool_t *p, void *basev, void *addv)
|
||||
return new;
|
||||
}
|
||||
|
||||
-static const char *
|
||||
- add_proxy(cmd_parms *cmd, void *dummy, const char *f1, const char *r1, int regex)
|
||||
+static const char *add_proxy(cmd_parms *cmd, void *dummy, const char *f1,
|
||||
+ const char *r1, const char *creds, int regex)
|
||||
{
|
||||
server_rec *s = cmd->server;
|
||||
proxy_server_conf *conf =
|
||||
@@ -1680,19 +1689,24 @@ static const char *
|
||||
new->port = port;
|
||||
new->regexp = reg;
|
||||
new->use_regex = regex;
|
||||
+ if (creds) {
|
||||
+ new->creds = apr_pstrcat(cmd->pool, "Basic ",
|
||||
+ ap_pbase64encode(cmd->pool, (char *)creds),
|
||||
+ NULL);
|
||||
+ }
|
||||
return NULL;
|
||||
}
|
||||
|
||||
-static const char *
|
||||
- add_proxy_noregex(cmd_parms *cmd, void *dummy, const char *f1, const char *r1)
|
||||
+static const char *add_proxy_noregex(cmd_parms *cmd, void *dummy, const char *f1,
|
||||
+ const char *r1, const char *creds)
|
||||
{
|
||||
- return add_proxy(cmd, dummy, f1, r1, 0);
|
||||
+ return add_proxy(cmd, dummy, f1, r1, creds, 0);
|
||||
}
|
||||
|
||||
-static const char *
|
||||
- add_proxy_regex(cmd_parms *cmd, void *dummy, const char *f1, const char *r1)
|
||||
+static const char *add_proxy_regex(cmd_parms *cmd, void *dummy, const char *f1,
|
||||
+ const char *r1, const char *creds)
|
||||
{
|
||||
- return add_proxy(cmd, dummy, f1, r1, 1);
|
||||
+ return add_proxy(cmd, dummy, f1, r1, creds, 1);
|
||||
}
|
||||
|
||||
PROXY_DECLARE(const char *) ap_proxy_de_socketfy(apr_pool_t *p, const char *url)
|
||||
@@ -2638,9 +2652,9 @@ static const command_rec proxy_cmds[] =
|
||||
"location, in regular expression syntax"),
|
||||
AP_INIT_FLAG("ProxyRequests", set_proxy_req, NULL, RSRC_CONF,
|
||||
"on if the true proxy requests should be accepted"),
|
||||
- AP_INIT_TAKE2("ProxyRemote", add_proxy_noregex, NULL, RSRC_CONF,
|
||||
+ AP_INIT_TAKE23("ProxyRemote", add_proxy_noregex, NULL, RSRC_CONF,
|
||||
"a scheme, partial URL or '*' and a proxy server"),
|
||||
- AP_INIT_TAKE2("ProxyRemoteMatch", add_proxy_regex, NULL, RSRC_CONF,
|
||||
+ AP_INIT_TAKE23("ProxyRemoteMatch", add_proxy_regex, NULL, RSRC_CONF,
|
||||
"a regex pattern and a proxy server"),
|
||||
AP_INIT_FLAG("ProxyPassInterpolateEnv", ap_set_flag_slot_char,
|
||||
(void*)APR_OFFSETOF(proxy_dir_conf, interpolate_env),
|
||||
diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h
|
||||
index 288c5d4..57cc92f 100644
|
||||
--- a/modules/proxy/mod_proxy.h
|
||||
+++ b/modules/proxy/mod_proxy.h
|
||||
@@ -116,6 +116,7 @@ struct proxy_remote {
|
||||
const char *protocol; /* the scheme used to talk to this proxy */
|
||||
const char *hostname; /* the hostname of this proxy */
|
||||
ap_regex_t *regexp; /* compiled regex (if any) for the remote */
|
||||
+ const char *creds; /* auth credentials (if any) for the proxy */
|
||||
int use_regex; /* simple boolean. True if we have a regex pattern */
|
||||
apr_port_t port; /* the port for this proxy */
|
||||
};
|
||||
diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c
|
||||
index 0759dac..2bfc8f0 100644
|
||||
--- a/modules/proxy/proxy_util.c
|
||||
+++ b/modules/proxy/proxy_util.c
|
||||
@@ -2446,11 +2446,14 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r,
|
||||
* So let's make it configurable by env.
|
||||
* The logic here is the same used in mod_proxy_http.
|
||||
*/
|
||||
- proxy_auth = apr_table_get(r->headers_in, "Proxy-Authorization");
|
||||
+ proxy_auth = apr_table_get(r->notes, "proxy-basic-creds");
|
||||
+ if (proxy_auth == NULL)
|
||||
+ proxy_auth = apr_table_get(r->headers_in, "Proxy-Authorization");
|
||||
+
|
||||
if (proxy_auth != NULL &&
|
||||
proxy_auth[0] != '\0' &&
|
||||
- r->user == NULL && /* we haven't yet authenticated */
|
||||
- apr_table_get(r->subprocess_env, "Proxy-Chain-Auth")) {
|
||||
+ (r->user == NULL /* we haven't yet authenticated */
|
||||
+ || apr_table_get(r->subprocess_env, "Proxy-Chain-Auth"))) {
|
||||
forward->proxy_auth = apr_pstrdup(conn->pool, proxy_auth);
|
||||
}
|
||||
}
|
||||
@@ -2672,7 +2675,8 @@ static apr_status_t send_http_connect(proxy_conn_rec *backend,
|
||||
nbytes = apr_snprintf(buffer, sizeof(buffer),
|
||||
"CONNECT %s:%d HTTP/1.0" CRLF,
|
||||
forward->target_host, forward->target_port);
|
||||
- /* Add proxy authorization from the initial request if necessary */
|
||||
+ /* Add proxy authorization from the configuration, or initial
|
||||
+ * request if necessary */
|
||||
if (forward->proxy_auth != NULL) {
|
||||
nbytes += apr_snprintf(buffer + nbytes, sizeof(buffer) - nbytes,
|
||||
"Proxy-Authorization: %s" CRLF,
|
||||
@@ -3567,6 +3571,7 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p,
|
||||
apr_bucket *e;
|
||||
int do_100_continue;
|
||||
conn_rec *origin = p_conn->connection;
|
||||
+ const char *creds;
|
||||
proxy_dir_conf *dconf = ap_get_module_config(r->per_dir_config, &proxy_module);
|
||||
|
||||
/*
|
||||
@@ -3743,6 +3748,11 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p,
|
||||
return HTTP_BAD_REQUEST;
|
||||
}
|
||||
|
||||
+ creds = apr_table_get(r->notes, "proxy-basic-creds");
|
||||
+ if (creds) {
|
||||
+ apr_table_mergen(r->headers_in, "Proxy-Authorization", creds);
|
||||
+ }
|
||||
+
|
||||
/* send request headers */
|
||||
headers_in_array = apr_table_elts(r->headers_in);
|
||||
headers_in = (const apr_table_entry_t *) headers_in_array->elts;
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,132 @@
|
||||
diff --git a/docs/manual/mod/mod_proxy_wstunnel.html.en b/docs/manual/mod/mod_proxy_wstunnel.html.en
|
||||
index 21ffbe2..16e1628 100644
|
||||
--- a/docs/manual/mod/mod_proxy_wstunnel.html.en
|
||||
+++ b/docs/manual/mod/mod_proxy_wstunnel.html.en
|
||||
@@ -60,14 +60,33 @@ NONE means you bypass the check for the header but still upgrade to WebSocket.
|
||||
ANY means that <code>Upgrade</code> will read in the request headers and use
|
||||
in the response <code>Upgrade</code></p>
|
||||
</div>
|
||||
-<div id="quickview"><a href="https://www.apache.org/foundation/contributing.html" class="badge"><img src="https://www.apache.org/images/SupportApache-small.png" alt="Support Apache!" /></a><h3 class="directives">Directives</h3>
|
||||
-<p>This module provides no
|
||||
- directives.</p>
|
||||
+<div id="quickview"><h3 class="directives">Directives</h3>
|
||||
+<ul id="toc">
|
||||
+<li><img alt="" src="../images/down.gif" /> <a href="#proxywebsocketidletimeout">ProxyWebsocketIdleTimeout</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_proxy_wstunnel">Known issues</a></li><li><a href="https://bz.apache.org/bugzilla/enter_bug.cgi?product=Apache%20httpd-2&component=mod_proxy_wstunnel">Report a bug</a></li></ul><h3>See also</h3>
|
||||
<ul class="seealso">
|
||||
<li><code class="module"><a href="../mod/mod_proxy.html">mod_proxy</a></code></li>
|
||||
<li><a href="#comments_section">Comments</a></li></ul></div>
|
||||
|
||||
+<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
|
||||
+<div class="directive-section"><h2><a name="ProxyWebsocketIdleTimeout" id="ProxyWebsocketIdleTimeout">ProxyWebsocketIdleTimeout</a> <a name="proxywebsocketidletimeout" id="proxywebsocketidletimeout">Directive</a> <a title="Permanent link" href="#proxywebsocketidletimeout" class="permalink">¶</a></h2>
|
||||
+<table class="directive">
|
||||
+<tr><th><a href="directive-dict.html#Description">Description:</a></th><td>Sets the maximum amount of time to wait for data on the websockets tunnel</td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Syntax">Syntax:</a></th><td><code>ProxyWebsocketIdleTimeout <var>num</var>[ms]</code></td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Default">Default:</a></th><td><code>ProxyWebsocketIdleTimeout 0</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>Extension</td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Module">Module:</a></th><td>mod_proxy_wstunnel</td></tr>
|
||||
+</table>
|
||||
+ <p>This directive imposes a maximum amount of time for the tunnel to be
|
||||
+ left open while idle. The timeout is considered in seconds by default, but
|
||||
+ it is possible to increase the time resolution to milliseconds
|
||||
+ adding the <em>ms</em> suffix.</p>
|
||||
+
|
||||
+</div>
|
||||
+
|
||||
</div>
|
||||
<div class="bottomlang">
|
||||
<p><span>Available Languages: </span><a href="../en/mod/mod_proxy_wstunnel.html" title="English"> en </a> |
|
||||
diff --git a/modules/proxy/mod_proxy_wstunnel.c b/modules/proxy/mod_proxy_wstunnel.c
|
||||
index 4aadbab..ca3ed3a 100644
|
||||
--- a/modules/proxy/mod_proxy_wstunnel.c
|
||||
+++ b/modules/proxy/mod_proxy_wstunnel.c
|
||||
@@ -18,6 +18,10 @@
|
||||
|
||||
module AP_MODULE_DECLARE_DATA proxy_wstunnel_module;
|
||||
|
||||
+typedef struct {
|
||||
+ apr_time_t idle_timeout;
|
||||
+} proxyws_dir_conf;
|
||||
+
|
||||
/*
|
||||
* Canonicalise http-like URLs.
|
||||
* scheme is the scheme for the URL
|
||||
@@ -108,6 +112,8 @@ static int proxy_wstunnel_request(apr_pool_t *p, request_rec *r,
|
||||
conn_rec *c = r->connection;
|
||||
apr_socket_t *sock = conn->sock;
|
||||
conn_rec *backconn = conn->connection;
|
||||
+ proxyws_dir_conf *dconf = ap_get_module_config(r->per_dir_config,
|
||||
+ &proxy_wstunnel_module);
|
||||
char *buf;
|
||||
apr_bucket_brigade *header_brigade;
|
||||
apr_bucket *e;
|
||||
@@ -185,10 +191,13 @@ static int proxy_wstunnel_request(apr_pool_t *p, request_rec *r,
|
||||
c->keepalive = AP_CONN_CLOSE;
|
||||
|
||||
do { /* Loop until done (one side closes the connection, or an error) */
|
||||
- rv = apr_pollset_poll(pollset, -1, &pollcnt, &signalled);
|
||||
+ rv = apr_pollset_poll(pollset, dconf->idle_timeout, &pollcnt, &signalled);
|
||||
if (rv != APR_SUCCESS) {
|
||||
if (APR_STATUS_IS_EINTR(rv)) {
|
||||
continue;
|
||||
+ } else if(APR_STATUS_IS_TIMEUP(rv)){
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "RH: the connection has timed out");
|
||||
+ return HTTP_REQUEST_TIME_OUT;
|
||||
}
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(02444) "error apr_poll()");
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
@@ -366,6 +375,38 @@ cleanup:
|
||||
return status;
|
||||
}
|
||||
|
||||
+static const char * proxyws_set_idle(cmd_parms *cmd, void *conf, const char *val)
|
||||
+{
|
||||
+ proxyws_dir_conf *dconf = conf;
|
||||
+ if (ap_timeout_parameter_parse(val, &(dconf->idle_timeout), "s") != APR_SUCCESS)
|
||||
+ return "ProxyWebsocketIdleTimeout timeout has wrong format";
|
||||
+
|
||||
+ if (dconf->idle_timeout < 0)
|
||||
+ return "ProxyWebsocketIdleTimeout timeout has to be a non-negative number";
|
||||
+
|
||||
+ if (!dconf->idle_timeout) dconf->idle_timeout = -1; /* loop indefinitely */
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+static void *create_proxyws_dir_config(apr_pool_t *p, char *dummy)
|
||||
+{
|
||||
+ proxyws_dir_conf *new =
|
||||
+ (proxyws_dir_conf *) apr_pcalloc(p, sizeof(proxyws_dir_conf));
|
||||
+
|
||||
+ new->idle_timeout = -1; /* no timeout */
|
||||
+
|
||||
+ return (void *) new;
|
||||
+}
|
||||
+
|
||||
+static const command_rec ws_proxy_cmds[] =
|
||||
+{
|
||||
+ AP_INIT_TAKE1("ProxyWebsocketIdleTimeout", proxyws_set_idle, NULL, RSRC_CONF|ACCESS_CONF,
|
||||
+ "timeout for activity in either direction, unlimited by default."),
|
||||
+
|
||||
+ {NULL}
|
||||
+};
|
||||
+
|
||||
static void ap_proxy_http_register_hook(apr_pool_t *p)
|
||||
{
|
||||
proxy_hook_scheme_handler(proxy_wstunnel_handler, NULL, NULL, APR_HOOK_FIRST);
|
||||
@@ -374,10 +415,10 @@ static void ap_proxy_http_register_hook(apr_pool_t *p)
|
||||
|
||||
AP_DECLARE_MODULE(proxy_wstunnel) = {
|
||||
STANDARD20_MODULE_STUFF,
|
||||
- NULL, /* create per-directory config structure */
|
||||
+ create_proxyws_dir_config, /* create per-directory config structure */
|
||||
NULL, /* merge per-directory config structures */
|
||||
NULL, /* create per-server config structure */
|
||||
NULL, /* merge per-server config structures */
|
||||
- NULL, /* command apr_table_t */
|
||||
+ ws_proxy_cmds, /* command apr_table_t */
|
||||
ap_proxy_http_register_hook /* register hooks */
|
||||
};
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,35 @@
|
||||
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 */
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue