Bug#1034329: unblock: apache2/2.4.57-1
Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock
X-Debbugs-Cc: apache2@packages.debian.org
Control: affects -1 + src:apache2
Please unblock package apache2
[ Reason ]
The security fixes provided by version 2.4.56 includes some regressions
(#1033408 and #1033284)
[ Impact ]
Major bugs
[ Tests ]
Test updated, passes
[ Risks ]
Low risk here, the version 2.4.57 contains only bug fixes
[ Checklist ]
[X] all changes are documented in the d/changelog
[X] I reviewed all changes and I approve them
[X] attach debdiff against the package in testing
[ Other info ]
The diff contains also a debian/NEWS entry (added also in bullseye after
#1018718 fix)
unblock apache2/2.4.57-1
diff --git a/CHANGES b/CHANGES
index 16f8f55d..b0e8b117 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,58 @@
-*- coding: utf-8 -*-
+Changes with Apache 2.4.57
+
+ *) mod_proxy: Check before forwarding that a nocanon path has not been
+ rewritten with spaces during processing. [Yann Ylavic]
+
+ *) mod_proxy: In case that AllowEncodedSlashes is set to NoDecode do not
+ double encode encoded slashes in the URL sent by the reverse proxy to the
+ backend. [Ruediger Pluem]
+
+ *) mod_http2: fixed a crash during connection termination. See PR 66539.
+ [Stefan Eissing]
+
+ *) mod_rewrite: Fix a 2.4.56 regression for substitutions ending
+ in a question mark. PR66547. [Eric Covener]
+
+ *) mod_rewrite: Add "BCTLS" and "BNE" RewriteRule flags. Re-allow encoded
+ characters on redirections without the "NE" flag.
+ [Yann Ylavic, Eric Covener]
+
+ *) mod_proxy: Fix double encoding of the uri-path of the request forwarded
+ to the origin server, when using mapping=encoded|servlet. [Yann Ylavic]
+
+ *) mod_mime: Do not match the extention against possible query string
+ parameters in case ProxyPass was used with the nocanon option.
+ [Ruediger Pluem]
+
Changes with Apache 2.4.56
+ *) SECURITY: CVE-2023-27522: Apache HTTP Server: mod_proxy_uwsgi
+ HTTP response splitting (cve.mitre.org)
+ HTTP Response Smuggling vulnerability in Apache HTTP Server via
+ mod_proxy_uwsgi. This issue affects Apache HTTP Server: from
+ 2.4.30 through 2.4.55.
+ Special characters in the origin response header can
+ truncate/split the response forwarded to the client.
+ Credits: Dimas Fariski Setyawan Putra (nyxsorcerer)
+
+ *) SECURITY: CVE-2023-25690: HTTP request splitting with
+ mod_rewrite and mod_proxy (cve.mitre.org)
+ Some mod_proxy configurations on Apache HTTP Server versions
+ 2.4.0 through 2.4.55 allow a HTTP Request Smuggling attack.
+ Configurations are affected when mod_proxy is enabled along with
+ some form of RewriteRule or ProxyPassMatch in which a non-specific
+ pattern matches some portion of the user-supplied request-target (URL)
+ data and is then re-inserted into the proxied request-target
+ using variable substitution. For example, something like:
+ RewriteEngine on
+ RewriteRule "^/here/(.*)" "http://example.com:8080/elsewhere?$1"; [P]
+ ProxyPassReverse /here/ http://example.com:8080/
+ Request splitting/smuggling could result in bypass of access
+ controls in the proxy server, proxying unintended URLs to
+ existing origin servers, and cache poisoning.
+ Credits: Lars Krapf of Adobe
+
*) rotatelogs: Add -T flag to allow subsequent rotated logfiles to be
truncated without the initial logfile being truncated. [Eric Covener]
@@ -112,6 +164,7 @@ Changes with Apache 2.4.55
The checks for this in nghttp2 v1.50.0+ are disabled.
- Extensive testing in production done by Alessandro Bianchi (@alexskynet)
on the v2.0.x versions for stability. Many thanks!
+
*) mod_proxy_http2: fixed #235 by no longer forwarding 'Host:' header when
request ':authority' is known. Improved test case that did not catch that
the previous 'fix' was incorrect.
@@ -319,6 +372,9 @@ Changes with Apache 2.4.54
domain names in the *.ts.net space.
[Stefan Eissing]
+ *) core: Change default value of LimitRequestBody from 0 (unlimited)
+ to 1GB. [Eric Covener]
+
Changes with Apache 2.4.53
*) SECURITY: CVE-2022-23943: mod_sed: Read/write beyond bounds
diff --git a/debian/NEWS b/debian/NEWS
new file mode 100644
index 00000000..a55a9d70
--- /dev/null
+++ b/debian/NEWS
@@ -0,0 +1,9 @@
+apache2 (2.4.54-3) unstable; urgency=medium
+
+ This version does not automatically enable the apache2 config snippet for
+ /manual anymore. If you want to have it enabled you will need to do this
+ yourself, e.g. with
+
+ /usr/sbin/a2enconf apache2-doc
+
+ -- Yadd <yadd@debian.org> Sat, 01 Apr 2023 08:17:08 +0400
diff --git a/debian/changelog b/debian/changelog
index 4ae13cf0..a6602864 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,24 @@
+apache2 (2.4.57-2) unstable; urgency=medium
+
+ * Revert debian/* changes (Bookworm freeze)
+
+ -- Yadd <yadd@debian.org> Thu, 13 Apr 2023 07:26:51 +0400
+
+apache2 (2.4.57-1) unstable; urgency=medium
+
+ * New upstream version 2.4.57
+ * Drop 2.4.56-regression patches
+
+ -- Yadd <yadd@debian.org> Sat, 08 Apr 2023 06:57:16 +0400
+
+apache2 (2.4.56-2) unstable; urgency=medium
+
+ * Fix regression in mod_rewrite introduced in version 2.4.56
+ (Closes: #1033284)
+ * Fix regression in http2 introduced by 2.4.56 (Closes: #1033408)
+
+ -- Yadd <yadd@debian.org> Sun, 02 Apr 2023 06:54:25 +0400
+
apache2 (2.4.56-1) unstable; urgency=medium
* New upstream version (Closes: #1032476, CVE-2023-27522, CVE-2023-25690)
diff --git a/debian/config-dir/sites-available/default-ssl.conf b/debian/config-dir/sites-available/default-ssl.conf
index 9de96fa2..330280de 100644
--- a/debian/config-dir/sites-available/default-ssl.conf
+++ b/debian/config-dir/sites-available/default-ssl.conf
@@ -45,8 +45,8 @@
# certificates for client authentication or alternatively one
# huge file containing all of them (file must be PEM encoded)
# Note: Inside SSLCACertificatePath you need hash symlinks
- # to point to the certificate files. Use the provided
- # Makefile to update the hash symlinks after changes.
+ # to point to the certificate files. Use the provided
+ # Makefile to update the hash symlinks after changes.
#SSLCACertificatePath /etc/ssl/certs/
#SSLCACertificateFile /etc/apache2/ssl.crt/ca-bundle.crt
@@ -55,8 +55,8 @@
# authentication or alternatively one huge file containing all
# of them (file must be PEM encoded)
# Note: Inside SSLCARevocationPath you need hash symlinks
- # to point to the certificate files. Use the provided
- # Makefile to update the hash symlinks after changes.
+ # to point to the certificate files. Use the provided
+ # Makefile to update the hash symlinks after changes.
#SSLCARevocationPath /etc/apache2/ssl.crl/
#SSLCARevocationFile /etc/apache2/ssl.crl/ca-bundle.crl
diff --git a/docs/manual/mod/core.html.tr.utf8 b/docs/manual/mod/core.html.tr.utf8
index ed1dba5c..5d87a514 100644
--- a/docs/manual/mod/core.html.tr.utf8
+++ b/docs/manual/mod/core.html.tr.utf8
@@ -33,7 +33,6 @@
<a href="../ja/mod/core.html" hreflang="ja" rel="alternate" title="Japanese"> ja </a> |
<a href="../tr/mod/core.html" title="Türkçe"> tr </a></p>
</div>
-<div class="outofdate">Bu çeviri güncel olmayabilir. Son değişiklikler için İngilizce sürüm geçerlidir.</div>
<table class="module"><tr><th><a href="module-dict.html#Description">Açıklama:</a></th><td>Apache HTTP Sunucusunda daima mevcut olan çekirdek
özellikler</td></tr>
<tr><th><a href="module-dict.html#Status">Durum:</a></th><td>Çekirdek</td></tr></table>
@@ -1359,6 +1358,11 @@ DocumentRoot "/var/www/${servername}/htdocs"</pre>
</IfDefine></pre>
+ <div class="warning"><h3>Ek Bilgi</h3>
+ <p>Bu yönerge, çalışma zamanında değil, yapılandırma işlemi sırasında
+ değerlendirilir. Sonuç olarak, bu yönerge bir <code class="directive"><a href="#if"><If></a></code> bölümü içine alınarak koşullu olarak
+ değerlendirilemez.</p>
+ </div>
</div>
<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
@@ -1696,7 +1700,7 @@ ErrorLogFormat "[%{uc}t] [%-m:%-l] [R:%L] [C:%{C}L] %7F: %E: %M"
ErrorLogFormat request "[%{uc}t] [R:%L] Request %k on C:%{c}L pid:%P tid:%T"
ErrorLogFormat request "[%{uc}t] [R:%L] UA:'%+{User-Agent}i'"
ErrorLogFormat request "[%{uc}t] [R:%L] Referer:'%+{Referer}i'"
-ErrorLogFormat connection "[%{uc}t] [C:%{c}L] local\ %a remote\ %A"</pre>
+ErrorLogFormat connection "[%{uc}t] [C:%{c}L] remote\ %a local\ %A"</pre>
@@ -2252,6 +2256,13 @@ takdirde uygulanacak yönergeleri barındırır.</td></tr>
yönerge için kullanılabilir olmayacaktır.
</div>
+ <div class="warning"><code class="directive">Define</code>,
+ <code class="directive">Include</code> ve <code class="directive">Error</code> gibi
+ yapılandırma ayrıştırılırken etkili olan yönergeler, bir <code class="directive"><If></code> yapılandırma bölümü içine alınarak koşullu
+ hale getirilemez. Bu bölümler, çalışma anında nasıl değerlendirildiklerine
+ bakılmaksızın, her zaman yapılandırmanın bir parçasıdır.
+ </div>
+
<h3>Ayrıca bakınız:</h3>
<ul>
diff --git a/docs/manual/mod/mod_md.html.fr.utf8 b/docs/manual/mod/mod_md.html.fr.utf8
index 737cfbe7..22a15ac2 100644
--- a/docs/manual/mod/mod_md.html.fr.utf8
+++ b/docs/manual/mod/mod_md.html.fr.utf8
@@ -29,8 +29,6 @@
<p><span>Langues Disponibles: </span><a href="../en/mod/mod_md.html" hreflang="en" rel="alternate" title="English"> en </a> |
<a href="../fr/mod/mod_md.html" title="Français"> fr </a></p>
</div>
-<div class="outofdate">Cette traduction peut être périmée. Vérifiez la version
- anglaise pour les changements récents.</div>
<table class="module"><tr><th><a href="module-dict.html#Description">Description:</a></th><td>Gestion des domaines au sein des serveurs virtuels et obtention
de certificats via le protocole ACME
</td></tr>
@@ -736,6 +734,12 @@
vérification valide pour les certificats génériques. Si vous
avez besoin d'un tel certificat, vous devez alors définir cette
directive.
+ </p><p>
+ Il est maintenant possible d'utiliser cette directive dans une
+ section <code class="directive"><a href="#mdomain">MDomain</a></code> pour
+ spécifier une commande spécifique au domaine considéré. Cela
+ permet de configurer un script spécifique au fournisseur de DNS
+ concerné.
</p><p>
Reportez vous à la section sur les certificats génériques pour
plus de détails.
diff --git a/docs/manual/mod/mod_rewrite.html.en b/docs/manual/mod/mod_rewrite.html.en
index 1631fe0c..30d74341 100644
--- a/docs/manual/mod/mod_rewrite.html.en
+++ b/docs/manual/mod/mod_rewrite.html.en
@@ -1307,6 +1307,16 @@ cannot use <code>$N</code> in the substitution string!
<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 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/mod/mod_rewrite.html.fr.utf8 b/docs/manual/mod/mod_rewrite.html.fr.utf8
index fcb07527..2f2625a9 100644
--- a/docs/manual/mod/mod_rewrite.html.fr.utf8
+++ b/docs/manual/mod/mod_rewrite.html.fr.utf8
@@ -1415,6 +1415,17 @@ substitution !
dans les références arrières <em>avant</em>
d'appliquer la transformation. <em><a href="../rewrite/flags.html#flag_b">détails ...</a></em></td>
</tr>
+<tr class="odd">
+ <td>BCTLS</td>
+ <td>Identique à [B], mais n'échappe que les espaces et les caractères de
+ contrôle. <em><a href="../rewrite/flags.html#flag_bctls">détails ...</a></em></td>
+ </tr>
+<tr>
+ <td>BNE</td>
+ <td>Les caractères de [B] ou [BCTLS] qui <strong>ne doivent pas</strong>
+ être échappés. <em><a href="../rewrite/flags.html#flag_bne">détails
+ ...</a></em></td>
+ </tr>
<tr class="odd">
<td>backrefnoplus|BNP</td>
<td>Avec ce drapeau, si les références arrières sont échappées,
diff --git a/docs/manual/programs/rotatelogs.html.fr.utf8 b/docs/manual/programs/rotatelogs.html.fr.utf8
index c5f8ee1d..fc71646f 100644
--- a/docs/manual/programs/rotatelogs.html.fr.utf8
+++ b/docs/manual/programs/rotatelogs.html.fr.utf8
@@ -30,8 +30,6 @@
<a href="../ko/programs/rotatelogs.html" hreflang="ko" rel="alternate" title="Korean"> ko </a> |
<a href="../tr/programs/rotatelogs.html" hreflang="tr" rel="alternate" title="Türkçe"> tr </a></p>
</div>
-<div class="outofdate">Cette traduction peut être périmée. Vérifiez la version
- anglaise pour les changements récents.</div>
<p><code>rotatelogs</code> est un programme simple à utiliser en
conjonction avec la fonctionnalité d'Apache de redirection dans un
@@ -120,6 +118,15 @@ chaînes de format contenant des caractères '%' sont cependant
respectées.
</dd>
+<dt><code>-T</code></dt>
+<dd>Provoque la troncature de tous les fichiers journaux lors de leur ouverture,
+à l'exception du fichier journal initial. Cela s'avère utile lorsque la chaîne
+de formatage contient quelque chose qui va se répéter de manière cyclique, comme
+le jour du mois par exemple. Disponible à partir de la version 2.4.56 du serveur
+HTTP Apache.
+</dd>
+
+
<dt><code>-v</code></dt>
<dd>Affiche une sortie verbeuse sur STDERR. La sortie contient le
résultat de l'interprétation de la configuration, ainsi que toutes les
@@ -252,6 +259,15 @@ spécifier un décalage.</dd>
tronquant au démarrage, puis une fois par jour. Ce scénario implique qu'un
processus séparé (tel que tail) traite le fichier en temps réel.</p>
+<div class="example"><pre class="prettyprint lang-config">CustomLog "|bin/rotatelogs -T /var/log/logfile.%d 86400" common</pre>
+</div>
+
+<p>Si le serveur est démarré ou redémarré le premier du mois, cela s'ajoute à la
+fin de <code>/var/log/logfile.01</code>. Lorsqu'une entrée de journal est écrite
+le deux du mois, <code>/var/log/logfile.02</code> est tronqué et les nouvelles
+entrées seront ajoutées à partir du début du fichier. Cet exemple conserve
+environ 1 mois de journaux sans nécessiter de maintenance externe.</p>
+
</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
<div class="section">
<h2><a name="portability" id="portability">Portabilité</a></h2>
diff --git a/docs/manual/programs/rotatelogs.html.tr.utf8 b/docs/manual/programs/rotatelogs.html.tr.utf8
index dd0156c3..22d438b6 100644
--- a/docs/manual/programs/rotatelogs.html.tr.utf8
+++ b/docs/manual/programs/rotatelogs.html.tr.utf8
@@ -30,7 +30,6 @@
<a href="../ko/programs/rotatelogs.html" hreflang="ko" rel="alternate" title="Korean"> ko </a> |
<a href="../tr/programs/rotatelogs.html" title="Türkçe"> tr </a></p>
</div>
-<div class="outofdate">Bu çeviri güncel olmayabilir. Son değişiklikler için İngilizce sürüm geçerlidir.</div>
<p><code><strong>rotatelogs</strong></code>, Apache'nin borulu günlük
dosyaları özelliği ile birlikte kullanmak için tasarlanmış basit bir
@@ -109,6 +108,13 @@
Dosya ismine bir sonek eklenmez, ancak biçem dizgesi '%' karakteri
içeriyorsa buna uyulur.</dd>
+ <dt><code>-T</code></dt>
+ <dd>Açıldığında ilk günlük dosyası dışındaki tüm dosyaların kırpılmasına
+ neden olur. Bu, biçem dizgesi ayın günü gibi döngüsel bir şey içerdiğinde
+ kullanışlıdır. 2.4.56 ve sonrasında mevcuttur.
+ </dd>
+
+
<dt><code><strong>-v</strong></code></dt>
<dd>Standart hataya verilen çıktı daha ayrıntılı olur. Çıktı,
yapılandırma çözümlemesinin sonuçlarını ve tüm dosya açma/kapama
@@ -191,9 +197,8 @@
<div class="section">
<h2><a name="examples" id="examples">Örnekler</a></h2>
-<div class="example"><p><code>
- CustomLog "|bin/rotatelogs /var/log/logfile 86400" common
-</code></p></div>
+<div class="example"><pre class="prettyprint lang-config">CustomLog "|bin/rotatelogs /var/log/logfile 86400" common</pre>
+</div>
<p>nnnn, günlük kaydının başladığı sistem zamanı olmak üzere
/var/log/logfile.nnnn dosyası oluşturulur. Bu zaman, daima döngü
@@ -201,36 +206,41 @@
kullanabilirsiniz. Her döngü süresinin sonunda (burada 24 saat sonra)
yeni bir günlük dosyası açılır.</p>
-<div class="example"><p><code>
- CustomLog "|bin/rotatelogs -l /var/log/logfile.%Y.%m.%d 86400" common
-</code></p></div>
+<div class="example"><pre class="prettyprint lang-config">CustomLog "|bin/rotatelogs -l /var/log/logfile.%Y.%m.%d 86400" common</pre>
+</div>
<p>yyyy, yıl; mm, ay; dd, ayın gününü belirtmek üzere
/var/log/logfile.yyyy.mm.dd dosyası oluşturulur. Her gün yerel zamanla
geceyarısı yeni bir günlük dosyasına geçilecektir.</p>
-<div class="example"><p><code>
- CustomLog "|bin/rotatelogs /var/log/logfile 5M" common
-</code></p></div>
+<div class="example"><pre class="prettyprint lang-config">CustomLog "|bin/rotatelogs /var/log/logfile 5M" common</pre>
+</div>
<p>Günlük dosyası 5 megabaytlık olunca yenisinin oluşturulmasını sağlar.
</p>
-<div class="example"><p><code>
- ErrorLog "|bin/rotatelogs /var/log/errorlog.%Y-%m-%d-%H_%M_%S 5M"
-</code></p></div>
+<div class="example"><pre class="prettyprint lang-config">ErrorLog "|bin/rotatelogs /var/log/errorlog.%Y-%m-%d-%H_%M_%S 5M"</pre>
+</div>
<p>Hata günlüğünün 5 megabaytta bir
<code>errorlog.YYYY-mm-dd-HH_MM_SS</code> biçemli bir isimle
oluşturulmasını sağlar.</p>
-<div class="example"><p><code>
- CustomLog "|bin/rotatelogs -t /var/log/logfile 86400" common
-</code></p></div>
+<div class="example"><pre class="prettyprint lang-config">CustomLog "|bin/rotatelogs -t /var/log/logfile 86400" common</pre>
+</div>
- <p>/var/log/logfile dosyasını oluşturur, sunucu başlatılırken ve günde
+ <p><code>/var/log/logfile</code> dosyasını oluşturur, sunucu başlatılırken ve günde
bir kere dosyanın tepesi kırpılır. Bu senaryoda ayrı bir sürecin (tail
gibi) dosyayı gerçek zamanlı işleyeceği umulur.</p>
+<div class="example"><pre class="prettyprint lang-config">CustomLog "|bin/rotatelogs -T /var/log/logfile.%d 86400" common</pre>
+</div>
+
+ <p>Sunucu ayın birinde başlatılırsa (veya yeniden başlatılırsa), bu,
+ <code>/var/log/logfile.01</code> dosyasının sonuna eklenir. Ayın ikinci
+ günü bir günlük girişi yazıldığında, <code>/var/log/logfile.02</code>
+ kırpılır ve en üste yeni girdiler eklenir. Bu örnek, özel bir bakım
+ gerektirmeden yaklaşık 1 aylık günlük tutar.</p>
+
</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
<div class="section">
<h2><a name="portability" id="portability">Taşınabilirlik</a></h2>
diff --git a/docs/manual/rewrite/flags.html.en b/docs/manual/rewrite/flags.html.en
index 5ffd1b2e..5e175f17 100644
--- a/docs/manual/rewrite/flags.html.en
+++ b/docs/manual/rewrite/flags.html.en
@@ -34,6 +34,8 @@ providing detailed explanations and examples.</p>
<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><ul id="toc"><li><img alt="" src="../images/down.gif" /> <a href="#introduction">Introduction</a></li>
<li><img alt="" src="../images/down.gif" /> <a href="#flag_b">B (escape backreferences)</a></li>
<li><img alt="" src="../images/down.gif" /> <a href="#flag_bnp">BNP|backrefnoplus (don't escape space to +)</a></li>
+<li><img alt="" src="../images/down.gif" /> <a href="#flag_bctls">BCTLS</a></li>
+<li><img alt="" src="../images/down.gif" /> <a href="#flag_bne">BNE</a></li>
<li><img alt="" src="../images/down.gif" /> <a href="#flag_c">C|chain</a></li>
<li><img alt="" src="../images/down.gif" /> <a href="#flag_co">CO|cookie</a></li>
<li><img alt="" src="../images/down.gif" /> <a href="#flag_dpi">DPI|discardpath</a></li>
@@ -85,10 +87,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 +118,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>
@@ -127,8 +139,40 @@ strings in the encoded form.</p>
in a backreference to %20 rather than '+'. Useful when the backreference
will be used in the path component rather than the query string.</p>
+<pre class="prettyprint lang-config"># Escape spaces to %20 in the path instead of + as used in form submission via
+# the query string
+RewriteRule "^search/(.*)$" "/search.php/$1" "[B,BNP]"</pre>
+
+
+
<p>This flag is available in version 2.4.26 and later.</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_bctls" id="flag_bctls">BCTLS</a></h2>
+<p>The [BCTLS] flag is similar to the [B] flag, but only escapes
+control characters and the space character. This is the same set of
+characters rejected when they are copied into the query string unencoded.
+</p>
+
+<pre class="prettyprint lang-config"># Escape control characters and spaces
+RewriteRule "^search/(.*)$" "/search.php/$1" "[BCTLS]"</pre>
+
+
+<p>This flag is available in version 2.4.57 and later.</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_bne" id="flag_bne">BNE</a></h2>
+<p>The list of characters in [BNE=...] are treated as exclusions to the
+characters of the [B] or [BCTLS] flags. The listed characters will not be
+escaped.
+</p>
+
+<pre class="prettyprint lang-config"># Escape the default characters, but leave /
+RewriteRule "^search/(.*)$" "/search.php?term=$1" "[B,BNE=/]"</pre>
+
+<p>This flag is available in version 2.4.57 and later.</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_c" id="flag_c">C|chain</a></h2>
@@ -210,7 +254,7 @@ attribute is set to the specified value. Typical values are <code>None</code>,
<p>Consider this example:</p>
<pre class="prettyprint lang-config">RewriteEngine On
-RewriteRule "^/index\.html" "-" [CO=frontdoor:yes:.example.com:1440:/]</pre>
+RewriteRule "^/index\.html" "-" [CO=frontdoor:yes:.example.com:1440:/]</pre>
<p>In the example give, the rule doesn't rewrite the request.
@@ -295,8 +339,8 @@ value of '1' if the requested URI is an image file. Then, that
environment variable is used to exclude those requests from the access
log.</p>
-<pre class="prettyprint lang-config">RewriteRule "\.(png|gif|jpg)$" "-" [E=image:1]
-CustomLog "logs/access_log" combined env=!image</pre>
+<pre class="prettyprint lang-config">RewriteRule "\.(png|gif|jpg)$" "-" [E=image:1]
+CustomLog "logs/access_log" combined env=!image</pre>
<p>Note that this same effect can be obtained using <code class="directive"><a href="../mod/mod_setenvif.html#setenvif">SetEnvIf</a></code>. This technique is offered as
@@ -321,7 +365,7 @@ allows more flexibility in assigning a Forbidden status.</p>
<p>The following rule will forbid <code>.exe</code> files from being
downloaded from your server.</p>
-<pre class="prettyprint lang-config">RewriteRule "\.exe" "-" [F]</pre>
+<pre class="prettyprint lang-config">RewriteRule "\.exe" "-" [F]</pre>
<p>This example uses the "-" syntax for the rewrite target, which means
@@ -341,7 +385,7 @@ longer available.</p>
<p>As with the [F] flag, you will typically use the "-" syntax for the
rewrite target when using the [G] flag:</p>
-<pre class="prettyprint lang-config">RewriteRule "oldproduct" "-" [G,NC]</pre>
+<pre class="prettyprint lang-config">RewriteRule "oldproduct" "-" [G,NC]</pre>
<p>When using [G], an [L] is implied - that is, the response is returned
@@ -354,7 +398,7 @@ immediately, and no further rules are evaluated.</p>
handler. For example, one might use this to force all files without a
file extension to be parsed by the php handler:</p>
-<pre class="prettyprint lang-config">RewriteRule "!\." "-" [H=application/x-httpd-php]</pre>
+<pre class="prettyprint lang-config">RewriteRule "!\." "-" [H=application/x-httpd-php]</pre>
<p>
@@ -416,8 +460,8 @@ argument to <code>index.php</code>, however, the <code class="directive"><a href
is already for <code>index.php</code>, the <code class="directive"><a href="../mod/mod_rewrite.html#rewriterule">RewriteRule</a></code> will be skipped.</p>
<pre class="prettyprint lang-config">RewriteBase "/"
-RewriteCond "%{REQUEST_URI}" "!=/index.php"
-RewriteRule "^(.*)" "/index.php?req=$1" [L,PT]</pre>
+RewriteCond "%{REQUEST_URI}" !=/index.php
+RewriteRule "^(.*)" "/index.php?req=$1" [L,PT]</pre>
</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
<div class="section">
@@ -440,11 +484,11 @@ pattern still matches (i.e., while the URI still contains an
<code>A</code>), perform this substitution (i.e., replace the
<code>A</code> with a <code>B</code>).</p>
-<p>In 2.4.8 and later, this module returns an error after 32,000 iterations to
+<p>In 2.4.8 and later, this module returns an error after 10,000 iterations to
protect against unintended looping. An alternative maximum number of
iterations can be specified by adding to the N flag. </p>
<pre class="prettyprint lang-config"># Be willing to replace 1 character in each pass of the loop
-RewriteRule "(.+)[><;]$" "$1" [N=64000]
+RewriteRule "(.+)[><;]$" "$1" [N=32000]
# ... or, give up if after 10 loops
RewriteRule "(.+)[><;]$" "$1" [N=10]</pre>
@@ -688,19 +732,21 @@ URI in request' warnings.
<p>The [S] flag is used to skip rules that you don't want to run. The
syntax of the skip flag is [S=<em>N</em>], where <em>N</em> signifies
the number of rules to skip (provided the <code class="directive"><a href="../mod/mod_rewrite.html#rewriterule">
-RewriteRule</a></code> matches). This can be thought of as a <code>goto</code>
-statement in your rewrite ruleset. In the following example, we only want
-to run the <code class="directive"><a href="../mod/mod_rewrite.html#rewriterule">RewriteRule</a></code> if the
-requested URI doesn't correspond with an actual file.</p>
+RewriteRule</a></code> and any preceding <code class="directive"><a href="../mod/mod_rewrite.html#rewritecond">
+RewriteCond</a></code> directives match). This can be thought of as a
+<code>goto</code> statement in your rewrite ruleset. In the following
+example, we only want to run the <code class="directive"><a href="../mod/mod_rewrite.html#rewriterule">
+RewriteRule</a></code> if the requested URI doesn't correspond with an
+actual file.</p>
<pre class="prettyprint lang-config"># Is the request for a non-existent file?
-RewriteCond "%{REQUEST_FILENAME}" "!-f"
-RewriteCond "%{REQUEST_FILENAME}" "!-d"
+RewriteCond "%{REQUEST_FILENAME}" !-f
+RewriteCond "%{REQUEST_FILENAME}" !-d
# If so, skip these two RewriteRules
-RewriteRule ".?" "-" [S=2]
+RewriteRule ".?" "-" [S=2]
-RewriteRule "(.*\.gif)" "images.php?$1"
-RewriteRule "(.*\.html)" "docs.php?$1"</pre>
+RewriteRule "(.*\.gif)" "images.php?$1"
+RewriteRule "(.*\.html)" "docs.php?$1"</pre>
<p>This technique is useful because a <code class="directive"><a href="../mod/mod_rewrite.html#rewritecond">RewriteCond</a></code> only applies to the
@@ -712,18 +758,18 @@ use this to make pseudo if-then-else constructs: The last rule of
the then-clause becomes <code>skip=N</code>, where N is the
number of rules in the else-clause:</p>
<pre class="prettyprint lang-config"># Does the file exist?
-RewriteCond "%{REQUEST_FILENAME}" "!-f"
-RewriteCond "%{REQUEST_FILENAME}" "!-d"
+RewriteCond "%{REQUEST_FILENAME}" !-f
+RewriteCond "%{REQUEST_FILENAME}" !-d
# Create an if-then-else construct by skipping 3 lines if we meant to go to the "else" stanza.
-RewriteRule ".?" "-" [S=3]
+RewriteRule ".?" "-" [S=3]
# IF the file exists, then:
- RewriteRule "(.*\.gif)" "images.php?$1"
+ RewriteRule "(.*\.gif)" "images.php?$1"
RewriteRule "(.*\.html)" "docs.php?$1"
# Skip past the "else" stanza.
- RewriteRule ".?" "-" [S=1]
+ RewriteRule ".?" "-" [S=1]
# ELSE...
- RewriteRule "(.*)" "404.php?file=$1"
+ RewriteRule "(.*)" "404.php?file=$1"
# END</pre>
@@ -740,7 +786,7 @@ sent. This has the same effect as the <code class="directive"><a href="../mod/mo
source code as plain text, if requested in a particular way:</p>
<pre class="prettyprint lang-config"># Serve .pl files as plain text
-RewriteRule "\.pl$" "-" [T=text/plain]</pre>
+RewriteRule "\.pl$" "-" [T=text/plain]</pre>
<p>Or, perhaps, if you have a camera that produces jpeg images without
@@ -748,7 +794,7 @@ file extensions, you could force those images to be served with the
correct MIME type by virtue of their file names:</p>
<pre class="prettyprint lang-config"># Files with 'IMG' in the name are jpg images.
-RewriteRule "IMG" "-" [T=image/jpg]</pre>
+RewriteRule "IMG" "-" [T=image/jpg]</pre>
<p>Please note that this is a trivial example, and could be better done
diff --git a/docs/manual/rewrite/flags.html.fr.utf8 b/docs/manual/rewrite/flags.html.fr.utf8
index 75d9aa84..4c3e4864 100644
--- a/docs/manual/rewrite/flags.html.fr.utf8
+++ b/docs/manual/rewrite/flags.html.fr.utf8
@@ -88,13 +88,7 @@ d'utilisation.</p>
<div class="section">
<h2><a name="flag_b" id="flag_b">B (échappement dans les références arrières)</a></h2>
<p>Avec le drapeau [B], la directive <code class="directive"><a href="../mod/mod_rewrite.html#rewriterule">RewriteRule</a></code> échappe les caractères
-non-alphanumériques avant d'appliquer la transformation. A partir
-de la version 2.4.26, vous pouvez limiter l'échappement dans les
-références arrières à une liste de caractères que vous pouvez spécifiez comme
-dans cet exemple : <code>[B=#?;]</code>. Notez que l'espace peut faire
-partie de la liste des caractères à échapper, mais qu'il ne doit pas
-être le dernier caractère de cette liste.
-</p>
+non-alphanumériques avant d'appliquer la transformation.</p>
<p><code>mod_rewrite</code> doit supprimer les séquences d'échappement
des URLs avant leur
@@ -138,6 +132,22 @@ si on présente à ce dernier une URL non échappée.</p>
%{THE_REQUEST}, les chaînes capturées se présentant
alors sous la forme codée.</p>
+<p>A partir
+de la version 2.4.26, vous pouvez limiter l'échappement dans les
+références arrières à une liste de caractères que vous pouvez spécifiez comme
+dans cet exemple : <code>[B=#?;]</code>. Notez que l'espace peut faire
+partie de la liste des caractères à échapper, mais que vous devez mettre entre
+guillemets le troisième argument de la directive <code class="directive"><a href="../mod/mod_rewrite.html#rewriterule">RewriteRule</a></code> et que l'espace ne doit pas
+être le dernier caractère de cette liste.
+</p>
+
+<pre class="prettyprint lang-config"># Échappement des espaces et des points d'interrogation. Les guillemets autour
+# du dernier argument sont obligatoires lorsque l'espace est inclus.
+RewriteRule "^search/(.*)$" "/search.php?term=$1" "[B= ?]"</pre>
+
+
+<p>Pour définir la liste des caractères à échapper de cette manière, voir <a href="flag_bne">flag_bne</a> et <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 (ne pas échapper
@@ -147,9 +157,43 @@ espace en %20 au lieu de '+' dans les références arrières. Ceci s'avère
utile lorsque la référence arrière est utilisée dans la partie chemin,
et non dans les paramètres de la requête.</p>
+<pre class="prettyprint lang-config"># Échappe le caractère espace en %20 dans le chemin au lieu de + comme dans la
+# soumission de formulaire à l'aide de la chaîne de paramètres
+RewriteRule "^search/(.*)$" "/search.php/$1" "[B,BNP]"</pre>
+
+
<p>Ce drapeau est disponible à partir de la version 2.4.26 du serveur HTTP
Apache.</p>
+<h3><a name="flag_bctls" id="flag_bctls">BCTLS</a></h3>
+<p>Le drapeau [BCTLS] est similaire à [B], à la différence que seuls les espaces
+et les caractères de contrôle sont échappés. Il s'agit du même jeu de caractères
+rejetés lorsqu'ils sont copiés dans la chaîne de paramètres non codée.
+</p>
+
+<pre class="prettyprint lang-config"># Échappe les espaces et les caractères de contrôle
+RewriteRule "^search/(.*)$" "/search.php/$1" "[BCTLS]"</pre>
+
+
+<p>Ce drapeau est disponible à partir de la version 2.4.57 du serveur HTTP
+Apache.</p>
+
+
+
+<h3><a name="flag_bne" id="flag_bne">BNE</a></h3>
+<p>Les caractères listés dans [BNE=...] sont exclus des listes de caractères
+correspondant aux drapeaux [B] ou [BCTLS]. Ils ne seront donc pas échappés.
+</p>
+
+<pre class="prettyprint lang-config"># Échappe les caractères par défaut, sauf /
+RewriteRule "^search/(.*)$" "/search.php?term=$1" "[B,BNE=/]"</pre>
+
+
+<p>Ce drapeau est disponible à partir de la version 2.4.57 du serveur HTTP
+Apache.</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_c" id="flag_c">C|chain</a></h2>
@@ -234,7 +278,7 @@ partir de la version 2.4.47 du serveur HTTP Apache.</dd>
<p>Voici un exemple :</p>
<pre class="prettyprint lang-config">RewriteEngine On
-RewriteRule "^/index\.html" "-" [CO=frontdoor:yes:.example.org:1440:/]</pre>
+RewriteRule "^/index\.html" "-" [CO=frontdoor:yes:.example.com:1440:/]</pre>
<p>Dans l'exemple ci-dessus, la règle ne réécrit
@@ -321,10 +365,9 @@ avec une valeur de '1' si l'URI de la requête correspond à un fichier
image. Cette variable d'environnement est ensuite utilisée pour exclure
une telle requête du journal des accès.</p>
-<div class="example"><p><code>
-RewriteRule "\.(png|gif|jpg)" "-" [E=image:1]<br />
-CustomLog "logs/access_log" combined env=!image
-</code></p></div>
+<pre class="prettyprint lang-config">RewriteRule "\.(png|gif|jpg)$" "-" [E=image:1]
+CustomLog "logs/access_log" combined env=!image</pre>
+
<p>Notez que le même effet peut être obtenu à l'aide de la directive
<code class="directive"><a href="../mod/mod_setenvif.html#setenvif">SetEnvIf</a></code>. Cette technique
@@ -351,7 +394,7 @@ Forbidden.</p>
<p>La règle suivante va interdire la téléchargement de fichiers
<code>.exe</code> depuis votre serveur.</p>
-<pre class="prettyprint lang-config">RewriteRule "\.exe" "-" [F]</pre>
+<pre class="prettyprint lang-config">RewriteRule "\.exe" "-" [F]</pre>
<p>Cet exemple utilise la syntaxe "-" pour la cible de réécriture, ce
@@ -372,7 +415,7 @@ disponible auparavant ne l'est plus actuellement.</p>
<p>Comme dans le cas du drapeau [F], on utilise en général la syntaxe
"-" pour la cible de réécriture lorsqu'on utilise le drapeau [G] :</p>
-<pre class="prettyprint lang-config">RewriteRule "oldproduct" "-" [G,NC]</pre>
+<pre class="prettyprint lang-config">RewriteRule "oldproduct" "-" [G,NC]</pre>
<p>Lorsqu'on utilise [G], [L] est implicite - c'est à dire que la
@@ -386,7 +429,7 @@ spécifié. Par exemple, on peut utiliser ce drapeau pour forcer
l'interprétation de tous les fichiers sans extension par le gestionnaire
php :</p>
-<pre class="prettyprint lang-config">RewriteRule "!\." "-" [H=application/x-httpd-php]</pre>
+<pre class="prettyprint lang-config">RewriteRule "!\." "-" [H=application/x-httpd-php]</pre>
<p>
@@ -455,8 +498,8 @@ directive <code class="directive"><a href="../mod/mod_rewrite.html#rewritecond">
la requête concerne déjà <code>index.php</code>, la directive <code class="directive"><a href="../mod/mod_rewrite.html#rewriterule">RewriteRule</a></code> sera sautée.</p>
<pre class="prettyprint lang-config">RewriteBase "/"
-RewriteCond "%{REQUEST_URI}" "!=/index.php"
-RewriteRule "^(.*)" "/index.php?req=$1" [L,PT]</pre>
+RewriteCond "%{REQUEST_URI}" !=/index.php
+RewriteRule "^(.*)" "/index.php?req=$1" [L,PT]</pre>
</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
<div class="section">
@@ -484,10 +527,10 @@ effectuer la substitution (c'est à dire, remplacer le <code>A</code> par
un <code>B</code>).</p>
<p>A partir de la version 2.4.8, ce module renvoie une erreur après
-32000 itérations afin d'éviter les boucles infinies. Ce nombre maximum
+10000 itérations afin d'éviter les boucles infinies. Ce nombre maximum
d'itération peut être modifié via le drapeau N.</p>
<pre class="prettyprint lang-config"># On veut remplacer 1 caractère à chaque itération de la boucle
-RewriteRule "(.+)[><;]$" "$1" [N=64000]
+RewriteRule "(.+)[><;]$" "$1" [N=32000]
# ... ou s'arrêter après 10 itérations
RewriteRule "(.+)[><;]$" "$1" [N=10]</pre>
@@ -745,19 +788,21 @@ avertissements 'Invalid URI in request'.
<p>Le drapeau [S] sert à sauter des règles que vous ne voulez pas voir
exécuter. La syntaxe du drapeau [S] est [S=<em>N</em>], où
<em>N</em> correspond au nombre de règles à sauter (sous
-réserve que la règle <code class="directive"><a href="../mod/mod_rewrite.html#rewriterule">RewriteRule</a></code> corresponde).
+réserve que la règle <code class="directive"><a href="../mod/mod_rewrite.html#rewriterule">RewriteRule</a></code> corresponde et qu'au moins
+une condition <code class="directive"><a href="../mod/mod_rewrite.html#rewritecond">RewriteCond</a></code>
+préalable soit vérifiée).
Ceci peut s'interpréter comme une instruction
<code>goto</code> dans votre jeu de règles de réécriture. Dans
l'exemple suivant, nous ne voulons exécuter la règle <code class="directive"><a href="../mod/mod_rewrite.html#rewriterule">RewriteRule</a></code> que si l'URI demandé ne
correspond pas à un fichier existant.</p>
<pre class="prettyprint lang-config"># La requête concerne-t-elle un fichier qui n'existe pas ?
-RewriteCond "%{REQUEST_FILENAME}" "!-f"
-RewriteCond "%{REQUEST_FILENAME}" "!-d"
+RewriteCond "%{REQUEST_FILENAME}" !-f
+RewriteCond "%{REQUEST_FILENAME}" !-d
# Si c'est la cas, on saute les deux règles de réécriture suivantes
-RewriteRule ".?" "-" [S=2]
+RewriteRule ".?" "-" [S=2]
-RewriteRule "(.*\.gif)" "images.php?$1"
-RewriteRule "(.*\.html)" "docs.php?$1"</pre>
+RewriteRule "(.*\.gif)" "images.php?$1"
+RewriteRule "(.*\.html)" "docs.php?$1"</pre>
@@ -772,18 +817,19 @@ d'élaborer des pseudo-constructions if-then-else : la dernière règle du
bloc then contiendra <code>skip=N</code>, où N est le nombre de règles
contenues dans le bloc else :</p>
<pre class="prettyprint lang-config"># Est-ce que le fichier existe ?
-RewriteCond "%{REQUEST_FILENAME}" "!-f"
-RewriteCond "%{REQUEST_FILENAME}" "!-d"
-# Create an if-then-else construct by skipping 3 lines if we meant to go to the "else" stanza.
-RewriteRule ".?" "-" [S=3]
+RewriteCond "%{REQUEST_FILENAME}" !-f
+RewriteCond "%{REQUEST_FILENAME}" !-d
+# Créer une structure conditionnelle if-then-else en sautant 3 lignes si nous
+# avions l'intention d'aller au bloc "else".
+RewriteRule ".?" "-" [S=3]
# Si le fichier existe, alors :
-RewriteRule "(.*\.gif)" "images.php?$1"
+ RewriteRule "(.*\.gif)" "images.php?$1"
RewriteRule "(.*\.html)" "docs.php?$1"
- # Skip past the "else" stanza.
- RewriteRule ".?" "-" [S=1]
+ # Passer le bloc "else".
+ RewriteRule ".?" "-" [S=1]
# ELSE...
-RewriteRule "(.*)" "404.php?file=$1
+ RewriteRule "(.*)" "404.php?file=$1"
# END</pre>
@@ -801,7 +847,7 @@ du code source Perl en tant que plein texte, s'il est requis d'une
certaine manière :</p>
<pre class="prettyprint lang-config"># Sert les fichier .pl en tant que plein texte
-RewriteRule "\.pl$" "-" [T=text/plain]</pre>
+RewriteRule "\.pl$" "-" [T=text/plain]</pre>
<p>Ou encore, si vous possédez une caméra qui produit des fichiers
@@ -809,7 +855,7 @@ images jpeg sans extension, vous pouvez forcer le renvoi de ces images
avec le type MIME correct en se basant sur le nom du fichier :</p>
<pre class="prettyprint lang-config"># Les fichiers dont le nom contient 'IMG' sont des images jpg.
-RewriteRule "IMG" "-" [T=image/jpg]</pre>
+RewriteRule "IMG" "-" [T=image/jpg]</pre>
<p>Notez cependant qu'il s'agit d'un exemple trivial, et que le problème
diff --git a/docs/manual/sections.html.tr.utf8 b/docs/manual/sections.html.tr.utf8
index be6ff8a7..b3a7cbf9 100644
--- a/docs/manual/sections.html.tr.utf8
+++ b/docs/manual/sections.html.tr.utf8
@@ -29,7 +29,6 @@
<a href="./ko/sections.html" hreflang="ko" rel="alternate" title="Korean"> ko </a> |
<a href="./tr/sections.html" title="Türkçe"> tr </a></p>
</div>
-<div class="outofdate">Bu çeviri güncel olmayabilir. Son değişiklikler için İngilizce sürüm geçerlidir.</div>
<p><a href="configuring.html">Yapılandırma dosyaları</a>ndaki
yönergeler sunucunun tamamına uygulanacağı gibi sadece belli dizinler,
@@ -349,9 +348,9 @@ ProxyPass "/" "balancer://mycluster/" stickysession=JSESSIONID|jsessionid nofail
<p>Bazı bölüm türleri başka bölüm türlerinin içinde olabilir. Bir yandan,
<code class="directive"><a href="./mod/core.html#files"><Files></a></code> bölümü
<code class="directive"><a href="./mod/core.html#directory"><Directory></a></code> bölümünün
- içinde bulunabilirken diğer yandan bir <code class="directive"><a href="./mod/core.html#if"><If></a></code> bölümü <code class="directive"><a href="./mod/core.html#directory"><Directory></a></code>, <code class="directive"><a href="./mod/core.html#location"><Location></a></code> ve <code class="directive"><a href="./mod/core.html#files"><Files></a></code> bölümlerinde bulunabilir fakat
- başka bir <code class="directive"><a href="./mod/core.html#if"><If></a></code> bölümünün
- içinde bulunamaz. Bu bölümlerin düzenli ifadeli türevleri de benzer tarzda
+ içinde bulunabilirken diğer yandan bir <code class="directive"><a href="./mod/core.html#if"><If></a></code> bölümü <code class="directive"><a href="./mod/core.html#directory"><Directory></a></code>, <code class="directive"><a href="./mod/core.html#location"><Location></a></code> ve <code class="directive"><a href="./mod/core.html#files"><Files></a></code> bölümlerinde bulunabilir fakat
+ başka bir <code class="directive"><a href="./mod/core.html#if"><If></a></code> bölümünün
+ içinde bulunamaz. Bu bölümlerin düzenli ifadeli türevleri de benzer tarzda
davranır.</p>
<p>İç içe bölümler, aynı türdeki iç içe olmayan bölümlerin sonrasına
@@ -440,7 +439,9 @@ ProxyPass "/" "balancer://mycluster/" stickysession=JSESSIONID|jsessionid nofail
ve <code class="directive"><a href="./mod/core.html#locationmatch"><LocationMatch></a></code>
aynı anda işleme sokulur.</li>
- <li><code class="directive"><a href="./mod/core.html#if"><If></a></code>
+ <li><code class="directive"><a href="./mod/core.html#if"><If></a></code> bölümleri,
+ önceki bağlamlardan herhangi birinin içine alınmış olsalar bile.
+
</li>
</ol>
@@ -448,31 +449,41 @@ ProxyPass "/" "balancer://mycluster/" stickysession=JSESSIONID|jsessionid nofail
<ul>
<li><code class="directive"><a href="./mod/core.html#directory"><Directory></a></code>
bölümündekiler hariç, her grup, yapılandırma dosyasında bulundukları
- sıraya göre işleme sokulurlar. Örneğin, 4. grupta <em>/foo/bar</em> için yapılan
- bir istek <code><Location "/foo/bar"></code> ve <code><Location
- "/foo"></code> bölümleriyle de eşleşir ve bunlar yapılandırma
+ sıraya göre işleme sokulurlar. Örneğin, 4. grupta <em>/foo/bar</em> için yapılan
+ bir istek <code><Location "/foo/bar"></code> ve <code><Location
+ "/foo"></code> bölümleriyle de eşleşir ve bunlar yapılandırma
dosyalarında bulundukları sıraya göre değerlendirilir.</li>
-
- <li>Yukarıda 1. grup olan <code class="directive"><a href="./mod/core.html#directory"><Directory></a></code> bölümü en kısa dizin elemanından en uzun
- dizin elemanına doğru işleme sokulur. Yani, örneğin, <code><Directory
- "/var/web/dir"></code> bölümü <code><Directory
+
+ <li>Yukarıda 1. grup olan <code class="directive"><a href="./mod/core.html#directory"><Directory></a></code> bölümü en kısa dizin elemanından en uzun
+ dizin elemanına doğru işleme sokulur. Yani, örneğin, <code><Directory
+ "/var/web/dir"></code> bölümü <code><Directory
"/var/web/dir/subdir"></code> bölümünden önce işleme sokulacaktır.</li>
-
- <li>Eğer aynı dizin için birden fazla <code class="directive"><a href="./mod/core.html#directory"><Directory></a></code> bölümü varsa bunlar yapılandırma
+
+ <li>Eğer aynı dizin için birden fazla <code class="directive"><a href="./mod/core.html#directory"><Directory></a></code> bölümü varsa bunlar yapılandırma
dosyasında bulundukları sıraya göre işleme sokulurlar.</li>
-
- <li><code class="directive"><a href="./mod/core.html#include">Include</a></code> yönergeleri ile
- yapılandırmaya dahil edilen dosyaların içerikleri <code class="directive"><a href="./mod/core.html#include">Include</a></code> yönergesinin bulunduğu yere konulduktan
+
+ <li><code class="directive"><a href="./mod/core.html#include">Include</a></code> yönergeleri ile
+ yapılandırmaya dahil edilen dosyaların içerikleri <code class="directive"><a href="./mod/core.html#include">Include</a></code> yönergesinin bulunduğu yere konulduktan
sonra işleme sokulurlar.</li>
<li><code class="directive"><a href="./mod/core.html#virtualhost"><VirtualHost></a></code>
bölümlerinin içindeki bölümler, sanal konak tanımı dışındaki
- karşılıklarından <em>sonra</em> uygulanırlar. Bu yöntemle ana sunucu
+ karşılıklarından <em>sonra</em> uygulanırlar. Bu yöntemle ana sunucu
yapılandırmasındaki tanımlar geçersiz kılınabilir</li>
<li>İstek <code class="module"><a href="./mod/mod_proxy.html">mod_proxy</a></code> tarafından sunulduğu takdirde,
<code class="directive"><a href="./mod/mod_proxy.html#proxy"><Proxy></a></code> taşıyıcısı
işlem sırasında <code class="directive"><a href="./mod/core.html#directory"><Directory></a></code> taşıyıcısının yerini alır.</li>
+
+ <li>katıştırma düzeni üzerindeki etkisi nedeniyle, ilgili yapılandırma
+ yönergelerini <code class="directive"><a href="./mod/core.html#if"><If></a></code>'in
+ içinde ve dışında karıştırırken dikkatli olunmalıdır. Doğrudan
+ <code class="directive"><a href="./mod/core.html#else"><Else></a></code> kullanımının
+ yardımı olabilir.</li>
+
+ <li><code>.htaccess</code> içinde <code class="directive"><a href="./mod/core.html#if"><If></a></code> kullanıldığında, üst dizindeki sarmalanmış
+ yönergeler, alt dizinde sarmalanmamış yönergelerden <em>sonra</em>
+ birleştirilir.</li>
</ul>
<div class="note"><h3>Bazı Teknik Bilgiler</h3>
@@ -484,35 +495,35 @@ ProxyPass "/" "balancer://mycluster/" stickysession=JSESSIONID|jsessionid nofail
tamamen elden çıkarılır.
</div>
- <h3><a name="relationship-module-configuration" id="relationship-module-configuration">Modüllerle
+ <h3><a name="relationship-module-configuration" id="relationship-module-configuration">Modüllerle
yapılandırma bölümleri arasındaki ilişki</a></h3>
-
- <p>Yapılandırma bölümlerini okurken örneğin <code class="module"><a href="./mod/mod_rewrite.html">mod_rewrite</a></code>
- gibi belli modüllerin yönergelerinin bu bölümlere nasıl katılacağı ve
- ne zaman nasıl işleneceği gibi sorular sıkça aklımızdan geçer. Bunun
- belli bir yanıtı yoktur ve biraz temel bilgi gerektirir. Her httpd
- modülü yapılandırmasını kendi yönetir ve httpd.conf içindeki
- yönergelerinin her biri belli bir bağlamdaki bir yapılandırmayı
+
+ <p>Yapılandırma bölümlerini okurken örneğin <code class="module"><a href="./mod/mod_rewrite.html">mod_rewrite</a></code>
+ gibi belli modüllerin yönergelerinin bu bölümlere nasıl katılacağı ve
+ ne zaman nasıl işleneceği gibi sorular sıkça aklımızdan geçer. Bunun
+ belli bir yanıtı yoktur ve biraz temel bilgi gerektirir. Her httpd
+ modülü yapılandırmasını kendi yönetir ve httpd.conf içindeki
+ yönergelerinin her biri belli bir bağlamdaki bir yapılandırmayı
belirtir. httpd bir komutu okunduğu sırada çalıştırmaz.</p>
-
- <p>Çalışma anında, httpd çekirdeği geçerli isteğe hangilerinin
- uygulanacağını belirlemek için yukarıda açıklanan sırada tanımlı
- yapılandırma bölümlerini tekrar tekrar okur. Eşleşen ilk bölümün bu
- istek için geçerli yapılandırmayı içerdiği varsayılır. Eğer alt
- bölümlerden biri de eşleşmişse bu bölümlerde yönergeleri bulunan her
- modüle yapılandırmasını iki bölüm arasında katıştırma şansı verilir.
- Sonuç üçüncü bir yapılandırma olup işlem bütün yapılandırma bölümleri
+
+ <p>Çalışma anında, httpd çekirdeği geçerli isteğe hangilerinin
+ uygulanacağını belirlemek için yukarıda açıklanan sırada tanımlı
+ yapılandırma bölümlerini tekrar tekrar okur. Eşleşen ilk bölümün bu
+ istek için geçerli yapılandırmayı içerdiği varsayılır. Eğer alt
+ bölümlerden biri de eşleşmişse bu bölümlerde yönergeleri bulunan her
+ modüle yapılandırmasını iki bölüm arasında katıştırma şansı verilir.
+ Sonuç üçüncü bir yapılandırma olup işlem bütün yapılandırma bölümleri
değerlendirilene kadar sürer.</p>
-
- <p>Yukarıdaki adımların ardından HTTP isteğiyle ilgili "asıl" işlem
- başlar: her modül ondan istenen görevleri gerçekleştirme şansına sahip
- olur. Nasıl davranacaklarını belirlemek için kendilerinin katıştırılmış
+
+ <p>Yukarıdaki adımların ardından HTTP isteğiyle ilgili "asıl" işlem
+ başlar: her modül ondan istenen görevleri gerçekleştirme şansına sahip
+ olur. Nasıl davranacaklarını belirlemek için kendilerinin katıştırılmış
son yapılandırmalarını http çekirdeğinden alabilirler.</p>
-
- <p>Sürecin tamamı bir örnekle görselleştirilebilir. Aşağıdaki örnekte
- belli bir HTTP başlığını ayarlamak için <code class="module"><a href="./mod/mod_headers.html">mod_headers</a></code>
- modülünün <code class="directive"><a href="./mod/mod_headers.html#header">Header</a></code> yönergesi
- kullanılmıştır. <code>/example/index.html</code> isteği için httpd
+
+ <p>Sürecin tamamı bir örnekle görselleştirilebilir. Aşağıdaki örnekte
+ belli bir HTTP başlığını ayarlamak için <code class="module"><a href="./mod/mod_headers.html">mod_headers</a></code>
+ modülünün <code class="directive"><a href="./mod/mod_headers.html#header">Header</a></code> yönergesi
+ kullanılmıştır. <code>/example/index.html</code> isteği için httpd
<code>CustomHeaderName</code> başlığına hangi değeri atayacaktır?
</p>
<pre class="prettyprint lang-config"><Directory "/">
@@ -525,37 +536,37 @@ ProxyPass "/" "balancer://mycluster/" stickysession=JSESSIONID|jsessionid nofail
<Directory "/example">
Header set CustomHeaderName iki
</Directory></pre>
-
+
<ul>
- <li><code class="directive">Directory</code> "/" eşleşir ve ilk yapılandırma
- olarak <code>CustomHeaderName</code> başlığı <code>bir</code>
+ <li><code class="directive">Directory</code> "/" eşleşir ve ilk yapılandırma
+ olarak <code>CustomHeaderName</code> başlığı <code>bir</code>
değeriyle oluşturulur.</li>
-
- <li><code class="directive">Directory</code> "/example" eşleşir ve
- <code class="module"><a href="./mod/mod_headers.html">mod_headers</a></code> modülünün koduna göre bir katıştırma
- durumundan yeni değer eskiyi geçersiz kılacağından yeni bir
- yapılandırma ile <code>CustomHeaderName</code> başlığının değeri
+
+ <li><code class="directive">Directory</code> "/example" eşleşir ve
+ <code class="module"><a href="./mod/mod_headers.html">mod_headers</a></code> modülünün koduna göre bir katıştırma
+ durumundan yeni değer eskiyi geçersiz kılacağından yeni bir
+ yapılandırma ile <code>CustomHeaderName</code> başlığının değeri
<code>iki</code> yapılır.</li>
-
- <li><code class="directive">FilesMatch</code> ".*" eşleşir ve başka bir
- katıştırma fırsatı doğar: <code>CustomHeaderName</code> başlığının
+
+ <li><code class="directive">FilesMatch</code> ".*" eşleşir ve başka bir
+ katıştırma fırsatı doğar: <code>CustomHeaderName</code> başlığının
değeri <code>yedi</code> yapılır.</li>
-
- <li>Neticede HHP isteğinin sonraki adımlarında
- <code class="module"><a href="./mod/mod_headers.html">mod_headers</a></code> çağrılıp <code>yedi</code> değeri
- atanmış <code>CustomHeaderName</code> başlığını işleme sokması
- istenecektir. <code class="module"><a href="./mod/mod_headers.html">mod_headers</a></code> normalde işini yapmak
- için bu yapılandırmayı kullanacaktır. Fakat bundan, bir yönergenin
- gerekli olmaması veya kullanımdan kaldırılması ve benzeri nedenlerle
- yapılandırmada iptal edilmesi gibi daha karmaşık bir eylemi bir
+
+ <li>Neticede HHP isteğinin sonraki adımlarında
+ <code class="module"><a href="./mod/mod_headers.html">mod_headers</a></code> çağrılıp <code>yedi</code> değeri
+ atanmış <code>CustomHeaderName</code> başlığını işleme sokması
+ istenecektir. <code class="module"><a href="./mod/mod_headers.html">mod_headers</a></code> normalde işini yapmak
+ için bu yapılandırmayı kullanacaktır. Fakat bundan, bir yönergenin
+ gerekli olmaması veya kullanımdan kaldırılması ve benzeri nedenlerle
+ yapılandırmada iptal edilmesi gibi daha karmaşık bir eylemi bir
modülün gerçekleştiremeyeceği anlamı çıkarılmamalıdır.</li>
</ul>
- <p><code class="directive">Directory</code> ile aynı katıştırma sırasından dolayı
- bu durum .htaccess için de geçerlidir. Burada anlaşılması gereken husus,
- <code class="directive">Directory</code> ve <code class="directive">FilesMatch</code>
- gibi yapılandırma bölümlerinin <code class="directive"><a href="./mod/mod_headers.html#header">Header</a></code> veya <code class="directive"><a href="./mod/mod_rewrite.html#rewriterule">RewriteRule</a></code> gibi modüle özgü
- yönergelerle karşılaştırılmamasıdır, çünkü bunlar farklı seviyelerde
+ <p><code class="directive">Directory</code> ile aynı katıştırma sırasından dolayı
+ bu durum .htaccess için de geçerlidir. Burada anlaşılması gereken husus,
+ <code class="directive">Directory</code> ve <code class="directive">FilesMatch</code>
+ gibi yapılandırma bölümlerinin <code class="directive"><a href="./mod/mod_headers.html#header">Header</a></code> veya <code class="directive"><a href="./mod/mod_rewrite.html#rewriterule">RewriteRule</a></code> gibi modüle özgü
+ yönergelerle karşılaştırılmamasıdır, çünkü bunlar farklı seviyelerde
işlem görür.
</p>
diff --git a/docs/manual/style/version.ent b/docs/manual/style/version.ent
index 29e0dfc7..30ec0ddd 100644
--- a/docs/manual/style/version.ent
+++ b/docs/manual/style/version.ent
@@ -19,6 +19,6 @@
<!ENTITY httpd.major "2">
<!ENTITY httpd.minor "4">
-<!ENTITY httpd.patch "56">
+<!ENTITY httpd.patch "57">
<!ENTITY httpd.docs "2.4">
diff --git a/httpd.spec b/httpd.spec
index c0c788eb..c253895e 100644
--- a/httpd.spec
+++ b/httpd.spec
@@ -4,7 +4,7 @@
Summary: Apache HTTP Server
Name: httpd
-Version: 2.4.56
+Version: 2.4.57
Release: 1
URL: http://httpd.apache.org/
Vendor: Apache Software Foundation
diff --git a/include/ap_mmn.h b/include/ap_mmn.h
index 402c23a3..ace7c43e 100644
--- a/include/ap_mmn.h
+++ b/include/ap_mmn.h
@@ -594,7 +594,7 @@
* 20120211.124 (2.4.51-dev) Add name_ex to struct proxy_worker_shared
* 20120211.125 (2.4.55-dev) Export mod_http2.h as public header
* 20120211.126 (2.4.55-dev) Add additional hcmethod_t enums and PROXY_WORKER_IS_ERROR
- *
+ * 20120211.127 (2.4.56-dev) Add ap_proxy_canonenc_ex
*/
#define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */
@@ -602,7 +602,7 @@
#ifndef MODULE_MAGIC_NUMBER_MAJOR
#define MODULE_MAGIC_NUMBER_MAJOR 20120211
#endif
-#define MODULE_MAGIC_NUMBER_MINOR 126 /* 0...n */
+#define MODULE_MAGIC_NUMBER_MINOR 127 /* 0...n */
/**
* Determine if the server's current MODULE_MAGIC_NUMBER is at least a
diff --git a/include/ap_release.h b/include/ap_release.h
index c858aaea..a5f511ae 100644
--- a/include/ap_release.h
+++ b/include/ap_release.h
@@ -43,7 +43,7 @@
#define AP_SERVER_MAJORVERSION_NUMBER 2
#define AP_SERVER_MINORVERSION_NUMBER 4
-#define AP_SERVER_PATCHLEVEL_NUMBER 56
+#define AP_SERVER_PATCHLEVEL_NUMBER 57
#define AP_SERVER_DEVBUILD_BOOLEAN 0
/* Synchronize the above with docs/manual/style/version.ent */
diff --git a/modules/http/mod_mime.c b/modules/http/mod_mime.c
index 03d1c411..700f824f 100644
--- a/modules/http/mod_mime.c
+++ b/modules/http/mod_mime.c
@@ -755,7 +755,7 @@ static int find_ct(request_rec *r)
mime_dir_config *conf;
apr_array_header_t *exception_list;
char *ext;
- const char *fn, *fntmp, *type, *charset = NULL, *resource_name;
+ const char *fn, *fntmp, *type, *charset = NULL, *resource_name, *qm;
int found_metadata = 0;
if (r->finfo.filetype == APR_DIR) {
@@ -775,6 +775,19 @@ static int find_ct(request_rec *r)
if (conf->use_path_info & 1) {
resource_name = apr_pstrcat(r->pool, r->filename, r->path_info, NULL);
}
+ /*
+ * In the reverse proxy case r->filename might contain a query string if
+ * the nocanon option was used with ProxyPass.
+ * If this is the case cut off the query string as the last parameter in
+ * this query string might end up on an extension we take care about, but
+ * we only want to match against path components not against query
+ * parameters.
+ */
+ else if ((r->proxyreq == PROXYREQ_REVERSE)
+ && (apr_table_get(r->notes, "proxy-nocanon"))
+ && ((qm = ap_strchr_c(r->filename, '?')) != NULL)) {
+ resource_name = apr_pstrmemdup(r->pool, r->filename, qm - r->filename);
+ }
else {
resource_name = r->filename;
}
diff --git a/modules/http2/h2_request.c b/modules/http2/h2_request.c
index bddbad51..20e94cd8 100644
--- a/modules/http2/h2_request.c
+++ b/modules/http2/h2_request.c
@@ -279,7 +279,7 @@ static request_rec *my_ap_create_request(conn_rec *c)
apr_bucket *h2_request_create_bucket(const h2_request *req, request_rec *r)
{
conn_rec *c = r->connection;
- apr_table_t *headers = apr_table_copy(r->pool, req->headers);
+ apr_table_t *headers = apr_table_clone(r->pool, req->headers);
const char *uri = req->path;
AP_DEBUG_ASSERT(req->authority);
@@ -303,7 +303,7 @@ static void assign_headers(request_rec *r, const h2_request *req,
{
const char *cl;
- r->headers_in = apr_table_copy(r->pool, req->headers);
+ r->headers_in = apr_table_clone(r->pool, req->headers);
if (req->authority) {
/* for internal handling, we have to simulate that :authority
* came in as Host:, RFC 9113 ch. says that mismatches between
diff --git a/modules/http2/mod_proxy_http2.c b/modules/http2/mod_proxy_http2.c
index aa299b93..5abccab0 100644
--- a/modules/http2/mod_proxy_http2.c
+++ b/modules/http2/mod_proxy_http2.c
@@ -154,29 +154,41 @@ static int proxy_http2_canon(request_rec *r, char *url)
if (apr_table_get(r->notes, "proxy-nocanon")) {
path = url; /* this is the raw path */
}
- else {
- path = ap_proxy_canonenc(r->pool, url, (int)strlen(url),
- enc_path, 0, r->proxyreq);
+ else if (apr_table_get(r->notes, "proxy-noencode")) {
+ path = url; /* this is the encoded path already */
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()
- "To be forwarded query string contains control "
- "characters or spaces");
- return HTTP_FORBIDDEN;
+ }
+ else {
+ core_dir_config *d = ap_get_core_module_config(r->per_dir_config);
+ int flags = d->allow_encoded_slashes && !d->decode_encoded_slashes ? PROXY_CANONENC_NOENCODEDSLASHENCODING : 0;
+
+ path = ap_proxy_canonenc_ex(r->pool, url, (int)strlen(url),
+ enc_path, flags, r->proxyreq);
+ if (!path) {
+ return HTTP_BAD_REQUEST;
}
+ search = r->args;
}
break;
case PROXYREQ_PROXY:
path = url;
break;
}
-
- if (path == NULL) {
- return HTTP_BAD_REQUEST;
+ /*
+ * If we have a raw control character or a ' ' in nocanon path or
+ * r->args, correct encoding was missed.
+ */
+ if (path == url && *ap_scan_vchar_obstext(path)) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10420)
+ "To be forwarded path contains control "
+ "characters or spaces");
+ return HTTP_FORBIDDEN;
+ }
+ if (search && *ap_scan_vchar_obstext(search)) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10412)
+ "To be forwarded query string contains control "
+ "characters or spaces");
+ return HTTP_FORBIDDEN;
}
if (port != def_port) {
diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c
index 5195ceee..f93f23f0 100644
--- a/modules/mappers/mod_rewrite.c
+++ b/modules/mappers/mod_rewrite.c
@@ -106,6 +106,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";
@@ -174,6 +176,7 @@ static const char* really_last_key = "rewrite_really_last";
#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
@@ -327,7 +330,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 {
@@ -427,7 +431,9 @@ static apr_global_mutex_t *rewrite_mapr_lock_acquire = NULL;
static const char *rewritemap_mutex_type = "rewrite-map";
/* Optional functions imported from mod_ssl when loaded: */
-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);
/*
* +-------------------------------------------------------+
@@ -654,14 +660,21 @@ static APR_INLINE unsigned char *c2x(unsigned what, unsigned char prefix,
* 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;
}
@@ -672,23 +685,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;
}
@@ -2469,7 +2467,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));
@@ -3541,13 +3540,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;
}
@@ -3809,7 +3819,6 @@ static const char *cmd_rewriterule(cmd_parms *cmd, void *in_dconf,
"'", NULL);
}
- /* arg3: optional flags field */
newrule->forced_mimetype = NULL;
newrule->forced_handler = NULL;
newrule->forced_responsecode = HTTP_MOVED_TEMPORARILY;
@@ -3818,6 +3827,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) {
@@ -3854,6 +3866,7 @@ static const char *cmd_rewriterule(cmd_parms *cmd, void *in_dconf,
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, '?')) {
@@ -4745,13 +4758,19 @@ static int hook_uri2file(request_rec *r)
}
if (rulestatus) {
- unsigned skip;
- apr_size_t flen;
-
- if (r->args && *(ap_scan_vchar_obstext(r->args))) {
+ 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 "
@@ -4766,8 +4785,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
@@ -4809,7 +4827,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 */
@@ -4817,7 +4835,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 */
@@ -5041,9 +5059,17 @@ 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;
- if (r->args && *(ap_scan_vchar_obstext(r->args))) {
+ 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.
@@ -5061,8 +5087,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
@@ -5086,7 +5111,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
@@ -5095,7 +5120,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,
@@ -5140,7 +5165,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.c b/modules/proxy/mod_proxy.c
index 9225bc9b..537c3c25 100644
--- a/modules/proxy/mod_proxy.c
+++ b/modules/proxy/mod_proxy.c
@@ -963,6 +963,8 @@ PROXY_DECLARE(int) ap_proxy_trans_match(request_rec *r, struct proxy_alias *ent,
}
if (found) {
+ unsigned int encoded = ent->flags & PROXYPASS_MAP_ENCODED;
+
/* A proxy module is assigned this URL, check whether it's interested
* in the request itself (e.g. proxy_wstunnel cares about Upgrade
* requests only, and could hand over to proxy_http otherwise).
@@ -982,6 +984,9 @@ PROXY_DECLARE(int) ap_proxy_trans_match(request_rec *r, struct proxy_alias *ent,
if (ent->flags & PROXYPASS_NOQUERY) {
apr_table_setn(r->notes, "proxy-noquery", "1");
}
+ if (encoded) {
+ apr_table_setn(r->notes, "proxy-noencode", "1");
+ }
if (servlet_uri) {
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(10248)
@@ -995,13 +1000,13 @@ PROXY_DECLARE(int) ap_proxy_trans_match(request_rec *r, struct proxy_alias *ent,
*/
AP_DEBUG_ASSERT(strlen(r->uri) >= strlen(servlet_uri));
strcpy(r->uri, servlet_uri);
- return DONE;
}
-
- ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(03464)
- "URI path '%s' matches proxy handler '%s'", r->uri,
- found);
- return OK;
+ else {
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(03464)
+ "URI path '%s' matches proxy handler '%s'", r->uri,
+ found);
+ }
+ return (encoded) ? DONE : OK;
}
return HTTP_CONTINUE;
diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h
index 5c08e99c..c51145e0 100644
--- a/modules/proxy/mod_proxy.h
+++ b/modules/proxy/mod_proxy.h
@@ -76,6 +76,10 @@ enum enctype {
enc_path, enc_search, enc_user, enc_fpath, enc_parm
};
+/* Flags for ap_proxy_canonenc_ex */
+#define PROXY_CANONENC_FORCEDEC 0x01
+#define PROXY_CANONENC_NOENCODEDSLASHENCODING 0x02
+
typedef enum {
NONE, TCP, OPTIONS, HEAD, GET, CPING, PROVIDER, OPTIONS11, HEAD11, GET11, EOT
} hcmethod_t;
@@ -676,6 +680,8 @@ PROXY_DECLARE(apr_status_t) ap_proxy_strncpy(char *dst, const char *src,
apr_size_t dlen);
PROXY_DECLARE(int) ap_proxy_hex2c(const char *x);
PROXY_DECLARE(void) ap_proxy_c2hex(int ch, char *x);
+PROXY_DECLARE(char *)ap_proxy_canonenc_ex(apr_pool_t *p, const char *x, int len, enum enctype t,
+ int flags, int proxyreq);
PROXY_DECLARE(char *)ap_proxy_canonenc(apr_pool_t *p, const char *x, int len, enum enctype t,
int forcedec, int proxyreq);
PROXY_DECLARE(char *)ap_proxy_canon_netloc(apr_pool_t *p, char **const urlp, char **userp,
diff --git a/modules/proxy/mod_proxy_ajp.c b/modules/proxy/mod_proxy_ajp.c
index e46bd903..65773ce7 100644
--- a/modules/proxy/mod_proxy_ajp.c
+++ b/modules/proxy/mod_proxy_ajp.c
@@ -65,23 +65,37 @@ static int proxy_ajp_canon(request_rec *r, char *url)
if (apr_table_get(r->notes, "proxy-nocanon")) {
path = url; /* this is the raw path */
}
- else {
- path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0,
- r->proxyreq);
+ else if (apr_table_get(r->notes, "proxy-noencode")) {
+ path = url; /* this is the encoded path already */
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;
+ }
+ else {
+ core_dir_config *d = ap_get_core_module_config(r->per_dir_config);
+ int flags = d->allow_encoded_slashes && !d->decode_encoded_slashes ? PROXY_CANONENC_NOENCODEDSLASHENCODING : 0;
+
+ path = ap_proxy_canonenc_ex(r->pool, url, strlen(url), enc_path, flags,
+ r->proxyreq);
+ if (!path) {
+ return HTTP_BAD_REQUEST;
}
+ search = r->args;
+ }
+ /*
+ * If we have a raw control character or a ' ' in nocanon path or
+ * r->args, correct encoding was missed.
+ */
+ if (path == url && *ap_scan_vchar_obstext(path)) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10418)
+ "To be forwarded path contains control "
+ "characters or spaces");
+ return HTTP_FORBIDDEN;
+ }
+ if (search && *ap_scan_vchar_obstext(search)) {
+ 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;
if (port != def_port)
apr_snprintf(sport, sizeof(sport), ":%d", port);
diff --git a/modules/proxy/mod_proxy_balancer.c b/modules/proxy/mod_proxy_balancer.c
index 7f990084..b8b452d0 100644
--- a/modules/proxy/mod_proxy_balancer.c
+++ b/modules/proxy/mod_proxy_balancer.c
@@ -102,23 +102,37 @@ static int proxy_balancer_canon(request_rec *r, char *url)
if (apr_table_get(r->notes, "proxy-nocanon")) {
path = url; /* this is the raw path */
}
- else {
- path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0,
- r->proxyreq);
+ else if (apr_table_get(r->notes, "proxy-noencode")) {
+ path = url; /* this is the encoded path already */
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;
+ }
+ else {
+ core_dir_config *d = ap_get_core_module_config(r->per_dir_config);
+ int flags = d->allow_encoded_slashes && !d->decode_encoded_slashes ? PROXY_CANONENC_NOENCODEDSLASHENCODING : 0;
+
+ path = ap_proxy_canonenc_ex(r->pool, url, strlen(url), enc_path, flags,
+ r->proxyreq);
+ if (!path) {
+ return HTTP_BAD_REQUEST;
}
+ search = r->args;
+ }
+ /*
+ * If we have a raw control character or a ' ' in nocanon path or
+ * r->args, correct encoding was missed.
+ */
+ if (path == url && *ap_scan_vchar_obstext(path)) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10416)
+ "To be forwarded path contains control "
+ "characters or spaces");
+ return HTTP_FORBIDDEN;
+ }
+ if (search && *ap_scan_vchar_obstext(search)) {
+ 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;
r->filename = apr_pstrcat(r->pool, "proxy:" BALANCER_PREFIX, host,
"/", path, (search) ? "?" : "", (search) ? search : "", NULL);
diff --git a/modules/proxy/mod_proxy_fcgi.c b/modules/proxy/mod_proxy_fcgi.c
index 3382b9bf..831bd15a 100644
--- a/modules/proxy/mod_proxy_fcgi.c
+++ b/modules/proxy/mod_proxy_fcgi.c
@@ -92,15 +92,30 @@ static int proxy_fcgi_canon(request_rec *r, char *url)
host = apr_pstrcat(r->pool, "[", host, "]", NULL);
}
- if (apr_table_get(r->notes, "proxy-nocanon")) {
- path = url; /* this is the raw path */
+ if (apr_table_get(r->notes, "proxy-nocanon")
+ || apr_table_get(r->notes, "proxy-noencode")) {
+ path = url; /* this is the raw/encoded path */
}
else {
- path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0,
- r->proxyreq);
+ core_dir_config *d = ap_get_core_module_config(r->per_dir_config);
+ int flags = d->allow_encoded_slashes && !d->decode_encoded_slashes ? PROXY_CANONENC_NOENCODEDSLASHENCODING : 0;
+
+ path = ap_proxy_canonenc_ex(r->pool, url, strlen(url), enc_path, flags,
+ r->proxyreq);
+ if (!path) {
+ return HTTP_BAD_REQUEST;
+ }
+ }
+ /*
+ * If we have a raw control character or a ' ' in nocanon path,
+ * correct encoding was missed.
+ */
+ if (path == url && *ap_scan_vchar_obstext(path)) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10414)
+ "To be forwarded path contains control "
+ "characters or spaces");
+ return HTTP_FORBIDDEN;
}
- if (path == NULL)
- return HTTP_BAD_REQUEST;
r->filename = apr_pstrcat(r->pool, "proxy:fcgi://", host, sport, "/",
path, NULL);
diff --git a/modules/proxy/mod_proxy_ftp.c b/modules/proxy/mod_proxy_ftp.c
index 3237a2ba..a3fb10a9 100644
--- a/modules/proxy/mod_proxy_ftp.c
+++ b/modules/proxy/mod_proxy_ftp.c
@@ -289,6 +289,8 @@ static int proxy_ftp_canon(request_rec *r, char *url)
apr_pool_t *p = r->pool;
const char *err;
apr_port_t port, def_port;
+ core_dir_config *d = ap_get_core_module_config(r->per_dir_config);
+ int flags = d->allow_encoded_slashes && !d->decode_encoded_slashes ? PROXY_CANONENC_NOENCODEDSLASHENCODING : 0;
/* */
if (ap_cstr_casecmpn(url, "ftp:", 4) == 0) {
@@ -327,7 +329,8 @@ static int proxy_ftp_canon(request_rec *r, char *url)
else
parms = "";
- path = ap_proxy_canonenc(p, url, strlen(url), enc_path, 0, r->proxyreq);
+ path = ap_proxy_canonenc_ex(p, url, strlen(url), enc_path, flags,
+ r->proxyreq);
if (path == NULL)
return HTTP_BAD_REQUEST;
if (!ftp_check_string(path))
diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c
index 51d19a0a..1842c49e 100644
--- a/modules/proxy/mod_proxy_http.c
+++ b/modules/proxy/mod_proxy_http.c
@@ -121,29 +121,42 @@ static int proxy_http_canon(request_rec *r, char *url)
if (apr_table_get(r->notes, "proxy-nocanon")) {
path = url; /* this is the raw path */
}
- else {
- path = ap_proxy_canonenc(r->pool, url, strlen(url),
- enc_path, 0, r->proxyreq);
+ else if (apr_table_get(r->notes, "proxy-noencode")) {
+ path = url; /* this is the encoded path already */
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;
+ }
+ else {
+ core_dir_config *d = ap_get_core_module_config(r->per_dir_config);
+ int flags = d->allow_encoded_slashes && !d->decode_encoded_slashes ? PROXY_CANONENC_NOENCODEDSLASHENCODING : 0;
+
+ path = ap_proxy_canonenc_ex(r->pool, url, strlen(url), enc_path,
+ flags, r->proxyreq);
+ if (!path) {
+ return HTTP_BAD_REQUEST;
}
+ search = r->args;
}
break;
case PROXYREQ_PROXY:
path = url;
break;
}
-
- if (path == NULL)
- return HTTP_BAD_REQUEST;
+ /*
+ * If we have a raw control character or a ' ' in nocanon path or
+ * r->args, correct encoding was missed.
+ */
+ if (path == url && *ap_scan_vchar_obstext(path)) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10415)
+ "To be forwarded path contains control "
+ "characters or spaces");
+ return HTTP_FORBIDDEN;
+ }
+ if (search && *ap_scan_vchar_obstext(search)) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10408)
+ "To be forwarded query string contains control "
+ "characters or spaces");
+ return HTTP_FORBIDDEN;
+ }
if (port != def_port)
apr_snprintf(sport, sizeof(sport), ":%d", port);
diff --git a/modules/proxy/mod_proxy_scgi.c b/modules/proxy/mod_proxy_scgi.c
index 493757d3..5444a5c4 100644
--- a/modules/proxy/mod_proxy_scgi.c
+++ b/modules/proxy/mod_proxy_scgi.c
@@ -179,6 +179,8 @@ static int scgi_canon(request_rec *r, char *url)
char *host, sport[sizeof(":65535")];
const char *err, *path;
apr_port_t port, def_port;
+ core_dir_config *d = ap_get_core_module_config(r->per_dir_config);
+ int flags = d->allow_encoded_slashes && !d->decode_encoded_slashes ? PROXY_CANONENC_NOENCODEDSLASHENCODING : 0;
if (ap_cstr_casecmpn(url, SCHEME "://", sizeof(SCHEME) + 2)) {
return DECLINED;
@@ -205,8 +207,8 @@ static int scgi_canon(request_rec *r, char *url)
host = apr_pstrcat(r->pool, "[", host, "]", NULL);
}
- path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0,
- r->proxyreq);
+ path = ap_proxy_canonenc_ex(r->pool, url, strlen(url), enc_path, flags,
+ r->proxyreq);
if (!path) {
return HTTP_BAD_REQUEST;
}
diff --git a/modules/proxy/mod_proxy_uwsgi.c b/modules/proxy/mod_proxy_uwsgi.c
index 92e153cc..fd76c955 100644
--- a/modules/proxy/mod_proxy_uwsgi.c
+++ b/modules/proxy/mod_proxy_uwsgi.c
@@ -84,10 +84,29 @@ static int uwsgi_canon(request_rec *r, char *url)
host = apr_pstrcat(r->pool, "[", host, "]", NULL);
}
- path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0,
- r->proxyreq);
- if (!path) {
- return HTTP_BAD_REQUEST;
+ if (apr_table_get(r->notes, "proxy-nocanon")
+ || apr_table_get(r->notes, "proxy-noencode")) {
+ path = url; /* this is the raw/encoded path */
+ }
+ else {
+ core_dir_config *d = ap_get_core_module_config(r->per_dir_config);
+ int flags = d->allow_encoded_slashes && !d->decode_encoded_slashes ? PROXY_CANONENC_NOENCODEDSLASHENCODING : 0;
+
+ path = ap_proxy_canonenc_ex(r->pool, url, strlen(url), enc_path, flags,
+ r->proxyreq);
+ if (!path) {
+ return HTTP_BAD_REQUEST;
+ }
+ }
+ /*
+ * If we have a raw control character or a ' ' in nocanon path,
+ * correct encoding was missed.
+ */
+ if (path == url && *ap_scan_vchar_obstext(path)) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10417)
+ "To be forwarded path contains control "
+ "characters or spaces");
+ return HTTP_FORBIDDEN;
}
r->filename =
diff --git a/modules/proxy/mod_proxy_wstunnel.c b/modules/proxy/mod_proxy_wstunnel.c
index 88f86a49..30ba1b49 100644
--- a/modules/proxy/mod_proxy_wstunnel.c
+++ b/modules/proxy/mod_proxy_wstunnel.c
@@ -110,23 +110,37 @@ static int proxy_wstunnel_canon(request_rec *r, char *url)
if (apr_table_get(r->notes, "proxy-nocanon")) {
path = url; /* this is the raw path */
}
- else {
- path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0,
- r->proxyreq);
+ else if (apr_table_get(r->notes, "proxy-noencode")) {
+ path = url; /* this is the encoded path already */
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;
+ }
+ else {
+ core_dir_config *d = ap_get_core_module_config(r->per_dir_config);
+ int flags = d->allow_encoded_slashes && !d->decode_encoded_slashes ? PROXY_CANONENC_NOENCODEDSLASHENCODING : 0;
+
+ path = ap_proxy_canonenc_ex(r->pool, url, strlen(url), enc_path, flags,
+ r->proxyreq);
+ if (!path) {
+ return HTTP_BAD_REQUEST;
}
+ search = r->args;
+ }
+ /*
+ * If we have a raw control character or a ' ' in nocanon path or
+ * r->args, correct encoding was missed.
+ */
+ if (path == url && *ap_scan_vchar_obstext(path)) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10419)
+ "To be forwarded path contains control "
+ "characters or spaces");
+ return HTTP_FORBIDDEN;
+ }
+ if (search && *ap_scan_vchar_obstext(search)) {
+ 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;
if (port != def_port)
apr_snprintf(sport, sizeof(sport), ":%d", port);
diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c
index 8267f1b9..caafde0b 100644
--- a/modules/proxy/proxy_util.c
+++ b/modules/proxy/proxy_util.c
@@ -200,14 +200,16 @@ PROXY_DECLARE(void) ap_proxy_c2hex(int ch, char *x)
* and encodes those which must be encoded, and does not touch
* those which must not be touched.
*/
-PROXY_DECLARE(char *)ap_proxy_canonenc(apr_pool_t *p, const char *x, int len,
- enum enctype t, int forcedec,
- int proxyreq)
+PROXY_DECLARE(char *)ap_proxy_canonenc_ex(apr_pool_t *p, const char *x, int len,
+ enum enctype t, int flags,
+ int proxyreq)
{
int i, j, ch;
char *y;
char *allowed; /* characters which should not be encoded */
char *reserved; /* characters which much not be en/de-coded */
+ int forcedec = flags & PROXY_CANONENC_FORCEDEC;
+ int noencslashesenc = flags & PROXY_CANONENC_NOENCODEDSLASHENCODING;
/*
* N.B. in addition to :@&=, this allows ';' in an http path
@@ -256,17 +258,29 @@ PROXY_DECLARE(char *)ap_proxy_canonenc(apr_pool_t *p, const char *x, int len,
* decode it if not already done. do not decode reverse proxied URLs
* unless specifically forced
*/
- if ((forcedec || (proxyreq && proxyreq != PROXYREQ_REVERSE)) && ch == '%') {
+ if ((forcedec || noencslashesenc
+ || (proxyreq && proxyreq != PROXYREQ_REVERSE)) && ch == '%') {
if (!apr_isxdigit(x[i + 1]) || !apr_isxdigit(x[i + 2])) {
return NULL;
}
ch = ap_proxy_hex2c(&x[i + 1]);
- i += 2;
if (ch != 0 && strchr(reserved, ch)) { /* keep it encoded */
- ap_proxy_c2hex(ch, &y[j]);
- j += 2;
+ y[j++] = x[i++];
+ y[j++] = x[i++];
+ y[j] = x[i];
continue;
}
+ if (noencslashesenc && !forcedec && (proxyreq == PROXYREQ_REVERSE)) {
+ /*
+ * In the reverse proxy case when we only want to keep encoded
+ * slashes untouched revert back to '%' which will cause
+ * '%' to be encoded in the following.
+ */
+ ch = '%';
+ }
+ else {
+ i += 2;
+ }
}
/* recode it, if necessary */
if (!apr_isalnum(ch) && !strchr(allowed, ch)) {
@@ -281,6 +295,22 @@ PROXY_DECLARE(char *)ap_proxy_canonenc(apr_pool_t *p, const char *x, int len,
return y;
}
+/*
+ * Convert a URL-encoded string to canonical form.
+ * It decodes characters which need not be encoded,
+ * and encodes those which must be encoded, and does not touch
+ * those which must not be touched.
+ */
+PROXY_DECLARE(char *)ap_proxy_canonenc(apr_pool_t *p, const char *x, int len,
+ enum enctype t, int forcedec,
+ int proxyreq)
+{
+ int flags;
+
+ flags = forcedec ? PROXY_CANONENC_FORCEDEC : 0;
+ return ap_proxy_canonenc_ex(p, x, len, t, flags, proxyreq);
+}
+
/*
* Parses network-location.
* urlp on input the URL; on output the path, after the leading /
diff --git a/test/README.pytest b/test/README.pytest
index 5949e12b..474030bd 100644
--- a/test/README.pytest
+++ b/test/README.pytest
@@ -72,7 +72,7 @@ Development
-----------
Adding a test in an existing file is done by adding a method. Its name
-must start with 'test_' and the common practise is to have the name
+must start with 'test_' and the common practice is to have the name
of the test suite there as well. All http2 tests start with 'test_h2_'.
Following this can be any characters. If you make test cases of a
diff --git a/test/modules/http2/test_004_post.py b/test/modules/http2/test_004_post.py
index 97f05e25..44f31d2c 100644
--- a/test/modules/http2/test_004_post.py
+++ b/test/modules/http2/test_004_post.py
@@ -5,6 +5,7 @@ import json
import os
import re
import sys
+import time
import pytest
@@ -173,6 +174,8 @@ CustomLog logs/test_004_30 issue_203
r = env.curl_get(url, 5, options=["--http2", "-H", "Range: bytes=0-{0}".format(chunk-1)])
assert 206 == r.response["status"]
assert chunk == len(r.response["body"].decode('utf-8'))
+ # Wait for log completeness
+ time.sleep(1)
# now check what response lengths have actually been reported
lines = open(logfile).readlines()
log_h2_full = json.loads(lines[-3])
diff --git a/test/modules/http2/test_600_h2proxy.py b/test/modules/http2/test_600_h2proxy.py
index 9591ce57..e93ba1ae 100644
--- a/test/modules/http2/test_600_h2proxy.py
+++ b/test/modules/http2/test_600_h2proxy.py
@@ -78,24 +78,30 @@ class TestH2Proxy:
conf.install()
assert env.apache_restart() == 0
url = env.mkurl("https", "cgi", f"/h2proxy/{env.http_port}/hello.py")
- r = env.curl_get(url, 5)
- assert r.response["status"] == 200
- assert r.json["h2_stream_id"] == "1"
if enable_reuse == "on":
- # reuse is not guarantueed for each request, but we expect some
+ # reuse is not guaranteed for each request, but we expect some
# to do it and run on a h2 stream id > 1
reused = False
- for _ in range(10):
- r = env.curl_get(url, 5)
- assert r.response["status"] == 200
- if int(r.json["h2_stream_id"]) > 1:
+ count = 10
+ r = env.curl_raw([url] * count, 5)
+ response = r.response
+ for n in range(count):
+ assert response["status"] == 200
+ if n == (count - 1):
+ break
+ response = response["previous"]
+ assert r.json[0]["h2_stream_id"] == "1"
+ for n in range(1, count):
+ if int(r.json[n]["h2_stream_id"]) > 1:
reused = True
break
assert reused
else:
- r = env.curl_get(url, 5)
+ r = env.curl_raw([url, url], 5)
+ assert r.response["previous"]["status"] == 200
assert r.response["status"] == 200
- assert r.json["h2_stream_id"] == "1"
+ assert r.json[0]["h2_stream_id"] == "1"
+ assert r.json[1]["h2_stream_id"] == "1"
# do some flexible setup from #235 to proper connection selection
@pytest.mark.parametrize("enable_reuse", [ "on", "off" ])
@@ -119,16 +125,13 @@ class TestH2Proxy:
conf.install()
assert env.apache_restart() == 0
url = env.mkurl("https", "cgi", f"/h2proxy/{env.http_port}/hello.py")
- r = env.curl_get(url, 5)
- assert r.response["status"] == 200
- assert int(r.json["port"]) == env.http_port
- # going to another backend port must create a new connection and
- # we should see stream id one again
- url = env.mkurl("https", "cgi", f"/h2proxy/{env.http_port2}/hello.py")
- r = env.curl_get(url, 5)
+ url2 = env.mkurl("https", "cgi", f"/h2proxy/{env.http_port2}/hello.py")
+ r = env.curl_raw([url, url2], 5)
+ assert r.response["previous"]["status"] == 200
+ assert int(r.json[0]["port"]) == env.http_port
assert r.response["status"] == 200
exp_port = env.http_port if enable_reuse == "on" else env.http_port2
- assert int(r.json["port"]) == exp_port
+ assert int(r.json[1]["port"]) == exp_port
# lets do some error tests
def test_h2_600_30(self, env):
diff --git a/test/pyhttpd/curl.py b/test/pyhttpd/curl.py
index 338e82ce..2b6840b1 100644
--- a/test/pyhttpd/curl.py
+++ b/test/pyhttpd/curl.py
@@ -32,7 +32,7 @@ class CurlPiper:
return self._r.response if self._r else None
def start(self):
- self.args, self.headerfile = self.env.curl_complete_args(self.url, timeout=5, options=[
+ self.args, self.headerfile = self.env.curl_complete_args([self.url], timeout=5, options=[
"-T", "-", "-X", "POST", "--trace-ascii", "%", "--trace-time"])
sys.stderr.write("starting: {0}\n".format(self.args))
self.proc = subprocess.Popen(self.args, stdin=subprocess.PIPE,
diff --git a/test/pyhttpd/env.py b/test/pyhttpd/env.py
index af856eff..2c918593 100644
--- a/test/pyhttpd/env.py
+++ b/test/pyhttpd/env.py
@@ -65,6 +65,8 @@ class HttpdTestSetup:
"proxy_http",
]
+ CURL_STDOUT_SEPARATOR = "===CURL_STDOUT_SEPARATOR==="
+
def __init__(self, env: 'HttpdTestEnv'):
self.env = env
self._source_dirs = [os.path.dirname(inspect.getfile(HttpdTestSetup))]
@@ -497,14 +499,26 @@ class HttpdTestEnv:
if not os.path.exists(path):
return os.makedirs(path)
- def run(self, args, intext=None, debug_log=True):
+ def run(self, args, stdout_list=False, intext=None, debug_log=True):
if debug_log:
log.debug(f"run: {args}")
start = datetime.now()
p = subprocess.run(args, stderr=subprocess.PIPE, stdout=subprocess.PIPE,
input=intext.encode() if intext else None)
+ stdout_as_list = None
+ if stdout_list:
+ try:
+ out = p.stdout.decode()
+ if HttpdTestSetup.CURL_STDOUT_SEPARATOR in out:
+ stdout_as_list = out.split(HttpdTestSetup.CURL_STDOUT_SEPARATOR)
+ if not stdout_as_list[len(stdout_as_list) - 1]:
+ stdout_as_list.pop()
+ p.stdout.replace(HttpdTestSetup.CURL_STDOUT_SEPARATOR.encode(), b'')
+ except:
+ pass
return ExecResult(args=args, exit_code=p.returncode,
stdout=p.stdout, stderr=p.stderr,
+ stdout_as_list=stdout_as_list,
duration=datetime.now() - start)
def mkurl(self, scheme, hostname, path='/'):
@@ -637,10 +651,9 @@ class HttpdTestEnv:
os.remove(os.path.join(self.gen_dir, fname))
self._curl_headerfiles_n = 0
- def curl_complete_args(self, urls, timeout=None, options=None,
+ def curl_complete_args(self, urls, stdout_list=False,
+ timeout=None, options=None,
insecure=False, force_resolve=True):
- if not isinstance(urls, list):
- urls = [urls]
u = urlparse(urls[0])
#assert u.hostname, f"hostname not in url: {urls[0]}"
headerfile = f"{self.gen_dir}/curl.headers.{self._curl_headerfiles_n}"
@@ -649,6 +662,8 @@ class HttpdTestEnv:
args = [
self._curl, "-s", "--path-as-is", "-D", headerfile,
]
+ if stdout_list:
+ args.extend(['-w', '%{stdout}' + HttpdTestSetup.CURL_STDOUT_SEPARATOR])
if u.scheme == 'http':
pass
elif insecure:
@@ -731,10 +746,16 @@ class HttpdTestEnv:
def curl_raw(self, urls, timeout=10, options=None, insecure=False,
force_resolve=True):
+ if not isinstance(urls, list):
+ urls = [urls]
+ stdout_list = False
+ if len(urls) > 1:
+ stdout_list = True
args, headerfile = self.curl_complete_args(
- urls=urls, timeout=timeout, options=options, insecure=insecure,
+ urls=urls, stdout_list=stdout_list,
+ timeout=timeout, options=options, insecure=insecure,
force_resolve=force_resolve)
- r = self.run(args)
+ r = self.run(args, stdout_list=stdout_list)
if r.exit_code == 0:
self.curl_parse_headerfile(headerfile, r=r)
if r.json:
diff --git a/test/pyhttpd/nghttp.py b/test/pyhttpd/nghttp.py
index fe4a1aed..f27e40d3 100644
--- a/test/pyhttpd/nghttp.py
+++ b/test/pyhttpd/nghttp.py
@@ -251,7 +251,9 @@ class Nghttp:
f.write("--DSAJKcd9876\n")
if not options:
options = []
- options.extend(["--data=%s" % reqbody])
+ options.extend([
+ "--data=%s" % reqbody,
+ "-HContent-Type: multipart/form-data; boundary=DSAJKcd9876"])
return self._raw(url, timeout, options)
def upload(self, url, fpath, timeout=5, options=None):
diff --git a/test/pyhttpd/result.py b/test/pyhttpd/result.py
index 04ea825a..3789461b 100644
--- a/test/pyhttpd/result.py
+++ b/test/pyhttpd/result.py
@@ -6,7 +6,9 @@ from typing import Optional, Dict, List
class ExecResult:
def __init__(self, args: List[str], exit_code: int,
- stdout: bytes, stderr: bytes = None, duration: timedelta = None):
+ stdout: bytes, stderr: bytes = None,
+ stdout_as_list: List[bytes] = None,
+ duration: timedelta = None):
self._args = args
self._exit_code = exit_code
self._stdout = stdout if stdout is not None else b''
@@ -17,7 +19,10 @@ class ExecResult:
self._assets = []
# noinspection PyBroadException
try:
- out = self._stdout.decode()
+ if stdout_as_list is None:
+ out = self._stdout.decode()
+ else:
+ out = "[" + ','.join(stdout_as_list) + "]"
self._json_out = json.loads(out)
except:
self._json_out = None
diff --git a/test/travis_run_linux.sh b/test/travis_run_linux.sh
index 58370700..f7a72d29 100755
--- a/test/travis_run_linux.sh
+++ b/test/travis_run_linux.sh
@@ -122,8 +122,23 @@ if ! test -v SKIP_TESTING; then
test -v TEST_INSTALL || make install
pushd test/perl-framework
perl Makefile.PL -apxs $PREFIX/bin/apxs
- make test APACHE_TEST_EXTRA_ARGS="${TEST_ARGS} ${TESTS}"
- RV=$?
+ make test APACHE_TEST_EXTRA_ARGS="${TEST_ARGS} ${TESTS}" | tee test.log
+ RV=${PIPESTATUS[0]}
+ # re-run failing tests with -v, avoiding set -e
+ if [ $RV -ne 0 ]; then
+ #mv t/logs/error_log t/logs/error_log_save
+ FAILERS=""
+ while read FAILER; do
+ FAILERS="$FAILERS $FAILER"
+ done < <(awk '/Failed:/{print $1}' test.log)
+ if [ -n "$FAILERS" ]; then
+ t/TEST -v $FAILERS || true
+ fi
+ # set -e would have killed us after the original t/TEST
+ rm -f test.log
+ #mv t/logs/error_log_save t/logs/error_log
+ false
+ fi
popd
fi
Reply to: