summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndré Malo <nd@apache.org>2005-09-24 11:22:21 +0000
committerAndré Malo <nd@apache.org>2005-09-24 11:22:21 +0000
commitbb509ec65c14af04b9b62b3ca34a000c24f3a99e (patch)
treecdaea405ee9f4bd4d3b6fd5bacd5584c565ae586
parent0eca20652f9990c781775ef9dfef3ed3e67aaf49 (diff)
downloadhttpd-bb509ec65c14af04b9b62b3ca34a000c24f3a99e.tar.gz
mod_version_for_2.0.x branch:
* Merge 290201 to 291277 from branches/2.0.x git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/mod_version_for_2.0.x@291280 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--CHANGES23
-rw-r--r--STATUS152
-rw-r--r--docs/manual/mod/core.html.de34
-rw-r--r--docs/manual/mod/core.html.en30
-rw-r--r--docs/manual/mod/core.xml28
-rw-r--r--docs/manual/mod/core.xml.de37
-rw-r--r--docs/manual/mod/core.xml.es2
-rw-r--r--docs/manual/mod/core.xml.ja2
-rw-r--r--docs/manual/mod/directives.html.de1
-rw-r--r--docs/manual/mod/directives.html.en1
-rw-r--r--docs/manual/mod/directives.html.ko.euc-kr1
-rw-r--r--docs/manual/mod/directives.html.ru.koi8-r1
-rw-r--r--docs/manual/mod/mod_dumpio.xml2
-rw-r--r--docs/manual/mod/quickreference.html.de4
-rw-r--r--docs/manual/mod/quickreference.html.en4
-rw-r--r--docs/manual/mod/quickreference.html.ko.euc-kr4
-rw-r--r--docs/manual/mod/quickreference.html.ru.koi8-r4
-rw-r--r--docs/manual/programs/htdbm.xml2
-rw-r--r--docs/manual/rewrite/rewrite_guide.xml2
-rw-r--r--docs/manual/rewrite/rewrite_guide_advanced.xml2
-rw-r--r--include/ap_mmn.h7
-rw-r--r--include/http_core.h8
-rw-r--r--modules/arch/netware/mod_netware.c12
-rw-r--r--modules/experimental/util_ldap.c6
-rw-r--r--modules/experimental/util_ldap_cache.c24
-rw-r--r--modules/experimental/util_ldap_cache.h1
-rw-r--r--modules/generators/mod_cgi.c4
-rw-r--r--modules/generators/mod_cgi.h6
-rw-r--r--modules/http/http_protocol.c93
-rw-r--r--modules/proxy/mod_proxy.c36
-rw-r--r--modules/proxy/proxy_http.c768
-rw-r--r--server/core.c32
-rw-r--r--srclib/pcre/pcre.c29
33 files changed, 844 insertions, 518 deletions
diff --git a/CHANGES b/CHANGES
index 22d2b8ddf1..fd1c6c854c 100644
--- a/CHANGES
+++ b/CHANGES
@@ -8,6 +8,29 @@ Changes with Apache 2.0.55
accompanying ap_version_t structure (minor MMN bump).
[André Malo]
+ *) mod_ldap: Fix PR 36563. Keep track of the number of attributes
+ retrieved from LDAP so that all of the values can be properly
+ cached even if the value is NULL.
+ [Brad Nicholes, Ondrej Sury <ondrej sury.org>]
+
+ *) SECURITY: CAN-2005-2491 (cve.mitre.org):
+ Fix integer overflows in PCRE in quantifier parsing which could
+ be triggered by a local user through use of a carefully-crafted
+ regex in an .htaccess file. [Philip Hazel]
+
+ *) SECURITY: CAN-2005-2088 (cve.mitre.org)
+ proxy: Correctly handle the Transfer-Encoding and Content-Length
+ headers. Discard the request Content-Length whenever T-E: chunked
+ is used, always passing one of either C-L or T-E: chunked whenever
+ the request includes a request body. Resolves an entire class of
+ proxy HTTP Request Splitting/Spoofing attacks. [William Rowe]
+
+ *) Added TraceEnable [on|off|extended] per-server directive to alter
+ the behavior of the TRACE method. This addresses a flaw in proxy
+ conformance to RFC 2616 - previously the proxy server would accept
+ a TRACE request body although the RFC prohibited it. The default
+ remains 'TraceEnable on'. [William Rowe]
+
*) Add ap_log_cerror() for logging messages associated with particular
client connections. [Jeff Trawick]
diff --git a/STATUS b/STATUS
index 9ea9aa75f6..2d93e2681b 100644
--- a/STATUS
+++ b/STATUS
@@ -104,54 +104,10 @@ CURRENT RELEASE NOTES:
RELEASE SHOWSTOPPERS:
- * Copy the backport branch of all of the mod_proxy_http.c's request body
- handling security, protocol and bug fixes; by svn copy'ing the file
- httpd/httpd/branches/proxy-reqbody-2.0.x/modules/proxy/proxy_http.c back to
- httpd/branches/2.0.x/... preserving the detail of all of the individually
- backported changes.
-
- +1: wrowe, jim, minfrin
- -1:
-
- For a complete history of individual unit changes, see r230703 - r230744 in
- http://svn.apache.org/viewcvs.cgi/httpd/httpd/branches/proxy-reqbody-2.0.x/
- [...] modules/proxy/proxy_http.c?&view=log
- Cite the specific patch with justification for each specific objection.
-
- Suggested; revert r219061 to thoroughly test this patch, as r219061 masks
- some underlying bugs (although it is a -good- patch in and of itself and
- provides additional protection to other content-handling modules).
-
- * TRACE must not have a request body per RFC2616; see the -trace.patch
- below for one of two alternatives. The other alternative; simply
- hack mod_proxy.c to reject TRACE when a body is seen, again see that
- -trace.patch for an illustration.
-
PATCHES ACCEPTED TO BACKPORT FROM TRUNK:
[ start all new proposals below, under PATCHES PROPOSED. ]
- *) mod_cgi: Added API call and overload of detached field in
- cgi_exec_info_t structure to support loading in current or new address
- space for CGIs. The patch change how NetWare use cmdtype for
- processes. It was made necessary by changes done to log.c r1.145.
- The HTTP and the APR patches are available at:
- <http://www.apache.org/~clar/detach-addrspace_HTTP_2_0.patch>
- <http://www.apache.org/~clar/detach-addrspace_APR_0_9.patch>
- +1: jjclar, bnicholes, trawick
- jerenkrantz: I'm confused as to the status of this backport.
- trawick: Somebody commits the APR 0.9 patch, then:
- do we have to wait for later APR 0.x release before putting
- calls to apr_procattr_addrspace_set() into httpd-2.0.x, or
- do we go ahead and introduce the prerequisite?
- clar replies: I am ready to commit the apr 0.9.x patch, but then will need
- the changes in the httpd-2.0.x to be done in order for NetWare to work
- as expected when calling apr_proc_create. Should I do both, APR and Http,
- at the same time?
- wrowe: commit to APR. Use an APR version test *in httpd* to determine
- if the old or new behavior should be used in httpd. In future versions
- you could remove the test altogether.
-
*) mod_actions: Regression from 1.3: the file referred to must exist.
Solve this by introducing the "virtual" modifier to the Action
directive. PR 28553.
@@ -194,12 +150,6 @@ PATCHES ACCEPTED TO BACKPORT FROM TRUNK:
+1: pquerna, nd, wrowe
Votes from before the integration branch: +1: jerenkrantz
- *) Fix CAN-2005-2491, integer overflow in pcre.
- http://svn.apache.org/viewcvs?rev=233493&view=rev
- rediff for 2.0: http://people.apache.org/~jorton/CAN-2005-2491.patch
- test case: perl-framework/t/security/CAN-2005-2491.t
- +1: jorton, nd, wrowe
-
PATCHES PROPOSED TO BACKPORT FROM TRUNK:
[ please place SVN revisions from trunk here, so it is easy to
identify exactly what the proposed changes are! Add all new
@@ -211,18 +161,6 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK:
+1: jorton, wrowe
wrowe cautions to backport to 2.2.x branch as well.
- *) Correct RFC 2616 non-compliance by refusing to proxy a request body
- in a TRACE request, unless TraceEnable extended is configured.
- Introduces TraceEnable [on|off|extended] to give the administrator
- full control of TRACE request handling. RFC 2616 does NOT require
- TRACE (although to disable remains silly). Current patch at;
- http://people.apache.org/~wrowe/httpd-2.0-trace.patch
- +1 wrowe, jimjag, colm
- colm notes: There are some \n's in apr_table_setn calls that are
- not consistent with other calls to apr_table_setn.
- There is no documentation for TraceEnable in trunk to
- backport, shouldn't release while still undocumented.
-
*) mod_headers: Support {...}s tag for SSL variable lookup.
http://www.apache.org/~jorton/mod_headers-2.0-ssl.diff
+1: jorton, trawick
@@ -252,9 +190,9 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK:
*) Provide TLS/SSL upgrade functionality in mod_ssl allowing an unsecure
connection to be upgraded to a secure connection upon request by the
- client. The full patch file is available at http://www.apache.org/~bnicholes/
- as well as a test client tlsupgrade.c. This functionality is mainly used by
- IPP clients today.
+ client. The full patch is available at http://www.apache.org/~bnicholes/
+ as well as a test client tlsupgrade.c. This functionality is mainly used
+ by IPP clients today.
modules/ssl/mod_ssl.c: r1.75, r1.97, r1.100
modules/ssl/mod_ssl.h: r1.123
modules/ssl/ssl_engine_config.c: r1.71, r1.90
@@ -328,51 +266,8 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK:
algorithims can be pretty "interesting", probably more
2.2.
- *) mod_ldap: Fix PR 36563. Keep track of the number of attributes
- retrieved from LDAP so that all of the values can be properly
- cached even if the value is NULL.
- http://issues.apache.org/bugzilla/attachment.cgi?id=16429
- or
- http://svn.apache.org/viewcvs.cgi?rev=156587&view=rev
- +1: bnicholes
-
PATCHES TO BACKPORT THAT ARE ON HOLD OR NOT GOING ANYWHERE SOON:
- *) Remove LDAP toolkit specific code from util_ldap and mod_auth_ldap.
- modules/experimental/mod_auth_ldap.c: 1.28
- modules/experimental/util_ldap.c: 1.36
- +0: minfrin (this requires the apr-util LDAP overhaul to be ported to
- apr-util v0.9 first)
- -0: jerenkrantz
- jerenkrantz: I don't think we can change the APR 0.9 interfaces.
- They are supposed to be set in stone.
- -1: wrowe: agrees with jerenkrantz, further realized that this major
- change in APR 1.0 caused -every- apr-util linked app to have
- the ldap sdk (openldap etc) linked in, and our --static-support
- stuff is horribly broken by this change. Not that it's wrong,
- we need to look at making it slightly more dynamic for those
- apps that don't touch ldap.
-
- *) Add load balancer support to the scoreboard in preparation for
- load balancing support in mod_proxy.
- include/scoreboard.h: 1.52
- server/scoreboard.c: 1.75
- +0: minfrin: it makes sense for v2.1 or v2.2
- -0: nd, jerenkrantz
- nd: -0 as in "it should be considered as a 2.1 feature".
- If the modified structures are public (are they?), I'm just -1.
- jerenkrantz: Sounds like a good 2.1 feature...
- -1: wrowe (make this a private score to the module and you would be fine;
- we don't need to keep overloading a single scoreboard.)
-
- *) mod_ssl: Remove some unused functions (after CAN-2004-0488 fix is applied)
- http://cvs.apache.org/viewcvs.cgi/httpd-2.0/modules/ssl/ssl_util.c?r1=1.46&r2=1.47
- +1: jorton
- trawick: need changes to mod_ssl.h to remove prototypes for those removed functions
- 0: nd: IMHO that's a public API change then and not applicable for
- 2.0, just let 'em in
- -1: wrowe (as nd suggests, leave the dead horse in peace.)
-
*) Replace some of the mutex locking in the worker MPM with
atomic operations for higher concurrency.
server/mpm/worker/fdqueue.c 1.24, 1.25
@@ -467,30 +362,31 @@ PATCHES TO BACKPORT THAT ARE ON HOLD OR NOT GOING ANYWHERE SOON:
http://svn.apache.org/viewcvs?view=rev&rev=158798
http://svn.apache.org/viewcvs?view=rev&rev=159410
http://svn.apache.org/viewcvs?view=rev&rev=160573
- +1: gregames
+ +1: gregames, wrowe (provided this is applied to ALL subreq types!)
-1: jerenkrantz (read_length isn't a sufficient check to see if a body
is present in the request; presence of T-E and C-L in
the headers is the correct flag.)
- gregames: done in rev 160573
- ±0: wrowe (this has a negative impact on modules who wish to 'inspect'
+ gregames: addressed jerenkrantz' objection in rev 160573
+ wrowe: this has a negative impact on modules who wish to 'inspect'
the headers, e.g. an xml transformation affected by the query
string or request POST args. The right solution is adopt apreq,
- providing an API for filters to participate in POST bodies.)
+ providing an API for filters to participate in POST bodies.
gregames: this does not affect POSTs. the affected function helps
create a GET subrequest with no body and is unprepared to deal with
subrequest bodies. any modules or applications wishing to
inspect headers will in fact work better because the headers will
reflect reality.
-
+ wrowe: I've reconsidered - the simple fact is that subrequests
+ don't have a good mechanism to 'share' the input body with the
+ main request, and it's gotta be up to the main request to handle
+ the input body. If the module wants to use apreq-provided data,
+ then it's going to have to ask apreq for the data instead of
+ looking at the headers. For that matter, why are subreq's even
+ propogating POST or other non-GET types? It seems that almost
+ any subreq should be handled as a GET in 2.0.
CURRENT VOTES:
- *) Promote mod_ldap and mod_auth_ldap from experimental to
- non experimental status.
- +1: bnicholes, wrowe
- +0: minfrin (wait till the last cache bugs are ironed out)
- -1: jerenkrantz
-
*) httpd-std.conf and friends;
a) httpd-std.conf should be tailored by install (from src or
@@ -502,28 +398,10 @@ CURRENT VOTES:
(.default.conf rather than .conf.default so that win32
can recognize .conf files as text configuration files.)
- b) tailored httpd-std.conf should be copied by install to
- sysconfdir/examples
- -0: striker
-
c) tailored httpd-std.conf should be installed to
sysconfdir/examples or manualdir/exampleconf/
+1: slive, trawick, Ken, nd (prefer the latter), erikabele
- d) tailored httpd-std.conf should be installed as httpd-std-<version>.conf.
- +1: striker
-
- e) Installing a set of default config files when upgrading a server
- doesn't make ANY sense at all.
- +1: ianh - medium/big sites don't use 'standard config' anyway, as it
- usually needs major customizations
- -1: Ken, wrowe, jwoolley, jim, nd, erikabele
- wrowe - diff is wonderful when comparing old/new default configs,
- even for customized sites that ianh mentions
- jim - it makes sense assuming that the default configs
- include the updated directives and inline comments
- that explain the changes and make the 'diff' more useful.
-
*) If the parent process dies, should the remaining child processes
"gracefully" self-terminate. Or maybe we should make it a runtime
option, or have a concept of 2 parent processes (one being a
diff --git a/docs/manual/mod/core.html.de b/docs/manual/mod/core.html.de
index f6722f9584..f79589047f 100644
--- a/docs/manual/mod/core.html.de
+++ b/docs/manual/mod/core.html.de
@@ -92,6 +92,7 @@ Servers</td></tr>
<li><img alt="" src="../images/down.gif" /> <a href="#setinputfilter">SetInputFilter</a></li>
<li><img alt="" src="../images/down.gif" /> <a href="#setoutputfilter">SetOutputFilter</a></li>
<li><img alt="" src="../images/down.gif" /> <a href="#timeout">TimeOut</a></li>
+<li><img alt="" src="../images/down.gif" /> <a href="#traceenable">TraceEnable</a></li>
<li><img alt="" src="../images/down.gif" /> <a href="#usecanonicalname">UseCanonicalName</a></li>
<li><img alt="" src="../images/down.gif" /> <a href="#virtualhost">&lt;VirtualHost&gt;</a></li>
</ul>
@@ -3174,6 +3175,39 @@ bevor er die Anfrage abbricht</td></tr>
</div>
<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
+<div class="directive-section"><h2><a name="TraceEnable" id="TraceEnable">TraceEnable</a>-<a name="traceenable" id="traceenable">Direktive</a></h2>
+<table class="directive">
+<tr><th><a href="directive-dict.html#Description">Beschreibung:</a></th><td>Legt das Serververhalten bei <code>TRACE</code>-Anfragen
+fest</td></tr>
+<tr><th><a href="directive-dict.html#Syntax">Syntax:</a></th><td><code>TraceEnable <var>[on|off|extended]</var></code></td></tr>
+<tr><th><a href="directive-dict.html#Default">Voreinstellung:</a></th><td><code>TraceEnable on</code></td></tr>
+<tr><th><a href="directive-dict.html#Context">Kontext:</a></th><td>Serverkonfiguration</td></tr>
+<tr><th><a href="directive-dict.html#Status">Status:</a></th><td>Core</td></tr>
+<tr><th><a href="directive-dict.html#Module">Modul:</a></th><td>core</td></tr>
+<tr><th><a href="directive-dict.html#Compatibility">Kompatibilität:</a></th><td>Seit den Versionen 1.3.34 und 2.0.55</td></tr>
+</table>
+ <p>Diese Direktive überschreibt das Verhalten bei <code>TRACE</code>
+ sowohl für den Hauptserver als auch für
+ <code class="module"><a href="../mod/mod_proxy.html">mod_proxy</a></code>. Die Voreinstellung <code>TraceEnable on</code>
+ erlaubt <code>TRACE</code>-Anfragen gemäß RFC 2616, welcher
+ das Mitschicken von Request-Bodies verbietet. <code>TraceEnable off</code>
+ veranlasst den Hauptserver und <code class="module"><a href="../mod/mod_proxy.html">mod_proxy</a></code>, dem
+ Client mit dem Fehler <code>405</code> (Methode nicht erlaubt)
+ antworten.</p>
+
+ <p>Mit Hilfe der nicht konformen Direktive <code>TraceEnable
+ extended</code> können Request-Bodies zugelassen werden. Das ist
+ allerdings ausschließlich für Test- und Diagnosezwecke gedacht.
+ Der Hauptserver (als Ursprungsserver) <span class="transnote">(<em>Anm.d.Ü.:</em> damit ist der
+ Normalbetrieb und nicht der Einsatz als Proxy-Server gemeint)</span>
+ limitiert den Request-Body auf 64K (plus 8K für die Chunk-Header,
+ wenn <code>Transfer-Encoding: chunked</code> verwendet wird) und
+ reflektiert den vollen Headersatz sowie alle Chunk-Header in seiner
+ Antwort. Im Betrieb als Proxyserver wird der Request-Body nicht auf
+ 64K begrenzt.</p>
+
+</div>
+<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
<div class="directive-section"><h2><a name="UseCanonicalName" id="UseCanonicalName">UseCanonicalName</a>-<a name="usecanonicalname" id="usecanonicalname">Direktive</a></h2>
<table class="directive">
<tr><th><a href="directive-dict.html#Description">Beschreibung:</a></th><td>Bestimmt, wie der Server seinen eigenen Namen und Port
diff --git a/docs/manual/mod/core.html.en b/docs/manual/mod/core.html.en
index 85747b2b85..b1ade3256a 100644
--- a/docs/manual/mod/core.html.en
+++ b/docs/manual/mod/core.html.en
@@ -92,6 +92,7 @@ available</td></tr>
<li><img alt="" src="../images/down.gif" /> <a href="#setinputfilter">SetInputFilter</a></li>
<li><img alt="" src="../images/down.gif" /> <a href="#setoutputfilter">SetOutputFilter</a></li>
<li><img alt="" src="../images/down.gif" /> <a href="#timeout">TimeOut</a></li>
+<li><img alt="" src="../images/down.gif" /> <a href="#traceenable">TraceEnable</a></li>
<li><img alt="" src="../images/down.gif" /> <a href="#usecanonicalname">UseCanonicalName</a></li>
<li><img alt="" src="../images/down.gif" /> <a href="#virtualhost">&lt;VirtualHost&gt;</a></li>
</ul>
@@ -3025,6 +3026,35 @@ certain events before failing a request</td></tr>
</div>
<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
+<div class="directive-section"><h2><a name="TraceEnable" id="TraceEnable">TraceEnable</a> <a name="traceenable" id="traceenable">Directive</a></h2>
+<table class="directive">
+<tr><th><a href="directive-dict.html#Description">Description:</a></th><td>Determines the behaviour on <code>TRACE</code>
+requests</td></tr>
+<tr><th><a href="directive-dict.html#Syntax">Syntax:</a></th><td><code>TraceEnable <var>[on|off|extended]</var></code></td></tr>
+<tr><th><a href="directive-dict.html#Default">Default:</a></th><td><code>TraceEnable on</code></td></tr>
+<tr><th><a href="directive-dict.html#Context">Context:</a></th><td>server config</td></tr>
+<tr><th><a href="directive-dict.html#Status">Status:</a></th><td>Core</td></tr>
+<tr><th><a href="directive-dict.html#Module">Module:</a></th><td>core</td></tr>
+<tr><th><a href="directive-dict.html#Compatibility">Compatibility:</a></th><td>Available in Apache 1.3.34, 2.0.55 and later</td></tr>
+</table>
+ <p>This directive overrides the behavior of <code>TRACE</code> for both
+ the core server and <code class="module"><a href="../mod/mod_proxy.html">mod_proxy</a></code>. The default
+ <code>TraceEnable on</code> permits <code>TRACE</code> requests per
+ RFC 2616, which disallows any request body to accompany the request.
+ <code>TraceEnable off</code> causes the core server and
+ <code class="module"><a href="../mod/mod_proxy.html">mod_proxy</a></code> to return a <code>405</code> (Method not
+ allowed) error to the client.</p>
+
+ <p>Finally, for testing and diagnostic purposes only, request
+ bodies may be allowed using the non-compliant <code>TraceEnable
+ extended</code> directive. The core (as an origin server) will
+ restrict the request body to 64k (plus 8k for chunk headers if
+ <code>Transfer-Encoding: chunked</code> is used). The core will
+ reflect the full headers and all chunk headers with the response
+ body. As a proxy server, the request body is not restricted to 64k.</p>
+
+</div>
+<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
<div class="directive-section"><h2><a name="UseCanonicalName" id="UseCanonicalName">UseCanonicalName</a> <a name="usecanonicalname" id="usecanonicalname">Directive</a></h2>
<table class="directive">
<tr><th><a href="directive-dict.html#Description">Description:</a></th><td>Configures how the server determines its own name and
diff --git a/docs/manual/mod/core.xml b/docs/manual/mod/core.xml
index 10d8a21f6c..a0f1224196 100644
--- a/docs/manual/mod/core.xml
+++ b/docs/manual/mod/core.xml
@@ -2980,6 +2980,34 @@ certain events before failing a request</description>
</directivesynopsis>
<directivesynopsis>
+<name>TraceEnable</name>
+<description>Determines the behaviour on <code>TRACE</code>
+requests</description>
+<syntax>TraceEnable <var>[on|off|extended]</var></syntax>
+<default>TraceEnable on</default>
+<contextlist><context>server config</context></contextlist>
+<compatibility>Available in Apache 1.3.34, 2.0.55 and later</compatibility>
+
+<usage>
+ <p>This directive overrides the behavior of <code>TRACE</code> for both
+ the core server and <module>mod_proxy</module>. The default
+ <code>TraceEnable on</code> permits <code>TRACE</code> requests per
+ RFC 2616, which disallows any request body to accompany the request.
+ <code>TraceEnable off</code> causes the core server and
+ <module>mod_proxy</module> to return a <code>405</code> (Method not
+ allowed) error to the client.</p>
+
+ <p>Finally, for testing and diagnostic purposes only, request
+ bodies may be allowed using the non-compliant <code>TraceEnable
+ extended</code> directive. The core (as an origin server) will
+ restrict the request body to 64k (plus 8k for chunk headers if
+ <code>Transfer-Encoding: chunked</code> is used). The core will
+ reflect the full headers and all chunk headers with the response
+ body. As a proxy server, the request body is not restricted to 64k.</p>
+</usage>
+</directivesynopsis>
+
+<directivesynopsis>
<name>UseCanonicalName</name>
<description>Configures how the server determines its own name and
port</description>
diff --git a/docs/manual/mod/core.xml.de b/docs/manual/mod/core.xml.de
index 07c9d4f441..ffa7d9ca94 100644
--- a/docs/manual/mod/core.xml.de
+++ b/docs/manual/mod/core.xml.de
@@ -1,10 +1,11 @@
<?xml version="1.0"?>
<!DOCTYPE modulesynopsis SYSTEM "../style/modulesynopsis.dtd">
<?xml-stylesheet type="text/xsl" href="../style/manual.de.xsl"?>
-<!-- English Revision: 279024 -->
+<!-- English Revision: 290733 -->
<!--
- Copyright 2003-2004 The Apache Software Foundation
+ Copyright 2003-2005 The Apache Software Foundation or its licensors,
+ as applicable
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -3122,6 +3123,38 @@ bevor er die Anfrage abbricht</description>
</directivesynopsis>
<directivesynopsis>
+<name>TraceEnable</name>
+<description>Legt das Serververhalten bei <code>TRACE</code>-Anfragen
+fest</description>
+<syntax>TraceEnable <var>[on|off|extended]</var></syntax>
+<default>TraceEnable on</default>
+<contextlist><context>server config</context></contextlist>
+<compatibility>Seit den Versionen 1.3.34 und 2.0.55</compatibility>
+
+<usage>
+ <p>Diese Direktive &uuml;berschreibt das Verhalten bei <code>TRACE</code>
+ sowohl f&uuml;r den Hauptserver als auch f&uuml;r
+ <module>mod_proxy</module>. Die Voreinstellung <code>TraceEnable on</code>
+ erlaubt <code>TRACE</code>-Anfragen gem&auml;&szlig; RFC 2616, welcher
+ das Mitschicken von Request-Bodies verbietet. <code>TraceEnable off</code>
+ veranlasst den Hauptserver und <module>mod_proxy</module>, dem
+ Client mit dem Fehler <code>405</code> (Methode nicht erlaubt)
+ antworten.</p>
+
+ <p>Mit Hilfe der nicht konformen Direktive <code>TraceEnable
+ extended</code> k&ouml;nnen Request-Bodies zugelassen werden. Das ist
+ allerdings ausschlie&szlig;lich f&uuml;r Test- und Diagnosezwecke gedacht.
+ Der Hauptserver (als Ursprungsserver) <transnote>damit ist der
+ Normalbetrieb und nicht der Einsatz als Proxy-Server gemeint</transnote>
+ limitiert den Request-Body auf 64K (plus 8K f&uuml;r die Chunk-Header,
+ wenn <code>Transfer-Encoding: chunked</code> verwendet wird) und
+ reflektiert den vollen Headersatz sowie alle Chunk-Header in seiner
+ Antwort. Im Betrieb als Proxyserver wird der Request-Body nicht auf
+ 64K begrenzt.</p>
+</usage>
+</directivesynopsis>
+
+<directivesynopsis>
<name>UseCanonicalName</name>
<description>Bestimmt, wie der Server seinen eigenen Namen und Port
ermittelt</description>
diff --git a/docs/manual/mod/core.xml.es b/docs/manual/mod/core.xml.es
index c07bd015af..643a136011 100644
--- a/docs/manual/mod/core.xml.es
+++ b/docs/manual/mod/core.xml.es
@@ -1,7 +1,7 @@
<?xml version="1.0"?>
<!DOCTYPE modulesynopsis SYSTEM "../style/modulesynopsis.dtd">
<?xml-stylesheet type="text/xsl" href="../style/manual.es.xsl"?>
-<!-- English Revision: 151420:279024 (outdated) -->
+<!-- English Revision: 151420:290733 (outdated) -->
<!--
Copyright 2005 The Apache Software Foundation or it licensors,
diff --git a/docs/manual/mod/core.xml.ja b/docs/manual/mod/core.xml.ja
index 3167ae71f1..6257dddcd5 100644
--- a/docs/manual/mod/core.xml.ja
+++ b/docs/manual/mod/core.xml.ja
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="iso-2022-jp"?>
<!DOCTYPE modulesynopsis SYSTEM "../style/modulesynopsis.dtd">
<?xml-stylesheet type="text/xsl" href="../style/manual.ja.xsl"?>
-<!-- English Revision: 106090:279024 (outdated) -->
+<!-- English Revision: 106090:290733 (outdated) -->
<!--
Copyright 2003-2004 The Apache Software Foundation
diff --git a/docs/manual/mod/directives.html.de b/docs/manual/mod/directives.html.de
index 8bb888148d..2ad2f638d6 100644
--- a/docs/manual/mod/directives.html.de
+++ b/docs/manual/mod/directives.html.de
@@ -383,6 +383,7 @@
<li><a href="mpm_common.html#threadsperchild">ThreadsPerChild</a></li>
<li><a href="mpm_netware.html#threadstacksize">ThreadStackSize</a></li>
<li><a href="core.html#timeout">TimeOut</a></li>
+<li><a href="core.html#traceenable">TraceEnable</a></li>
<li><a href="mod_log_config.html#transferlog">TransferLog</a></li>
<li><a href="mod_mime.html#typesconfig">TypesConfig</a></li>
<li><a href="mod_env.html#unsetenv" id="U" name="U">UnsetEnv</a></li>
diff --git a/docs/manual/mod/directives.html.en b/docs/manual/mod/directives.html.en
index f5cafdb3c1..274a638519 100644
--- a/docs/manual/mod/directives.html.en
+++ b/docs/manual/mod/directives.html.en
@@ -384,6 +384,7 @@
<li><a href="mpm_common.html#threadsperchild">ThreadsPerChild</a></li>
<li><a href="mpm_netware.html#threadstacksize">ThreadStackSize</a></li>
<li><a href="core.html#timeout">TimeOut</a></li>
+<li><a href="core.html#traceenable">TraceEnable</a></li>
<li><a href="mod_log_config.html#transferlog">TransferLog</a></li>
<li><a href="mod_mime.html#typesconfig">TypesConfig</a></li>
<li><a href="mod_env.html#unsetenv" id="U" name="U">UnsetEnv</a></li>
diff --git a/docs/manual/mod/directives.html.ko.euc-kr b/docs/manual/mod/directives.html.ko.euc-kr
index 9d47114499..4868ca57c0 100644
--- a/docs/manual/mod/directives.html.ko.euc-kr
+++ b/docs/manual/mod/directives.html.ko.euc-kr
@@ -379,6 +379,7 @@
<li><a href="mpm_common.html#threadsperchild">ThreadsPerChild</a></li>
<li><a href="mpm_netware.html#threadstacksize">ThreadStackSize</a></li>
<li><a href="core.html#timeout">TimeOut</a></li>
+<li><a href="core.html#traceenable">TraceEnable</a></li>
<li><a href="mod_log_config.html#transferlog">TransferLog</a></li>
<li><a href="mod_mime.html#typesconfig">TypesConfig</a></li>
<li><a href="mod_env.html#unsetenv" id="U" name="U">UnsetEnv</a></li>
diff --git a/docs/manual/mod/directives.html.ru.koi8-r b/docs/manual/mod/directives.html.ru.koi8-r
index d079a7f950..1d88ad823d 100644
--- a/docs/manual/mod/directives.html.ru.koi8-r
+++ b/docs/manual/mod/directives.html.ru.koi8-r
@@ -385,6 +385,7 @@
<li><a href="mpm_common.html#threadsperchild">ThreadsPerChild</a></li>
<li><a href="mpm_netware.html#threadstacksize">ThreadStackSize</a></li>
<li><a href="core.html#timeout">TimeOut</a></li>
+<li><a href="core.html#traceenable">TraceEnable</a></li>
<li><a href="mod_log_config.html#transferlog">TransferLog</a></li>
<li><a href="mod_mime.html#typesconfig">TypesConfig</a></li>
<li><a href="mod_env.html#unsetenv" id="U" name="U">UnsetEnv</a></li>
diff --git a/docs/manual/mod/mod_dumpio.xml b/docs/manual/mod/mod_dumpio.xml
index b17be15289..11e5d12ab7 100644
--- a/docs/manual/mod/mod_dumpio.xml
+++ b/docs/manual/mod/mod_dumpio.xml
@@ -1,7 +1,7 @@
<?xml version="1.0"?>
<!DOCTYPE modulesynopsis SYSTEM "../style/modulesynopsis.dtd">
<?xml-stylesheet type="text/xsl" href="../style/manual.en.xsl"?>
-<!-- $LastChangedRevision: 125277 $ -->
+<!-- $LastChangedRevision$ -->
<!--
Copyright 2004-2005 The Apache Software Foundation or its licensors, as
diff --git a/docs/manual/mod/quickreference.html.de b/docs/manual/mod/quickreference.html.de
index 95944a28f1..548b26f425 100644
--- a/docs/manual/mod/quickreference.html.de
+++ b/docs/manual/mod/quickreference.html.de
@@ -699,6 +699,8 @@ Certificate verification</td></tr>
<tr><td><a href="mpm_netware.html#threadstacksize">ThreadStackSize <var>number</var></a></td><td> 65536 </td><td>s</td><td>M</td></tr><tr><td class="descr" colspan="4">Determine the stack size for each thread</td></tr>
<tr class="odd"><td><a href="core.html#timeout">TimeOut <var>Sekunden</var></a></td><td> 300 </td><td>s</td><td>C</td></tr><tr class="odd"><td class="descr" colspan="4">Zeitspanne, die der Server auf verschiedene Ereignisse wartet,
bevor er die Anfrage abbricht</td></tr>
+<tr class="odd"><td><a href="core.html#traceenable">TraceEnable <var>[on|off|extended]</var></a></td><td> on </td><td>s</td><td>C</td></tr><tr class="odd"><td class="descr" colspan="4">Legt das Serververhalten bei <code>TRACE</code>-Anfragen
+fest</td></tr>
<tr><td><a href="mod_log_config.html#transferlog">TransferLog <var>file</var>|<var>pipe</var></a></td><td></td><td>sv</td><td>B</td></tr><tr><td class="descr" colspan="4">Specify location of a log file</td></tr>
<tr class="odd"><td><a href="mod_mime.html#typesconfig">TypesConfig <var>file-path</var></a></td><td> conf/mime.types </td><td>s</td><td>B</td></tr><tr class="odd"><td class="descr" colspan="4">The location of the <code>mime.types</code> file</td></tr>
<tr><td><a href="mod_env.html#unsetenv" id="U" name="U">UnsetEnv <var>env-variable</var> [<var>env-variable</var>]
@@ -734,4 +736,4 @@ set</td></tr>
</div><div id="footer">
<p class="apache">Copyright 1995-2005 The Apache Software Foundation or its licensors, as applicable.<br />Lizenziert unter der <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>.</p>
<p class="menu"><a href="../mod/">Module</a> | <a href="../mod/directives.html">Direktiven</a> | <a href="../faq/">FAQ</a> | <a href="../glossary.html">Glossar</a> | <a href="../sitemap.html">Seitenindex</a></p></div>
-</body></html> \ No newline at end of file
+</body></html>
diff --git a/docs/manual/mod/quickreference.html.en b/docs/manual/mod/quickreference.html.en
index f1a6230da4..29ac4d6b3e 100644
--- a/docs/manual/mod/quickreference.html.en
+++ b/docs/manual/mod/quickreference.html.en
@@ -680,6 +680,8 @@ per child process</td></tr>
<tr><td><a href="mpm_netware.html#threadstacksize">ThreadStackSize <var>number</var></a></td><td> 65536 </td><td>s</td><td>M</td></tr><tr><td class="descr" colspan="4">Determine the stack size for each thread</td></tr>
<tr class="odd"><td><a href="core.html#timeout">TimeOut <var>seconds</var></a></td><td> 300 </td><td>s</td><td>C</td></tr><tr class="odd"><td class="descr" colspan="4">Amount of time the server will wait for
certain events before failing a request</td></tr>
+<tr class="odd"><td><a href="core.html#traceenable">TraceEnable <var>[on|off|extended]</var></a></td><td> on </td><td>s</td><td>C</td></tr><tr class="odd"><td class="descr" colspan="4">Determines the behaviour on <code>TRACE</code>
+requests</td></tr>
<tr><td><a href="mod_log_config.html#transferlog">TransferLog <var>file</var>|<var>pipe</var></a></td><td></td><td>sv</td><td>B</td></tr><tr><td class="descr" colspan="4">Specify location of a log file</td></tr>
<tr class="odd"><td><a href="mod_mime.html#typesconfig">TypesConfig <var>file-path</var></a></td><td> conf/mime.types </td><td>s</td><td>B</td></tr><tr class="odd"><td class="descr" colspan="4">The location of the <code>mime.types</code> file</td></tr>
<tr><td><a href="mod_env.html#unsetenv" id="U" name="U">UnsetEnv <var>env-variable</var> [<var>env-variable</var>]
@@ -715,4 +717,4 @@ set</td></tr>
</div><div id="footer">
<p class="apache">Copyright 1995-2005 The Apache Software Foundation or its licensors, as applicable.<br />Licensed under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>.</p>
<p class="menu"><a href="../mod/">Modules</a> | <a href="../mod/directives.html">Directives</a> | <a href="../faq/">FAQ</a> | <a href="../glossary.html">Glossary</a> | <a href="../sitemap.html">Sitemap</a></p></div>
-</body></html> \ No newline at end of file
+</body></html>
diff --git a/docs/manual/mod/quickreference.html.ko.euc-kr b/docs/manual/mod/quickreference.html.ko.euc-kr
index 3deb70e38b..fbe5c690d6 100644
--- a/docs/manual/mod/quickreference.html.ko.euc-kr
+++ b/docs/manual/mod/quickreference.html.ko.euc-kr
@@ -631,6 +631,8 @@ per child process</td></tr>
<tr><td><a href="mpm_netware.html#threadstacksize">ThreadStackSize <var>number</var></a></td><td> 65536 </td><td>s</td><td>M</td></tr><tr><td class="descr" colspan="4">Determine the stack size for each thread</td></tr>
<tr class="odd"><td><a href="core.html#timeout">TimeOut <var>seconds</var></a></td><td> 300 </td><td>s</td><td>C</td></tr><tr class="odd"><td class="descr" colspan="4">Amount of time the server will wait for
certain events before failing a request</td></tr>
+<tr class="odd"><td><a href="core.html#traceenable">TraceEnable <var>[on|off|extended]</var></a></td><td> on </td><td>s</td><td>C</td></tr><tr class="odd"><td class="descr" colspan="4">Determines the behaviour on <code>TRACE</code>
+requests</td></tr>
<tr><td><a href="mod_log_config.html#transferlog">TransferLog <var>file</var>|<var>pipe</var></a></td><td></td><td>sv</td><td>B</td></tr><tr><td class="descr" colspan="4">·Î±×ÆÄÀÏ À§Ä¡¸¦ ¼³Á¤ÇÑ´Ù</td></tr>
<tr class="odd"><td><a href="mod_mime.html#typesconfig">TypesConfig <var>file-path</var></a></td><td> conf/mime.types </td><td>s</td><td>B</td></tr><tr class="odd"><td class="descr" colspan="4">The location of the <code>mime.types</code> file</td></tr>
<tr><td><a href="mod_env.html#unsetenv" id="U" name="U">UnsetEnv <var>env-variable</var> [<var>env-variable</var>]
@@ -666,4 +668,4 @@ set</td></tr>
</div><div id="footer">
<p class="apache">Copyright 1995-2005 The Apache Software Foundation or its licensors, as applicable.<br />Licensed under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>.</p>
<p class="menu"><a href="../mod/">¸ðµâ</a> | <a href="../mod/directives.html">Áö½Ã¾îµé</a> | <a href="../faq/">FAQ</a> | <a href="../glossary.html">¿ë¾î</a> | <a href="../sitemap.html">»çÀÌÆ®¸Ê</a></p></div>
-</body></html> \ No newline at end of file
+</body></html>
diff --git a/docs/manual/mod/quickreference.html.ru.koi8-r b/docs/manual/mod/quickreference.html.ru.koi8-r
index 4e42f6c71a..772f9980d0 100644
--- a/docs/manual/mod/quickreference.html.ru.koi8-r
+++ b/docs/manual/mod/quickreference.html.ru.koi8-r
@@ -682,6 +682,8 @@ per child process</td></tr>
<tr><td><a href="mpm_netware.html#threadstacksize">ThreadStackSize <var>number</var></a></td><td> 65536 </td><td>s</td><td>M</td></tr><tr><td class="descr" colspan="4">Determine the stack size for each thread</td></tr>
<tr class="odd"><td><a href="core.html#timeout">TimeOut <var>seconds</var></a></td><td> 300 </td><td>s</td><td>C</td></tr><tr class="odd"><td class="descr" colspan="4">Amount of time the server will wait for
certain events before failing a request</td></tr>
+<tr class="odd"><td><a href="core.html#traceenable">TraceEnable <var>[on|off|extended]</var></a></td><td> on </td><td>s</td><td>C</td></tr><tr class="odd"><td class="descr" colspan="4">Determines the behaviour on <code>TRACE</code>
+requests</td></tr>
<tr><td><a href="mod_log_config.html#transferlog">TransferLog <var>file</var>|<var>pipe</var></a></td><td></td><td>sv</td><td>B</td></tr><tr><td class="descr" colspan="4">Specify location of a log file</td></tr>
<tr class="odd"><td><a href="mod_mime.html#typesconfig">TypesConfig <var>file-path</var></a></td><td> conf/mime.types </td><td>s</td><td>B</td></tr><tr class="odd"><td class="descr" colspan="4">The location of the <code>mime.types</code> file</td></tr>
<tr><td><a href="mod_env.html#unsetenv" id="U" name="U">UnsetEnv <var>env-variable</var> [<var>env-variable</var>]
@@ -717,4 +719,4 @@ set</td></tr>
</div><div id="footer">
<p class="apache">Copyright 1995-2005 The Apache Software Foundation or its licensors, as applicable.<br />Licensed under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>.</p>
<p class="menu"><a href="../mod/">íÏÄÕÌÉ</a> | <a href="../mod/directives.html">äÉÒÅËÔÉ×Ù</a> | <a href="../faq/">FAQ</a> | <a href="../glossary.html">çÌÏÓÓÁÒÉÊ</a> | <a href="../sitemap.html">ëÁÒÔÁ ÓÁÊÔÁ</a></p></div>
-</body></html> \ No newline at end of file
+</body></html>
diff --git a/docs/manual/programs/htdbm.xml b/docs/manual/programs/htdbm.xml
index 03890eda8f..de888d8aa0 100644
--- a/docs/manual/programs/htdbm.xml
+++ b/docs/manual/programs/htdbm.xml
@@ -1,7 +1,7 @@
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE manualpage SYSTEM "../style/manualpage.dtd">
<?xml-stylesheet type="text/xsl" href="../style/manual.en.xsl"?>
-<!-- $LastChangedRevision: 151405 $ -->
+<!-- $LastChangedRevision$ -->
<!--
Copyright 2003-2005 The Apache Software Foundation or its licensors, as
diff --git a/docs/manual/rewrite/rewrite_guide.xml b/docs/manual/rewrite/rewrite_guide.xml
index 0b1aa36dd9..6aa69fc01f 100644
--- a/docs/manual/rewrite/rewrite_guide.xml
+++ b/docs/manual/rewrite/rewrite_guide.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE manualpage SYSTEM "../style/manualpage.dtd">
<?xml-stylesheet type="text/xsl" href="../style/manual.en.xsl"?>
-<!-- $LastChangedRevision: 123578 $ -->
+<!-- $LastChangedRevision$ -->
<!--
Copyright 2002-2005 The Apache Software Foundation or its licensors, as
diff --git a/docs/manual/rewrite/rewrite_guide_advanced.xml b/docs/manual/rewrite/rewrite_guide_advanced.xml
index 257f388934..d44bad6629 100644
--- a/docs/manual/rewrite/rewrite_guide_advanced.xml
+++ b/docs/manual/rewrite/rewrite_guide_advanced.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE manualpage SYSTEM "../style/manualpage.dtd">
<?xml-stylesheet type="text/xsl" href="../style/manual.en.xsl"?>
-<!-- $LastChangedRevision: 123578 $ -->
+<!-- $LastChangedRevision$ -->
<!--
Copyright 2002-2005 The Apache Software Foundation or its licensors, as
diff --git a/include/ap_mmn.h b/include/ap_mmn.h
index 0e1175cd42..a6b1d1bddf 100644
--- a/include/ap_mmn.h
+++ b/include/ap_mmn.h
@@ -83,8 +83,9 @@
* ap_finalize_sub_req_protocol on Win32 and NetWare
* 20020903.9 (2.0.51-dev) create pcommands and initialize arrays before
* calling ap_setup_prelinked_modules
- * 20020903.10 (2.0.55-dev) added ap_get_server_revision / ap_version_t
- * add ap_log_cerror()
+ * 20020903.10 (2.0.55-dev) add ap_log_cerror()
+ * 20020903.11 (2.0.55-dev) added trace_enable to core_server_config
+ * added ap_get_server_revision / ap_version_t
*/
#define MODULE_MAGIC_COOKIE 0x41503230UL /* "AP20" */
@@ -92,7 +93,7 @@
#ifndef MODULE_MAGIC_NUMBER_MAJOR
#define MODULE_MAGIC_NUMBER_MAJOR 20020903
#endif
-#define MODULE_MAGIC_NUMBER_MINOR 10 /* 0...n */
+#define MODULE_MAGIC_NUMBER_MINOR 11 /* 0...n */
/**
* Determine if the server's current MODULE_MAGIC_NUMBER is at least a
diff --git a/include/http_core.h b/include/http_core.h
index 9028ff012b..dfcb0fc256 100644
--- a/include/http_core.h
+++ b/include/http_core.h
@@ -549,6 +549,14 @@ typedef struct {
/* recursion backstopper */
int redirect_limit; /* maximum number of internal redirects */
int subreq_limit; /* maximum nesting level of subrequests */
+
+ /* TRACE control */
+#define AP_TRACE_UNSET -1
+#define AP_TRACE_DISABLE 0
+#define AP_TRACE_ENABLE 1
+#define AP_TRACE_EXTENDED 2
+ int trace_enable;
+
} core_server_config;
/* for AddOutputFiltersByType in core.c */
diff --git a/modules/arch/netware/mod_netware.c b/modules/arch/netware/mod_netware.c
index aa560f7931..2c4e2248bf 100644
--- a/modules/arch/netware/mod_netware.c
+++ b/modules/arch/netware/mod_netware.c
@@ -100,7 +100,6 @@ static apr_status_t ap_cgi_build_command(const char **cmd, const char ***argv,
char *ext = NULL;
char *cmd_only, *ptr;
const char *new_cmd;
- const char *detached = NULL;
netware_dir_config *d;
apr_file_t *fh;
const char *args = "";
@@ -143,6 +142,7 @@ static apr_status_t ap_cgi_build_command(const char **cmd, const char ***argv,
/* check if we have a registered command for the extension*/
new_cmd = apr_table_get(d->file_type_handlers, ext);
+ e_info->detached = AP_PROC_DETACHED;
if (new_cmd == NULL) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"Could not find a command associated with the %s extension", ext);
@@ -154,18 +154,12 @@ static apr_status_t ap_cgi_build_command(const char **cmd, const char ***argv,
*cmd = apr_pstrcat (p, new_cmd, " ", cmd_only, NULL);
/* Run in its own address space if specified */
- detached = apr_table_get(d->file_handler_mode, ext);
- if (detached) {
- e_info->cmd_type = APR_PROGRAM_ENV;
- }
- else {
- e_info->cmd_type = APR_PROGRAM;
- }
+ if(apr_table_get(d->file_handler_mode, ext))
+ e_info->detached |= AP_PROC_NEWADDRSPACE;
}
/* Tokenize the full command string into its arguments */
apr_tokenize_to_argv(*cmd, (char***)argv, p);
- e_info->detached = 1;
/* The first argument should be the executible */
*cmd = ap_server_root_relative(p, *argv[0]);
diff --git a/modules/experimental/util_ldap.c b/modules/experimental/util_ldap.c
index 9a74445784..dabc4e7dec 100644
--- a/modules/experimental/util_ldap.c
+++ b/modules/experimental/util_ldap.c
@@ -769,6 +769,7 @@ LDAP_DECLARE(int) util_ldap_cache_checkuserid(request_rec *r, util_ldap_connecti
const char ***retvals)
{
const char **vals = NULL;
+ int numvals = 0;
int result = 0;
LDAPMessage *res, *entry;
char *dn;
@@ -932,6 +933,7 @@ start_over:
int i = 0;
while (attrs[k++]);
vals = apr_pcalloc(r->pool, sizeof(char *) * (k+1));
+ numvals = k;
while (attrs[i]) {
char **values;
int j = 0;
@@ -959,6 +961,7 @@ start_over:
the_search_node.bindpw = bindpw;
the_search_node.lastbind = apr_time_now();
the_search_node.vals = vals;
+ the_search_node.numvals = numvals;
/* Search again to make sure that another thread didn't ready insert this node
into the cache before we got here. If it does exist then update the lastbind */
@@ -1001,6 +1004,7 @@ LDAP_DECLARE(int) util_ldap_cache_getuserdn(request_rec *r, util_ldap_connection
const char ***retvals)
{
const char **vals = NULL;
+ int numvals = 0;
int result = 0;
LDAPMessage *res, *entry;
char *dn;
@@ -1115,6 +1119,7 @@ start_over:
int i = 0;
while (attrs[k++]);
vals = apr_pcalloc(r->pool, sizeof(char *) * (k+1));
+ numvals = k;
while (attrs[i]) {
char **values;
int j = 0;
@@ -1142,6 +1147,7 @@ start_over:
the_search_node.bindpw = NULL;
the_search_node.lastbind = apr_time_now();
the_search_node.vals = vals;
+ the_search_node.numvals = numvals;
/* Search again to make sure that another thread didn't ready insert this node
into the cache before we got here. If it does exist then update the lastbind */
diff --git a/modules/experimental/util_ldap_cache.c b/modules/experimental/util_ldap_cache.c
index ca85689077..58b3c6fbfe 100644
--- a/modules/experimental/util_ldap_cache.c
+++ b/modules/experimental/util_ldap_cache.c
@@ -158,18 +158,22 @@ void *util_ldap_search_node_copy(util_ald_cache_t *cache, void *c)
/* copy vals */
if (node->vals) {
- int k = 0;
+ int k = node->numvals;
int i = 0;
- while (node->vals[k++]);
if (!(newnode->vals = util_ald_alloc(cache, sizeof(char *) * (k+1)))) {
util_ldap_search_node_free(cache, newnode);
return NULL;
}
- while (node->vals[i]) {
- if (!(newnode->vals[i] = util_ald_strdup(cache, node->vals[i]))) {
- util_ldap_search_node_free(cache, newnode);
- return NULL;
+ newnode->numvals = node->numvals;
+ for (;k;k--) {
+ if (node->vals[i]) {
+ if (!(newnode->vals[i] = util_ald_strdup(cache, node->vals[i]))) {
+ util_ldap_search_node_free(cache, newnode);
+ return NULL;
+ }
}
+ else
+ newnode->vals[i] = NULL;
i++;
}
}
@@ -199,9 +203,13 @@ void util_ldap_search_node_free(util_ald_cache_t *cache, void *n)
{
int i = 0;
util_search_node_t *node = (util_search_node_t *)n;
+ int k = node->numvals;
+
if (node->vals) {
- while (node->vals[i]) {
- util_ald_free(cache, node->vals[i++]);
+ for (;k;k--,i++) {
+ if (node->vals[i]) {
+ util_ald_free(cache, node->vals[i]);
+ }
}
util_ald_free(cache, node->vals);
}
diff --git a/modules/experimental/util_ldap_cache.h b/modules/experimental/util_ldap_cache.h
index 5a0ab79f33..51e50a51d2 100644
--- a/modules/experimental/util_ldap_cache.h
+++ b/modules/experimental/util_ldap_cache.h
@@ -110,6 +110,7 @@ typedef struct util_search_node_t {
NULL if the bind failed */
apr_time_t lastbind; /* Time of last successful bind */
const char **vals; /* Values of queried attributes */
+ int numvals; /* Number of queried attributes */
} util_search_node_t;
/*
diff --git a/modules/generators/mod_cgi.c b/modules/generators/mod_cgi.c
index 1ff33bb559..3a8ae8ef6b 100644
--- a/modules/generators/mod_cgi.c
+++ b/modules/generators/mod_cgi.c
@@ -436,7 +436,9 @@ static apr_status_t run_cgi_child(apr_file_t **script_out,
e_info->cmd_type)) != APR_SUCCESS) ||
((rc = apr_procattr_detach_set(procattr,
- e_info->detached)) != APR_SUCCESS) ||
+ e_info->detached & AP_PROC_DETACHED)) != APR_SUCCESS) ||
+ ((rc = apr_procattr_addrspace_set(procattr,
+ (e_info->detached & AP_PROC_NEWADDRSPACE) ? 1 : 0)) != APR_SUCCESS) ||
((rc = apr_procattr_child_errfn_set(procattr, cgi_child_errfn)) != APR_SUCCESS)) {
/* Something bad happened, tell the world. */
ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r,
diff --git a/modules/generators/mod_cgi.h b/modules/generators/mod_cgi.h
index 7221093a83..cf9d9ba9d7 100644
--- a/modules/generators/mod_cgi.h
+++ b/modules/generators/mod_cgi.h
@@ -19,6 +19,9 @@
#include "mod_include.h"
+#define AP_PROC_DETACHED 1
+#define AP_PROC_NEWADDRSPACE 2
+
typedef enum {RUN_AS_SSI, RUN_AS_CGI} prog_types;
typedef struct {
@@ -27,7 +30,8 @@ typedef struct {
apr_int32_t err_pipe;
int process_cgi;
apr_cmdtype_e cmd_type;
- apr_int32_t detached;
+ apr_int32_t detached; /* used as a bitfield for detached_ & addrspace_set, */
+ /* when initializing apr_proc_attr structure */
prog_types prog_type;
apr_bucket_brigade **bb;
include_ctx_t *ctx;
diff --git a/modules/http/http_protocol.c b/modules/http/http_protocol.c
index 8b58453255..0bad324c42 100644
--- a/modules/http/http_protocol.c
+++ b/modules/http/http_protocol.c
@@ -1321,6 +1321,9 @@ static char *make_allow(request_rec *r)
apr_int64_t mask;
apr_array_header_t *allow = apr_array_make(r->pool, 10, sizeof(char *));
apr_hash_index_t *hi = apr_hash_first(r->pool, methods_registry);
+ /* For TRACE below */
+ core_server_config *conf =
+ ap_get_module_config(r->server->module_config, &core_module);
mask = r->allowed_methods->method_mask;
@@ -1338,8 +1341,9 @@ static char *make_allow(request_rec *r)
}
}
- /* TRACE is always allowed */
- *(const char **)apr_array_push(allow) = "TRACE";
+ /* TRACE is tested on a per-server basis */
+ if (conf->trace_enable != AP_TRACE_DISABLE)
+ *(const char **)apr_array_push(allow) = "TRACE";
list = apr_array_pstrcat(r->pool, allow, ',');
@@ -1364,9 +1368,16 @@ static char *make_allow(request_rec *r)
AP_DECLARE_NONSTD(int) ap_send_http_trace(request_rec *r)
{
+ core_server_config *conf;
int rv;
- apr_bucket_brigade *b;
+ apr_bucket_brigade *bb;
header_struct h;
+ apr_bucket *b;
+ int body;
+ char *bodyread = NULL, *bodyoff;
+ apr_size_t bodylen = 0;
+ apr_size_t bodybuf;
+ long res;
if (r->method_number != M_TRACE) {
return DECLINED;
@@ -1376,23 +1387,87 @@ AP_DECLARE_NONSTD(int) ap_send_http_trace(request_rec *r)
while (r->prev) {
r = r->prev;
}
+ conf = (core_server_config *)ap_get_module_config(r->server->module_config,
+ &core_module);
+
+ if (conf->trace_enable == AP_TRACE_DISABLE) {
+ apr_table_setn(r->notes, "error-notes",
+ "TRACE denied by server configuration");
+ return HTTP_FORBIDDEN;
+ }
- if ((rv = ap_setup_client_block(r, REQUEST_NO_BODY))) {
+ if (conf->trace_enable == AP_TRACE_EXTENDED)
+ /* XX should be = REQUEST_CHUNKED_PASS */
+ body = REQUEST_CHUNKED_DECHUNK;
+ else
+ body = REQUEST_NO_BODY;
+
+ if ((rv = ap_setup_client_block(r, body))) {
+ if (rv == HTTP_REQUEST_ENTITY_TOO_LARGE)
+ apr_table_setn(r->notes, "error-notes",
+ "TRACE with a request body is not allowed");
return rv;
}
+ if (ap_should_client_block(r)) {
+
+ if (r->remaining > 0) {
+ if (r->remaining > 65536) {
+ apr_table_setn(r->notes, "error-notes",
+ "Extended TRACE request bodies cannot exceed 64k");
+ return HTTP_REQUEST_ENTITY_TOO_LARGE;
+ }
+ /* always 32 extra bytes to catch chunk header exceptions */
+ bodybuf = (apr_size_t)r->remaining + 32;
+ }
+ else {
+ /* Add an extra 8192 for chunk headers */
+ bodybuf = 73730;
+ }
+
+ bodyoff = bodyread = apr_palloc(r->pool, bodybuf);
+
+ /* only while we have enough for a chunked header */
+ while ((!bodylen || bodybuf >= 32) &&
+ (res = ap_get_client_block(r, bodyoff, bodybuf)) > 0) {
+ bodylen += res;
+ bodybuf -= res;
+ bodyoff += res;
+ }
+ if (res > 0 && bodybuf < 32) {
+ /* discard_rest_of_request_body into our buffer */
+ while (ap_get_client_block(r, bodyread, bodylen) > 0)
+ ;
+ apr_table_setn(r->notes, "error-notes",
+ "Extended TRACE request bodies cannot exceed 64k");
+ return HTTP_REQUEST_ENTITY_TOO_LARGE;
+ }
+
+ if (res < 0) {
+ return HTTP_BAD_REQUEST;
+ }
+ }
+
ap_set_content_type(r, "message/http");
/* Now we recreate the request, and echo it back */
- b = apr_brigade_create(r->pool, r->connection->bucket_alloc);
- apr_brigade_putstrs(b, NULL, NULL, r->the_request, CRLF, NULL);
+ bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
+ apr_brigade_putstrs(bb, NULL, NULL, r->the_request, CRLF, NULL);
h.pool = r->pool;
- h.bb = b;
+ h.bb = bb;
apr_table_do((int (*) (void *, const char *, const char *))
form_header_field, (void *) &h, r->headers_in, NULL);
- apr_brigade_puts(b, NULL, NULL, CRLF);
- ap_pass_brigade(r->output_filters, b);
+ apr_brigade_puts(bb, NULL, NULL, CRLF);
+
+ /* If configured to accept a body, echo the body */
+ if (bodylen) {
+ b = apr_bucket_pool_create(bodyread, bodylen,
+ r->pool, bb->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(bb, b);
+ }
+
+ ap_pass_brigade(r->output_filters, bb);
return DONE;
}
diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c
index e9961d6cb1..e22b4b7ac2 100644
--- a/modules/proxy/mod_proxy.c
+++ b/modules/proxy/mod_proxy.c
@@ -350,6 +350,42 @@ static int proxy_handler(request_rec *r)
apr_table_set(r->headers_in, "Max-Forwards",
apr_psprintf(r->pool, "%ld", (maxfwd > 0) ? maxfwd : 0));
+ if (r->method_number == M_TRACE) {
+ core_server_config *coreconf = (core_server_config *)
+ ap_get_module_config(sconf, &core_module);
+
+ if (coreconf->trace_enable == AP_TRACE_DISABLE)
+ {
+ /* Allow "error-notes" string to be printed by ap_send_error_response()
+ * Note; this goes nowhere, canned error response need an overhaul.
+ */
+ apr_table_setn(r->notes, "error-notes",
+ "TRACE forbidden by server configuration");
+ apr_table_setn(r->notes, "verbose-error-to", "*");
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "proxy: TRACE forbidden by server configuration");
+ return HTTP_FORBIDDEN;
+ }
+
+ /* Can't test ap_should_client_block, we aren't ready to send
+ * the client a 100 Continue response till the connection has
+ * been established
+ */
+ if (coreconf->trace_enable != AP_TRACE_EXTENDED
+ && (r->read_length || r->read_chunked || r->remaining))
+ {
+ /* Allow "error-notes" string to be printed by ap_send_error_response()
+ * Note; this goes nowhere, canned error response need an overhaul.
+ */
+ apr_table_setn(r->notes, "error-notes",
+ "TRACE with request body is not allowed");
+ apr_table_setn(r->notes, "verbose-error-to", "*");
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "proxy: TRACE with request body is not allowed");
+ return HTTP_REQUEST_ENTITY_TOO_LARGE;
+ }
+ }
+
url = r->filename + 6;
p = strchr(url, ':');
if (p == NULL)
diff --git a/modules/proxy/proxy_http.c b/modules/proxy/proxy_http.c
index 57e31d99a2..225b7011b4 100644
--- a/modules/proxy/proxy_http.c
+++ b/modules/proxy/proxy_http.c
@@ -431,23 +431,23 @@ static void terminate_headers(apr_bucket_alloc_t *bucket_alloc,
static apr_status_t pass_brigade(apr_bucket_alloc_t *bucket_alloc,
request_rec *r, proxy_http_conn_t *p_conn,
- conn_rec *origin, apr_bucket_brigade *b,
+ conn_rec *origin, apr_bucket_brigade *bb,
int flush)
{
apr_status_t status;
if (flush) {
apr_bucket *e = apr_bucket_flush_create(bucket_alloc);
- APR_BRIGADE_INSERT_TAIL(b, e);
+ APR_BRIGADE_INSERT_TAIL(bb, e);
}
- status = ap_pass_brigade(origin->output_filters, b);
+ status = ap_pass_brigade(origin->output_filters, bb);
if (status != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
- "proxy: pass request data failed to %pI (%s)",
+ "proxy: pass request body failed to %pI (%s)",
p_conn->addr, p_conn->name);
return status;
}
- apr_brigade_cleanup(b);
+ apr_brigade_cleanup(bb);
return APR_SUCCESS;
}
@@ -455,40 +455,28 @@ static apr_status_t stream_reqbody_chunked(apr_pool_t *p,
request_rec *r,
proxy_http_conn_t *p_conn,
conn_rec *origin,
- apr_bucket_brigade *header_brigade)
+ apr_bucket_brigade *header_brigade,
+ apr_bucket_brigade *input_brigade)
{
int seen_eos = 0;
apr_size_t hdr_len;
apr_off_t bytes;
apr_status_t status;
apr_bucket_alloc_t *bucket_alloc = r->connection->bucket_alloc;
- apr_bucket_brigade *b, *input_brigade;
+ apr_bucket_brigade *bb;
apr_bucket *e;
- input_brigade = apr_brigade_create(p, bucket_alloc);
+ add_te_chunked(p, bucket_alloc, header_brigade);
+ terminate_headers(bucket_alloc, header_brigade);
- do {
+ while (!APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade)))
+ {
char chunk_hdr[20]; /* must be here due to transient bucket. */
- status = ap_get_brigade(r->input_filters, input_brigade,
- AP_MODE_READBYTES, APR_BLOCK_READ,
- HUGE_STRING_LEN);
-
- if (status != APR_SUCCESS) {
- return status;
- }
-
/* If this brigade contains EOS, either stop or remove it. */
if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) {
seen_eos = 1;
- /* As a shortcut, if this brigade is simply an EOS bucket,
- * don't send anything down the filter chain.
- */
- if (APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade))) {
- break;
- }
-
/* We can't pass this EOS to the output_filters. */
e = APR_BRIGADE_LAST(input_brigade);
apr_bucket_delete(e);
@@ -515,28 +503,38 @@ static apr_status_t stream_reqbody_chunked(apr_pool_t *p,
/* we never sent the header brigade, so go ahead and
* take care of that now
*/
- add_te_chunked(p, bucket_alloc, header_brigade);
- terminate_headers(bucket_alloc, header_brigade);
- b = header_brigade;
- APR_BRIGADE_CONCAT(b, input_brigade);
+ bb = header_brigade;
+ APR_BRIGADE_CONCAT(bb, input_brigade);
header_brigade = NULL;
}
else {
- b = input_brigade;
+ bb = input_brigade;
}
- status = pass_brigade(bucket_alloc, r, p_conn, origin, b, 0);
+ /* The request is flushed below this loop with chunk EOS header */
+ status = pass_brigade(bucket_alloc, r, p_conn, origin, bb, 0);
+ if (status != APR_SUCCESS) {
+ return status;
+ }
+
+ if (seen_eos) {
+ break;
+ }
+
+ status = ap_get_brigade(r->input_filters, input_brigade,
+ AP_MODE_READBYTES, APR_BLOCK_READ,
+ HUGE_STRING_LEN);
+
if (status != APR_SUCCESS) {
return status;
}
- } while (!seen_eos);
+ }
if (header_brigade) {
/* we never sent the header brigade because there was no request body;
- * send it now without T-E
+ * send it now
*/
- terminate_headers(bucket_alloc, header_brigade);
- b = header_brigade;
+ bb = header_brigade;
}
else {
if (!APR_BRIGADE_EMPTY(input_brigade)) {
@@ -545,15 +543,17 @@ static apr_status_t stream_reqbody_chunked(apr_pool_t *p,
AP_DEBUG_ASSERT(APR_BUCKET_IS_EOS(e));
apr_bucket_delete(e);
}
- e = apr_bucket_immortal_create(ASCII_ZERO ASCII_CRLF
- /* <trailers> */
- ASCII_CRLF,
- 5, bucket_alloc);
- APR_BRIGADE_INSERT_TAIL(input_brigade, e);
- b = input_brigade;
+ bb = input_brigade;
}
-
- status = pass_brigade(bucket_alloc, r, p_conn, origin, b, 1);
+
+ e = apr_bucket_immortal_create(ASCII_ZERO ASCII_CRLF
+ /* <trailers> */
+ ASCII_CRLF,
+ 5, bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(bb, e);
+
+ /* Now we have headers-only, or the chunk EOS mark; flush it */
+ status = pass_brigade(bucket_alloc, r, p_conn, origin, bb, 1);
return status;
}
@@ -562,77 +562,95 @@ static apr_status_t stream_reqbody_cl(apr_pool_t *p,
proxy_http_conn_t *p_conn,
conn_rec *origin,
apr_bucket_brigade *header_brigade,
+ apr_bucket_brigade *input_brigade,
const char *old_cl_val)
{
int seen_eos = 0;
- apr_status_t status;
+ apr_status_t status = APR_SUCCESS;
apr_bucket_alloc_t *bucket_alloc = r->connection->bucket_alloc;
- apr_bucket_brigade *b, *input_brigade;
+ apr_bucket_brigade *bb;
apr_bucket *e;
+ apr_off_t cl_val = 0;
+ apr_off_t bytes;
+ apr_off_t bytes_streamed = 0;
- input_brigade = apr_brigade_create(p, bucket_alloc);
-
- do {
- status = ap_get_brigade(r->input_filters, input_brigade,
- AP_MODE_READBYTES, APR_BLOCK_READ,
- HUGE_STRING_LEN);
+ if (old_cl_val) {
+ add_cl(p, bucket_alloc, header_brigade, old_cl_val);
+ cl_val = atol(old_cl_val);
+ }
+ terminate_headers(bucket_alloc, header_brigade);
- if (status != APR_SUCCESS) {
- return status;
- }
+ while (!APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade)))
+ {
+ apr_brigade_length(input_brigade, 1, &bytes);
+ bytes_streamed += bytes;
/* If this brigade contains EOS, either stop or remove it. */
if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) {
seen_eos = 1;
- /* As a shortcut, if this brigade is simply an EOS bucket,
- * don't send anything down the filter chain.
- */
- if (APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade))) {
- break;
- }
-
/* We can't pass this EOS to the output_filters. */
e = APR_BRIGADE_LAST(input_brigade);
apr_bucket_delete(e);
}
+ /* C-L < bytes streamed?!?
+ * We will error out after the body is completely
+ * consumed, but we can't stream more bytes at the
+ * back end since they would in part be interpreted
+ * as another request! If nothing is sent, then
+ * just send nothing.
+ *
+ * Prevents HTTP Response Splitting.
+ */
+ if (bytes_streamed > cl_val)
+ continue;
+
if (header_brigade) {
/* we never sent the header brigade, so go ahead and
* take care of that now
*/
- add_cl(p, bucket_alloc, header_brigade, old_cl_val);
- terminate_headers(bucket_alloc, header_brigade);
- b = header_brigade;
- APR_BRIGADE_CONCAT(b, input_brigade);
+ bb = header_brigade;
+ APR_BRIGADE_CONCAT(bb, input_brigade);
header_brigade = NULL;
}
else {
- b = input_brigade;
+ bb = input_brigade;
}
- status = pass_brigade(bucket_alloc, r, p_conn, origin, b, 0);
+ /* Once we hit EOS, we are ready to flush. */
+ status = pass_brigade(bucket_alloc, r, p_conn, origin, bb, seen_eos);
+ if (status != APR_SUCCESS) {
+ return status;
+ }
+
+ if (seen_eos) {
+ break;
+ }
+
+ status = ap_get_brigade(r->input_filters, input_brigade,
+ AP_MODE_READBYTES, APR_BLOCK_READ,
+ HUGE_STRING_LEN);
+
if (status != APR_SUCCESS) {
return status;
}
- } while (!seen_eos);
+ }
+
+ if (bytes_streamed != cl_val) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+ "proxy: client %s given Content-Length did not match"
+ " number of body bytes read", r->connection->remote_ip);
+ return APR_EOF;
+ }
if (header_brigade) {
/* we never sent the header brigade since there was no request
- * body; send it now, and only specify C-L if client specified
- * C-L: 0
+ * body; send it now with the flush flag
*/
- if (!strcmp(old_cl_val, "0")) {
- add_cl(p, bucket_alloc, header_brigade, old_cl_val);
- }
- terminate_headers(bucket_alloc, header_brigade);
- b = header_brigade;
+ bb = header_brigade;
+ status = pass_brigade(bucket_alloc, r, p_conn, origin, bb, 1);
}
- else {
- /* need to flush any pending data */
- b = input_brigade; /* empty now; pass_brigade() will add flush */
- }
- status = pass_brigade(bucket_alloc, r, p_conn, origin, b, 1);
return status;
}
@@ -642,39 +660,26 @@ static apr_status_t spool_reqbody_cl(apr_pool_t *p,
request_rec *r,
proxy_http_conn_t *p_conn,
conn_rec *origin,
- apr_bucket_brigade *header_brigade)
+ apr_bucket_brigade *header_brigade,
+ apr_bucket_brigade *input_brigade,
+ int force_cl)
{
int seen_eos = 0;
apr_status_t status;
apr_bucket_alloc_t *bucket_alloc = r->connection->bucket_alloc;
- apr_bucket_brigade *body_brigade, *input_brigade;
+ apr_bucket_brigade *body_brigade;
apr_bucket *e;
apr_off_t bytes, bytes_spooled = 0, fsize = 0;
apr_file_t *tmpfile = NULL;
body_brigade = apr_brigade_create(p, bucket_alloc);
- input_brigade = apr_brigade_create(p, bucket_alloc);
-
- do {
- status = ap_get_brigade(r->input_filters, input_brigade,
- AP_MODE_READBYTES, APR_BLOCK_READ,
- HUGE_STRING_LEN);
-
- if (status != APR_SUCCESS) {
- return status;
- }
+ while (!APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade)))
+ {
/* If this brigade contains EOS, either stop or remove it. */
if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) {
seen_eos = 1;
- /* As a shortcut, if this brigade is simply an EOS bucket,
- * don't send anything down the filter chain.
- */
- if (APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade))) {
- break;
- }
-
/* We can't pass this EOS to the output_filters. */
e = APR_BRIGADE_LAST(input_brigade);
apr_bucket_delete(e);
@@ -735,9 +740,20 @@ static apr_status_t spool_reqbody_cl(apr_pool_t *p,
bytes_spooled += bytes;
- } while (!seen_eos);
+ if (seen_eos) {
+ break;
+ }
- if (bytes_spooled) {
+ status = ap_get_brigade(r->input_filters, input_brigade,
+ AP_MODE_READBYTES, APR_BLOCK_READ,
+ HUGE_STRING_LEN);
+
+ if (status != APR_SUCCESS) {
+ return status;
+ }
+ }
+
+ if (bytes_spooled || force_cl) {
add_cl(p, bucket_alloc, header_brigade, apr_off_t_toa(p, bytes_spooled));
}
terminate_headers(bucket_alloc, header_brigade);
@@ -766,112 +782,36 @@ static apr_status_t spool_reqbody_cl(apr_pool_t *p,
}
APR_BRIGADE_INSERT_TAIL(header_brigade, e);
}
+ /* This is all a single brigade, pass with flush flagged */
status = pass_brigade(bucket_alloc, r, p_conn, origin, header_brigade, 1);
return status;
}
-static apr_status_t send_request_body(apr_pool_t *p,
- request_rec *r,
- proxy_http_conn_t *p_conn,
- conn_rec *origin,
- apr_bucket_brigade *header_brigade,
- int force10)
-{
- enum {RB_INIT, RB_STREAM_CL, RB_STREAM_CHUNKED, RB_SPOOL_CL} rb_method = RB_INIT;
- const char *old_cl_val, *te_val;
- int cl_zero; /* client sent "Content-Length: 0", which we forward on to server */
- apr_status_t status;
-
- /* send CL or use chunked encoding?
- *
- * . CL is the most friendly to the origin server since it is the
- * most widely supported
- * . CL stinks if we don't know the length since we have to buffer
- * the data in memory or on disk until we get the entire data
- *
- * special cases to check for:
- * . if we're using HTTP/1.0 to origin server, then we must send CL
- * . if client sent C-L and there are no input resource filters, the
- * the body size can't change so we send the same CL and stream the
- * body
- * . if client used chunked or proxy-sendchunks is set, we'll also
- * use chunked
- *
- * normal case:
- * we have to compute content length by reading the entire request
- * body; if request body is not small, we'll spool the remaining input
- * to a temporary file
- *
- * special envvars to override the normal decision:
- * . proxy-sendchunks
- * use chunked encoding; not compatible with force-proxy-request-1.0
- * . proxy-sendcl
- * spool the request body to compute C-L
- * . proxy-sendunchangedcl
- * use C-L from client and spool the request body
- */
- old_cl_val = apr_table_get(r->headers_in, "Content-Length");
- cl_zero = old_cl_val && !strcmp(old_cl_val, "0");
-
- if (!force10
- && !cl_zero
- && apr_table_get(r->subprocess_env, "proxy-sendchunks")) {
- rb_method = RB_STREAM_CHUNKED;
- }
- else if (!cl_zero
- && apr_table_get(r->subprocess_env, "proxy-sendcl")) {
- rb_method = RB_SPOOL_CL;
- }
- else {
- if (old_cl_val &&
- (r->input_filters == r->proto_input_filters
- || cl_zero
- || apr_table_get(r->subprocess_env, "proxy-sendunchangedcl"))) {
- rb_method = RB_STREAM_CL;
- }
- else if (force10) {
- rb_method = RB_SPOOL_CL;
- }
- else if ((te_val = apr_table_get(r->headers_in, "Transfer-Encoding"))
- && !strcasecmp(te_val, "chunked")) {
- rb_method = RB_STREAM_CHUNKED;
- }
- else {
- rb_method = RB_SPOOL_CL;
- }
- }
-
- switch(rb_method) {
- case RB_STREAM_CHUNKED:
- status = stream_reqbody_chunked(p, r, p_conn, origin, header_brigade);
- break;
- case RB_STREAM_CL:
- status = stream_reqbody_cl(p, r, p_conn, origin, header_brigade, old_cl_val);
- break;
- case RB_SPOOL_CL:
- status = spool_reqbody_cl(p, r, p_conn, origin, header_brigade);
- break;
- default:
- ap_assert(1 != 1);
- }
-
- return status;
-}
-
static
apr_status_t ap_proxy_http_request(apr_pool_t *p, request_rec *r,
proxy_http_conn_t *p_conn, conn_rec *origin,
proxy_server_conf *conf,
apr_uri_t *uri,
- char *url, apr_bucket_brigade *bb,
- char *server_portstr) {
+ char *url,
+ apr_bucket_brigade *header_brigade,
+ char *server_portstr)
+{
conn_rec *c = r->connection;
- char *buf;
+ apr_bucket_alloc_t *bucket_alloc = c->bucket_alloc;
+ apr_bucket_brigade *input_brigade;
+ apr_bucket_brigade *temp_brigade;
apr_bucket *e;
+ char *buf;
const apr_array_header_t *headers_in_array;
const apr_table_entry_t *headers_in;
int counter;
apr_status_t status;
+ enum rb_methods {RB_INIT, RB_STREAM_CL, RB_STREAM_CHUNKED, RB_SPOOL_CL};
+ enum rb_methods rb_method = RB_INIT;
+ const char *old_cl_val = NULL;
+ const char *old_te_val = NULL;
+ apr_off_t bytes_read = 0;
+ apr_off_t bytes;
int force10;
/*
@@ -881,40 +821,39 @@ apr_status_t ap_proxy_http_request(apr_pool_t *p, request_rec *r,
/* strip connection listed hop-by-hop headers from the request */
/* even though in theory a connection: close coming from the client
* should not affect the connection to the server, it's unlikely
- * that subsequent client requests will hit this thread/process, so
- * we cancel server keepalive if the client does.
+ * that subsequent client requests will hit this thread/process,
+ * so we cancel server keepalive if the client does.
*/
- p_conn->close += ap_proxy_liststr(apr_table_get(r->headers_in,
- "Connection"), "close");
- /* sub-requests never use keepalives */
- if (r->main) {
+ if (ap_proxy_liststr(apr_table_get(r->headers_in,
+ "Connection"), "close")) {
p_conn->close++;
+ /* XXX: we are abusing r->headers_in rather than a copy,
+ * give the core output handler a clue the client would
+ * rather just close.
+ */
+ c->keepalive = AP_CONN_CLOSE;
}
-
ap_proxy_clear_connection(p, r->headers_in);
- if (p_conn->close) {
- apr_table_setn(r->headers_in, "Connection", "close");
- origin->keepalive = AP_CONN_CLOSE;
- }
- if ( apr_table_get(r->subprocess_env,"force-proxy-request-1.0")) {
+ if (apr_table_get(r->subprocess_env, "force-proxy-request-1.0")) {
buf = apr_pstrcat(p, r->method, " ", url, " HTTP/1.0" CRLF, NULL);
force10 = 1;
+ p_conn->close++;
} else {
buf = apr_pstrcat(p, r->method, " ", url, " HTTP/1.1" CRLF, NULL);
force10 = 0;
}
- if ( apr_table_get(r->subprocess_env,"proxy-nokeepalive")) {
- apr_table_unset(r->headers_in, "Connection");
+ if (apr_table_get(r->subprocess_env, "proxy-nokeepalive")) {
origin->keepalive = AP_CONN_CLOSE;
+ p_conn->close++;
}
ap_xlate_proto_to_ascii(buf, strlen(buf));
e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc);
- APR_BRIGADE_INSERT_TAIL(bb, e);
- if ( conf->preserve_host == 0 ) {
+ APR_BRIGADE_INSERT_TAIL(header_brigade, e);
+ if (conf->preserve_host == 0) {
if (uri->port_str && uri->port != DEFAULT_HTTP_PORT) {
- buf = apr_pstrcat(p, "Host: ", uri->hostname, ":", uri->port_str, CRLF,
- NULL);
+ buf = apr_pstrcat(p, "Host: ", uri->hostname, ":", uri->port_str,
+ CRLF, NULL);
} else {
buf = apr_pstrcat(p, "Host: ", uri->hostname, CRLF, NULL);
}
@@ -937,7 +876,7 @@ apr_status_t ap_proxy_http_request(apr_pool_t *p, request_rec *r,
}
ap_xlate_proto_to_ascii(buf, strlen(buf));
e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc);
- APR_BRIGADE_INSERT_TAIL(bb, e);
+ APR_BRIGADE_INSERT_TAIL(header_brigade, e);
/* handle Via */
if (conf->viaopt == via_block) {
@@ -988,7 +927,7 @@ apr_status_t ap_proxy_http_request(apr_pool_t *p, request_rec *r,
* determine, where the original request came from.
*/
apr_table_mergen(r->headers_in, "X-Forwarded-For",
- r->connection->remote_ip);
+ r->connection->remote_ip);
/* Add X-Forwarded-Host: so that upstream knows what the
* original request hostname was.
@@ -1002,7 +941,7 @@ apr_status_t ap_proxy_http_request(apr_pool_t *p, request_rec *r,
* XXX: This duplicates Via: - do we strictly need it?
*/
apr_table_mergen(r->headers_in, "X-Forwarded-Server",
- r->server->server_hostname);
+ r->server->server_hostname);
}
/* send request headers */
@@ -1010,82 +949,265 @@ apr_status_t ap_proxy_http_request(apr_pool_t *p, request_rec *r,
headers_in_array = apr_table_elts(r->headers_in);
headers_in = (const apr_table_entry_t *) headers_in_array->elts;
for (counter = 0; counter < headers_in_array->nelts; counter++) {
- if (headers_in[counter].key == NULL || headers_in[counter].val == NULL
+ if (headers_in[counter].key == NULL
+ || headers_in[counter].val == NULL
- /* Clear out hop-by-hop request headers not to send
- * RFC2616 13.5.1 says we should strip these headers
- */
- /* Already sent */
- || !apr_strnatcasecmp(headers_in[counter].key, "Host")
-
- || !apr_strnatcasecmp(headers_in[counter].key, "Keep-Alive")
- || !apr_strnatcasecmp(headers_in[counter].key, "TE")
- || !apr_strnatcasecmp(headers_in[counter].key, "Trailer")
- || !apr_strnatcasecmp(headers_in[counter].key, "Transfer-Encoding")
- || !apr_strnatcasecmp(headers_in[counter].key, "Upgrade")
+ /* Already sent */
+ || !strcasecmp(headers_in[counter].key, "Host")
- /* We'll add appropriate Content-Length later, if appropriate.
+ /* Clear out hop-by-hop request headers not to send
+ * RFC2616 13.5.1 says we should strip these headers
*/
- || !apr_strnatcasecmp(headers_in[counter].key, "Content-Length")
+ || !strcasecmp(headers_in[counter].key, "Keep-Alive")
+ || !strcasecmp(headers_in[counter].key, "TE")
+ || !strcasecmp(headers_in[counter].key, "Trailer")
+ || !strcasecmp(headers_in[counter].key, "Upgrade")
+
+ /* XXX: @@@ FIXME: "Proxy-Authorization" should *only* be
+ * suppressed if THIS server requested the authentication,
+ * not when a frontend proxy requested it!
+ *
+ * The solution to this problem is probably to strip out
+ * the Proxy-Authorisation header in the authorisation
+ * code itself, not here. This saves us having to signal
+ * somehow whether this request was authenticated or not.
+ */
+ || !strcasecmp(headers_in[counter].key,"Proxy-Authorization")
+ || !strcasecmp(headers_in[counter].key,"Proxy-Authenticate")) {
+ continue;
+ }
- /* XXX: @@@ FIXME: "Proxy-Authorization" should *only* be
- * suppressed if THIS server requested the authentication,
- * not when a frontend proxy requested it!
- *
- * The solution to this problem is probably to strip out
- * the Proxy-Authorisation header in the authorisation
- * code itself, not here. This saves us having to signal
- * somehow whether this request was authenticated or not.
+ /* Skip Transfer-Encoding and Content-Length for now.
*/
- || !apr_strnatcasecmp(headers_in[counter].key,"Proxy-Authorization")
- || !apr_strnatcasecmp(headers_in[counter].key,"Proxy-Authenticate")) {
+ if (!strcasecmp(headers_in[counter].key, "Transfer-Encoding")) {
+ old_te_val = headers_in[counter].val;
+ continue;
+ }
+ if (!strcasecmp(headers_in[counter].key, "Content-Length")) {
+ old_cl_val = headers_in[counter].val;
continue;
}
+
/* for sub-requests, ignore freshness/expiry headers */
if (r->main) {
- if (headers_in[counter].key == NULL || headers_in[counter].val == NULL
- || !apr_strnatcasecmp(headers_in[counter].key, "If-Match")
- || !apr_strnatcasecmp(headers_in[counter].key, "If-Modified-Since")
- || !apr_strnatcasecmp(headers_in[counter].key, "If-Range")
- || !apr_strnatcasecmp(headers_in[counter].key, "If-Unmodified-Since")
- || !apr_strnatcasecmp(headers_in[counter].key, "If-None-Match")) {
- continue;
- }
-
- /* If you POST to a page that gets server-side parsed
- * by mod_include, and the parsing results in a reverse
- * proxy call, the proxied request will be a GET, but
- * its request_rec will have inherited the Content-Length
- * of the original request (the POST for the enclosing
- * page). We can't send the original POST's request body
- * as part of the proxied subrequest, so we need to avoid
- * sending the corresponding content length. Otherwise,
- * the server to which we're proxying will sit there
- * forever, waiting for a request body that will never
- * arrive.
- */
- if ((r->method_number == M_GET) && headers_in[counter].key &&
- !apr_strnatcasecmp(headers_in[counter].key,
- "Content-Length")) {
- continue;
- }
+ if ( !strcasecmp(headers_in[counter].key, "If-Match")
+ || !strcasecmp(headers_in[counter].key, "If-Modified-Since")
+ || !strcasecmp(headers_in[counter].key, "If-Range")
+ || !strcasecmp(headers_in[counter].key, "If-Unmodified-Since")
+ || !strcasecmp(headers_in[counter].key, "If-None-Match")) {
+ continue;
+ }
}
-
buf = apr_pstrcat(p, headers_in[counter].key, ": ",
headers_in[counter].val, CRLF,
NULL);
ap_xlate_proto_to_ascii(buf, strlen(buf));
e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc);
- APR_BRIGADE_INSERT_TAIL(bb, e);
+ APR_BRIGADE_INSERT_TAIL(header_brigade, e);
+ }
+
+ /* We have headers, let's figure out our request body... */
+ input_brigade = apr_brigade_create(p, bucket_alloc);
+
+ /* sub-requests never use keepalives, and mustn't pass request bodies.
+ * Because the new logic looks at input_brigade, we will self-terminate
+ * input_brigade and jump past all of the request body logic...
+ * Reading anything with ap_get_brigade is likely to consume the
+ * main request's body or read beyond EOS - which would be unplesant.
+ */
+ if (r->main) {
+ p_conn->close++;
+ if (old_cl_val) {
+ old_cl_val = NULL;
+ apr_table_unset(r->headers_in, "Content-Length");
+ }
+ if (old_te_val) {
+ old_te_val = NULL;
+ apr_table_unset(r->headers_in, "Transfer-Encoding");
+ }
+ rb_method = RB_STREAM_CL;
+ e = apr_bucket_eos_create(input_brigade->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(input_brigade, e);
+ goto skip_body;
+ }
+
+ /* WE only understand chunked. Other modules might inject
+ * (and therefore, decode) other flavors but we don't know
+ * that the can and have done so unless they they remove
+ * their decoding from the headers_in T-E list.
+ * XXX: Make this extensible, but in doing so, presume the
+ * encoding has been done by the extensions' handler, and
+ * do not modify add_te_chunked's logic
+ */
+ if (old_te_val && strcmp(old_te_val, "chunked") != 0) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+ "proxy: %s Transfer-Encoding is not supported",
+ old_te_val);
+ return APR_EINVAL;
+ }
+
+ if (old_cl_val && old_te_val) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_ENOTIMPL, r->server,
+ "proxy: client %s (%s) requested Transfer-Encoding body"
+ " with Content-Length (C-L ignored)",
+ c->remote_ip, c->remote_host ? c->remote_host: "");
+ apr_table_unset(r->headers_in, "Content-Length");
+ old_cl_val = NULL;
+ origin->keepalive = AP_CONN_CLOSE;
+ p_conn->close++;
+ }
+
+ /* Prefetch MAX_MEM_SPOOL bytes
+ *
+ * This helps us avoid any election of C-L v.s. T-E
+ * request bodies, since we are willing to keep in
+ * memory this much data, in any case. This gives
+ * us an instant C-L election if the body is of some
+ * reasonable size.
+ */
+ temp_brigade = apr_brigade_create(p, bucket_alloc);
+ do {
+ status = ap_get_brigade(r->input_filters, temp_brigade,
+ AP_MODE_READBYTES, APR_BLOCK_READ,
+ MAX_MEM_SPOOL - bytes_read);
+ if (status != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
+ "proxy: prefetch request body failed to %s"
+ " from %s (%s)",
+ p_conn->name ? p_conn->name: "",
+ c->remote_ip, c->remote_host ? c->remote_host: "");
+ return status;
+ }
+
+ apr_brigade_length(temp_brigade, 1, &bytes);
+ APR_BRIGADE_CONCAT(input_brigade, temp_brigade);
+ bytes_read += bytes;
+
+ /* Ensure we don't hit a wall where we have a buffer too small
+ * for ap_get_brigade's filters to fetch us another bucket,
+ * surrender once we hit 80 bytes less than MAX_MEM_SPOOL
+ * (an arbitrary value.)
+ */
+ } while ((bytes_read < MAX_MEM_SPOOL - 80)
+ && !APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade)));
+
+ /* Use chunked request body encoding or send a content-length body?
+ *
+ * Prefer C-L when:
+ *
+ * We have no request body (handled by RB_STREAM_CL)
+ *
+ * We have a request body length <= MAX_MEM_SPOOL
+ *
+ * The administrator has setenv force-proxy-request-1.0
+ *
+ * The client sent a C-L body, and the administrator has
+ * not setenv proxy-sendchunked or has set setenv proxy-sendcl
+ *
+ * The client sent a T-E body, and the administrator has
+ * setenv proxy-sendcl, and not setenv proxy-sendchunked
+ *
+ * If both proxy-sendcl and proxy-sendchunked are set, the
+ * behavior is the same as if neither were set, large bodies
+ * that can't be read will be forwarded in their original
+ * form of C-L, or T-E.
+ *
+ * To ensure maximum compatibility, setenv proxy-sendcl
+ * To reduce server resource use, setenv proxy-sendchunked
+ *
+ * Then address specific servers with conditional setenv
+ * options to restore the default behavior where desireable.
+ *
+ * We have to compute content length by reading the entire request
+ * body; if request body is not small, we'll spool the remaining
+ * input to a temporary file. Chunked is always preferable.
+ *
+ * We can only trust the client-provided C-L if the T-E header
+ * is absent, and the filters are unchanged (the body won't
+ * be resized by another content filter).
+ */
+ if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) {
+ /* The whole thing fit, so our decision is trivial, use
+ * the filtered bytes read from the client for the request
+ * body Content-Length.
+ *
+ * If we expected no body, and read no body, do not set
+ * the Content-Length.
+ */
+ if (old_cl_val || old_te_val || bytes_read) {
+ old_cl_val = apr_off_t_toa(r->pool, bytes_read);
+ }
+ rb_method = RB_STREAM_CL;
+ }
+ else if (old_te_val) {
+ if (force10
+ || (apr_table_get(r->subprocess_env, "proxy-sendcl")
+ && !apr_table_get(r->subprocess_env, "proxy-sendchunks"))) {
+ rb_method = RB_SPOOL_CL;
+ }
+ else {
+ rb_method = RB_STREAM_CHUNKED;
+ }
+ }
+ else if (old_cl_val) {
+ if (r->input_filters == r->proto_input_filters) {
+ rb_method = RB_STREAM_CL;
+ }
+ else if (!force10
+ && apr_table_get(r->subprocess_env, "proxy-sendchunks")
+ && !apr_table_get(r->subprocess_env, "proxy-sendcl")) {
+ rb_method = RB_STREAM_CHUNKED;
+ }
+ else {
+ rb_method = RB_SPOOL_CL;
+ }
+ }
+ else {
+ /* This is an appropriate default; very efficient for no-body
+ * requests, and has the behavior that it will not add any C-L
+ * when the old_cl_val is NULL.
+ */
+ rb_method = RB_SPOOL_CL;
+ }
+
+/* Yes I hate gotos. This is the subrequest shortcut */
+skip_body:
+ /* Handle Connection: header */
+ if (!force10 && p_conn->close) {
+ buf = apr_pstrdup(p, "Connection: close" CRLF);
+ ap_xlate_proto_to_ascii(buf, strlen(buf));
+ e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(header_brigade, e);
+ }
+
+ /* send the request body, if any. */
+ switch(rb_method) {
+ case RB_STREAM_CHUNKED:
+ status = stream_reqbody_chunked(p, r, p_conn, origin, header_brigade,
+ input_brigade);
+ break;
+ case RB_STREAM_CL:
+ status = stream_reqbody_cl(p, r, p_conn, origin, header_brigade,
+ input_brigade, old_cl_val);
+ break;
+ case RB_SPOOL_CL:
+ status = spool_reqbody_cl(p, r, p_conn, origin, header_brigade,
+ input_brigade, (old_cl_val != NULL)
+ || (old_te_val != NULL)
+ || (bytes_read > 0));
+ break;
+ default:
+ ap_assert(1 != 1);
+ break;
}
- /* send the request data, if any. */
- status = send_request_body(p, r, p_conn, origin, bb, force10);
if (status != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
- "proxy: request failed to %pI (%s)",
- p_conn->addr, p_conn->name);
+ "proxy: pass request body failed to %pI (%s)"
+ " from %s (%s)",
+ p_conn->addr, p_conn->name ? p_conn->name: "",
+ c->remote_ip, c->remote_host ? c->remote_host: "");
return status;
}
@@ -1102,6 +1224,7 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r,
char *server_portstr) {
conn_rec *c = r->connection;
char buffer[HUGE_STRING_LEN];
+ const char *buf;
char keepchar;
request_rec *rp;
apr_bucket *e;
@@ -1140,9 +1263,9 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r,
"Error reading from remote server");
}
- /* Is it an HTTP/1 response?
- * This is buggy if we ever see an HTTP/1.10
- */
+ /* Is it an HTTP/1 response?
+ * This is buggy if we ever see an HTTP/1.10
+ */
if (apr_date_checkmask(buffer, "HTTP/#.# ###*")) {
int major, minor;
@@ -1177,7 +1300,6 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r,
}
r->status_line = apr_pstrdup(p, &buffer[9]);
-
/* read the headers. */
/* N.B. for HTTP/1.0 clients, we have to fold line-wrapped headers*/
/* Also, take care with headers with multiple occurences. */
@@ -1199,35 +1321,32 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r,
r->status = HTTP_BAD_GATEWAY;
r->status_line = "bad gateway";
return r->status;
+ }
- } else {
- const char *buf;
-
- /* can't have both Content-Length and Transfer-Encoding */
- if (apr_table_get(r->headers_out, "Transfer-Encoding")
- && apr_table_get(r->headers_out, "Content-Length")) {
- /* 2616 section 4.4, point 3: "if both Transfer-Encoding
- * and Content-Length are received, the latter MUST be
- * ignored"; so unset it here to prevent any confusion
- * later. */
- apr_table_unset(r->headers_out, "Content-Length");
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
- r->server,
- "proxy: server %s returned Transfer-Encoding and Content-Length",
- p_conn->name);
- p_conn->close += 1;
- }
-
- /* strip connection listed hop-by-hop headers from response */
- p_conn->close += ap_proxy_liststr(apr_table_get(r->headers_out,
- "Connection"),
- "close");
- ap_proxy_clear_connection(p, r->headers_out);
- if ((buf = apr_table_get(r->headers_out, "Content-Type"))) {
- ap_set_content_type(r, apr_pstrdup(p, buf));
- }
- ap_proxy_pre_http_request(origin,rp);
+ /* can't have both Content-Length and Transfer-Encoding */
+ if (apr_table_get(r->headers_out, "Transfer-Encoding")
+ && apr_table_get(r->headers_out, "Content-Length")) {
+ /* 2616 section 4.4, point 3: "if both Transfer-Encoding
+ * and Content-Length are received, the latter MUST be
+ * ignored"; so unset it here to prevent any confusion
+ * later. */
+ apr_table_unset(r->headers_out, "Content-Length");
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
+ r->server,
+ "proxy: server %s returned Transfer-Encoding and Content-Length",
+ p_conn->name);
+ p_conn->close += 1;
}
+
+ /* strip connection listed hop-by-hop headers from response */
+ p_conn->close += ap_proxy_liststr(apr_table_get(r->headers_out,
+ "Connection"),
+ "close");
+ ap_proxy_clear_connection(p, r->headers_out);
+ if ((buf = apr_table_get(r->headers_out, "Content-Type"))) {
+ ap_set_content_type(r, apr_pstrdup(p, buf));
+ }
+ ap_proxy_pre_http_request(origin,rp);
/* handle Via header in response */
if (conf->viaopt != via_off && conf->viaopt != via_block) {
@@ -1269,43 +1388,36 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r,
}
/* we must accept 3 kinds of date, but generate only 1 kind of date */
- {
- const char *buf;
- if ((buf = apr_table_get(r->headers_out, "Date")) != NULL) {
- apr_table_set(r->headers_out, "Date",
- ap_proxy_date_canon(p, buf));
- }
- if ((buf = apr_table_get(r->headers_out, "Expires")) != NULL) {
- apr_table_set(r->headers_out, "Expires",
- ap_proxy_date_canon(p, buf));
- }
- if ((buf = apr_table_get(r->headers_out, "Last-Modified")) != NULL) {
- apr_table_set(r->headers_out, "Last-Modified",
- ap_proxy_date_canon(p, buf));
- }
+ if ((buf = apr_table_get(r->headers_out, "Date")) != NULL) {
+ apr_table_set(r->headers_out, "Date",
+ ap_proxy_date_canon(p, buf));
+ }
+ if ((buf = apr_table_get(r->headers_out, "Expires")) != NULL) {
+ apr_table_set(r->headers_out, "Expires",
+ ap_proxy_date_canon(p, buf));
+ }
+ if ((buf = apr_table_get(r->headers_out, "Last-Modified")) != NULL) {
+ apr_table_set(r->headers_out, "Last-Modified",
+ ap_proxy_date_canon(p, buf));
}
/* munge the Location and URI response headers according to
* ProxyPassReverse
*/
- {
- const char *buf;
- if ((buf = apr_table_get(r->headers_out, "Location")) != NULL) {
- apr_table_set(r->headers_out, "Location",
- ap_proxy_location_reverse_map(r, conf, buf));
- }
- if ((buf = apr_table_get(r->headers_out, "Content-Location")) != NULL) {
- apr_table_set(r->headers_out, "Content-Location",
- ap_proxy_location_reverse_map(r, conf, buf));
- }
- if ((buf = apr_table_get(r->headers_out, "URI")) != NULL) {
- apr_table_set(r->headers_out, "URI",
- ap_proxy_location_reverse_map(r, conf, buf));
- }
+ if ((buf = apr_table_get(r->headers_out, "Location")) != NULL) {
+ apr_table_set(r->headers_out, "Location",
+ ap_proxy_location_reverse_map(r, conf, buf));
+ }
+ if ((buf = apr_table_get(r->headers_out, "Content-Location")) != NULL) {
+ apr_table_set(r->headers_out, "Content-Location",
+ ap_proxy_location_reverse_map(r, conf, buf));
+ }
+ if ((buf = apr_table_get(r->headers_out, "URI")) != NULL) {
+ apr_table_set(r->headers_out, "URI",
+ ap_proxy_location_reverse_map(r, conf, buf));
}
if ((r->status == 401) && (conf->error_override != 0)) {
- const char *buf;
const char *wa = "WWW-Authenticate";
if ((buf = apr_table_get(r->headers_out, wa))) {
apr_table_set(r->err_headers_out, wa, buf);
diff --git a/server/core.c b/server/core.c
index e702b459c6..5e7bf1f20e 100644
--- a/server/core.c
+++ b/server/core.c
@@ -458,6 +458,8 @@ static void *create_core_server_config(apr_pool_t *a, server_rec *s)
conf->redirect_limit = 0; /* 0 == unset */
conf->subreq_limit = 0;
+ conf->trace_enable = AP_TRACE_UNSET;
+
return (void *)conf;
}
@@ -489,6 +491,10 @@ static void *merge_core_server_configs(apr_pool_t *p, void *basev, void *virtv)
? virt->subreq_limit
: base->subreq_limit;
+ conf->trace_enable = (virt->trace_enable != AP_TRACE_UNSET)
+ ? virt->trace_enable
+ : base->trace_enable;
+
return conf;
}
@@ -1587,7 +1593,7 @@ AP_CORE_DECLARE_NONSTD(const char *) ap_limit_section(cmd_parms *cmd,
methnum = ap_method_number_of(method);
if (methnum == M_TRACE && !tog) {
- return "TRACE cannot be controlled by <Limit>";
+ return "TRACE cannot be controlled by <Limit>, see TraceEnable";
}
else if (methnum == M_INVALID) {
/* method has not been registered yet, but resorce restriction
@@ -3121,6 +3127,28 @@ static apr_status_t emulate_sendfile(core_net_rec *c, apr_file_t *fd,
return rv;
}
+static const char *set_trace_enable(cmd_parms *cmd, void *dummy,
+ const char *arg1)
+{
+ core_server_config *conf = ap_get_module_config(cmd->server->module_config,
+ &core_module);
+
+ if (strcasecmp(arg1, "on") == 0) {
+ conf->trace_enable = AP_TRACE_ENABLE;
+ }
+ else if (strcasecmp(arg1, "off") == 0) {
+ conf->trace_enable = AP_TRACE_DISABLE;
+ }
+ else if (strcasecmp(arg1, "extended") == 0) {
+ conf->trace_enable = AP_TRACE_EXTENDED;
+ }
+ else {
+ return "TraceEnable must be one of 'on', 'off', or 'extended'";
+ }
+
+ return NULL;
+}
+
/* Note --- ErrorDocument will now work from .htaccess files.
* The AllowOverride of Fileinfo allows webmasters to turn it off
*/
@@ -3346,6 +3374,8 @@ AP_INIT_TAKE1("MaxMemFree", ap_mpm_set_max_mem_free, NULL, RSRC_CONF,
AP_INIT_TAKE1("EnableExceptionHook", ap_mpm_set_exception_hook, NULL, RSRC_CONF,
"Controls whether exception hook may be called after a crash"),
#endif
+AP_INIT_TAKE1("TraceEnable", set_trace_enable, NULL, RSRC_CONF,
+ "'on' (default), 'off' or 'extended' to trace request body content"),
{ NULL }
};
diff --git a/srclib/pcre/pcre.c b/srclib/pcre/pcre.c
index ad3ddc7c57..56e1b10649 100644
--- a/srclib/pcre/pcre.c
+++ b/srclib/pcre/pcre.c
@@ -714,7 +714,18 @@ read_repeat_counts(const uschar *p, int *minp, int *maxp,
int min = 0;
int max = -1;
+/* Read the minimum value and do a paranoid check: a negative value indicates
+an integer overflow. */
+
while ((cd->ctypes[*p] & ctype_digit) != 0) min = min * 10 + *p++ - '0';
+if (min < 0 || min > 65535)
+ {
+ *errorptr = ERR5;
+ return p;
+ }
+
+/* Read the maximum value if there is one, and again do a paranoid on its size.
+Also, max must not be less than min. */
if (*p == '}') max = min; else
{
@@ -722,6 +733,11 @@ if (*p == '}') max = min; else
{
max = 0;
while((cd->ctypes[*p] & ctype_digit) != 0) max = max * 10 + *p++ - '0';
+ if (max < 0 || max > 65535)
+ {
+ *errorptr = ERR5;
+ return p;
+ }
if (max < min)
{
*errorptr = ERR4;
@@ -730,16 +746,11 @@ if (*p == '}') max = min; else
}
}
-/* Do paranoid checks, then fill in the required variables, and pass back the
-pointer to the terminating '}'. */
+/* Fill in the required variables, and pass back the pointer to the terminating
+'}'. */
-if (min > 65535 || max > 65535)
- *errorptr = ERR5;
-else
- {
- *minp = min;
- *maxp = max;
- }
+*minp = min;
+*maxp = max;
return p;
}