You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by co...@apache.org on 2020/02/05 23:05:44 UTC

svn commit: r1873675 - /httpd/httpd/trunk/docs/manual/mod/mod_headers.xml

Author: covener
Date: Wed Feb  5 23:05:44 2020
New Revision: 1873675

URL: http://svn.apache.org/viewvc?rev=1873675&view=rev
Log:
rework the mysteries of onsuccess and always

I thought I was well-versed in this topic but reading my own text and 
r1844401 while playing with samesite recipes made me want to rewrite it.

Pushed the advice down into the actions.


Modified:
    httpd/httpd/trunk/docs/manual/mod/mod_headers.xml

Modified: httpd/httpd/trunk/docs/manual/mod/mod_headers.xml
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/manual/mod/mod_headers.xml?rev=1873675&r1=1873674&r2=1873675&view=diff
==============================================================================
--- httpd/httpd/trunk/docs/manual/mod/mod_headers.xml (original)
+++ httpd/httpd/trunk/docs/manual/mod/mod_headers.xml Wed Feb  5 23:05:44 2020
@@ -330,68 +330,16 @@ available in 2.4.10 and later</compatibi
     <p> The optional <var>condition</var> argument determines which internal
     table of responses headers this directive will operate against:
     <code>onsuccess</code> (default, can be omitted) or <code>always</code>.
-    The difference between the two lists is that the headers contained in the
-    latter are added to the response even on error, and persisted across
-    internal redirects (for example, ErrorDocument handlers).
-
-    Note also that repeating this directive with both conditions makes sense in
-    some scenarios because <code>always</code> is not a superset of
-    <code>onsuccess</code> with respect to existing headers:</p>
-
-    <ul>
-       <li> You're adding a header to a locally generated non-success (non-2xx) response, such
-            as a redirect, in which case only the table corresponding to
-            <code>always</code> is used in the ultimate response.</li>
-       <li> You're modifying or removing a header generated by a CGI script
-            or by <module>mod_proxy_fcgi</module>,
-            in which case the CGI scripts' headers are in the table corresponding to
-            <code>always</code> and not in the default table.</li>
-       <li> You're modifying or removing a header generated by some piece of
-            the server but that header is not being found by the default
-            <code>onsuccess</code> condition.</li>
-    </ul>
-
-    <p>This difference between <code>onsuccess</code> and <code>always</code> is
-    a feature that resulted as a consequence of how httpd internally stores
-    headers for a HTTP response, since it does not offer any "normalized" single
-    list of headers. The main problem that can arise if the following concept
-    is not kept in mind while writing the configuration is that some HTTP responses
-    might end up with the same header duplicated (confusing users or sometimes even
-    HTTP clients). For example, suppose that you have a simple PHP proxy setup with
-    <module>mod_proxy_fcgi</module> and your backend PHP scripts adds the
-    <code>X-Foo: bar</code> header to each HTTP response. As described above,
-    <module>mod_proxy_fcgi</module> uses the <code>always</code> table to store
-    headers, so a configuration like the following ends up in the wrong result, namely
-    having the header duplicated with both values:</p>
-
-    <highlight language="config">
-# X-Foo's value is set in the 'onsuccess' headers table
-Header set X-Foo: baz
-    </highlight>    
-
-    <p>To circumvent this limitation, there are some known configuration
-    patterns that can help, like the following:</p>
-
-        <highlight language="config">
-# 'onsuccess' can be omitted since it is the default
-Header onsuccess unset X-Foo
-Header always set X-Foo "baz"
-        </highlight>
-
-    <p>Separately from the <var>condition</var> parameter described above, you
-    can limit an action based on HTTP status codes for e.g. proxied or CGI
-    requests. See the example that uses %{REQUEST_STATUS} in the section above.</p>
-
-    <p>The action it performs is determined by the first
-    argument (second argument if a <var>condition</var> is specified).
-    This can be one of the following values:</p>
+    Guidance on when to specify <code>always</code> is provided relative to each
+    action below. </p>
 
     <note type="warning"><title>Warning</title>
-        <p>Please read the difference between <code>always</code>
-        and <code>onsuccess</code> headers list described above
-        before start reading the actions list, since that important
-        concept still applies. Each action, in fact, works as described
-        but only on the target headers list.</p>
+        <p>Carefully read the difference between <code>always</code>
+        and <code>onsuccess</code> for each action listed below as the
+        behavior can be unintuitive and is a frequent source of confusion. 
+        Where the guidance suggest repeating the conditions, it is safe to try 
+        each experimentally and use the one you find effective to match the
+        pre-existing header.</p>
     </note>
 
     <dl>
@@ -400,19 +348,30 @@ Header always set X-Foo "baz"
     even if this header already exists. This can result in two
     (or more) headers having the same name. This can lead to
     unforeseen consequences, and in general <code>set</code>,
-    <code>append</code> or <code>merge</code> should be used instead.</dd>
+    <code>append</code> or <code>merge</code> should be used instead.
+    <p>Specify a condition of <code>always</code> if you want the header to
+    be included in non-2xx response (such as redirects or errors)</p>
+    </dd>
 
     <dt><code>append</code></dt>
     <dd>The response header is appended to any existing header of
     the same name. When a new value is merged onto an existing
     header it is separated from the existing header with a comma.
-    This is the HTTP standard way of giving a header multiple values.</dd>
+    This is the HTTP standard way of giving a header multiple values.
+    <p>If the header was added by this module, you must match the condition
+    parameter that was originally used. Otherwise, you must determine by trial
+    and error whether <code>always</code> should be specified because you can't
+    reliably know which internal table the existing value is present in.</p>
+    </dd>
 
     <dt><code>echo</code></dt>
     <dd>Request headers with this name are echoed back in the
     response headers. <var>header</var> may be a
     <glossary ref="regex">regular expression</glossary>.
-    <var>value</var> must be omitted.</dd>
+    <var>value</var> must be omitted.
+    <p>Specify a condition of <code>always</code> if you want the header to
+    be included in non-2xx response (such as redirects or errors).</p>
+    </dd>
 
     <dt><code>edit</code></dt>
     <dt><code>edit*</code></dt>
@@ -424,7 +383,11 @@ Header always set X-Foo "baz"
     The <code>edit</code> form will match and replace exactly once
     in a header value, whereas the <code>edit*</code> form will replace
     <em>every</em> instance of the search pattern if it appears more
-    than once.</dd>
+    than once.
+    <p>Because you cannot reliably know which internal header table might have a match,
+    you should repeat your edit/edit* directive with both <code>always</code> and
+    <code>onsuccess</code>.</p>
+    </dd>
 
     <dt><code>merge</code></dt>
     <dd>The response header is appended to any existing header of
@@ -434,15 +397,32 @@ Header always set X-Foo "baz"
     This is the HTTP standard way of giving a header multiple values.
     Values are compared in a case sensitive manner, and after
     all format specifiers have been processed.  Values in double quotes
-    are considered different from otherwise identical unquoted values.</dd>
+    are considered different from otherwise identical unquoted values.
+    <p>If the header was added by this module, you must match the condition
+    parameter that was originally used. Otherwise, you must determine by trial
+    and error whether <code>always</code> should be specified because you can't
+    reliably know which internal table the existing value is present in.</p>
+    </dd>
+
 
     <dt><code>set</code></dt>
     <dd>The response header is set, replacing any previous header
-    with this name. The <var>value</var> may be a format string.</dd>
+    with this name. The <var>value</var> may be a format string.
+    <p>If the header was added by this module, you must match the condition
+    parameter that was originally used. Otherwise, you must determine by trial
+    and error whether <code>always</code> should be specified because you can't
+    reliably know which internal table the existing value is present in.</p>
+    </dd>
+
 
     <dt><code>setifempty</code></dt>
     <dd>The request header is set, but only if there is no previous header
     with this name.
+    <p>If the header was added by this module, you must match the condition
+    parameter that was originally used. Otherwise, you must determine by trial
+    and error whether <code>always</code> should be specified because you can't
+    reliably know which internal table the existing value is present in.</p>
+
     <note>
     The Content-Type header is a special use case since there might be
     the chance that its value have been determined but the header is not part
@@ -454,17 +434,27 @@ Header always set X-Foo "baz"
     </highlight>
     </note></dd>
 
+
     <dt><code>unset</code></dt>
     <dd>The response header of this name is removed, if it exists.
     If there are multiple headers of the same name, all will be
-    removed. <var>value</var> must be omitted.</dd>
+    removed. <var>value</var> must be omitted.
+    <p>Because you cannot reliably know which internal header table might have a match,
+    you should repeat your this directive with both <code>always</code> and
+    <code>onsuccess</code>.</p>
+    </dd>
 
     <dt><code>note</code></dt>
     <dd>The value of the named response <var>header</var> is copied into an
     internal note whose name is given by <var>value</var>.  This is useful
     if a header sent by a CGI or proxied resource is configured to be unset
     but should also be logged.<br />
-    Available in 2.4.7 and later.</dd>
+    Available in 2.4.7 and later.
+    <p>If the header was added by this module, you must match the condition
+    parameter that was originally used. Otherwise, you must determine by trial
+    and error whether <code>always</code> should be specified because you can't
+    reliably know which internal table the existing value is present in.</p>
+    </dd>
 
     </dl>