Re: HEAD response's Content-Length stripped when zero

2015-05-07 Thread Yann Ylavic
On Wed, Apr 29, 2015 at 2:46 PM, Eric Covener cove...@gmail.com wrote:

 Maybe we could remember here if the CL was set by
 ap_content_length_filter or someone else?

I finally committed (in r1678215) a fix that moves all the logic in
ap_content_length_filter().

Thanks,
Yann.


Re: HEAD response's Content-Length stripped when zero

2015-04-29 Thread Eric Covener
On Wed, Apr 29, 2015 at 8:19 AM, Yann Ylavic ylavic@gmail.com wrote:
 Hence how about removing this whole block (is there any module today
 outsmarting httpd that cannot be considered as buggy?) or least
 disable it for forwarded responses, eg:

 Index: modules/http/http_filters.c
 ===
 --- modules/http/http_filters.c(revision 1676716)
 +++ modules/http/http_filters.c(working copy)
 @@ -1292,6 +1292,7 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_heade
   * The default (unset) behavior is to squelch the C-L in this case.
   */
  if (r-header_only
 + !r-proxyreq
   (clheader = apr_table_get(r-headers_out, Content-Length))
   !strcmp(clheader, 0)
   conf-http_cl_head_zero != AP_HTTP_CL_HEAD_ZERO_ENABLE) {


Maybe we could remember here if the CL was set by
ap_content_length_filter or someone else?

-- 
Eric Covener
cove...@gmail.com


HEAD response's Content-Length stripped when zero

2015-04-29 Thread Yann Ylavic
Due to ap_http_header_filter():

/* This is a hack, but I can't find anyway around it.  The idea is that
 * we don't want to send out 0 Content-Lengths if it is a head request.
 * This happens when modules try to outsmart the server, and return
 * if they see a HEAD request.  Apache 1.3 handlers were supposed to
 * just return in that situation, and the core handled the HEAD.  In
 * 2.0, if a handler returns, then the core sends an EOS bucket down
 * the filter stack, and the content-length filter computes a C-L of
 * zero and that gets put in the headers, and we end up sending a
 * zero C-L to the client.  We can't just remove the C-L filter,
 * because well behaved 2.0 handlers will send their data down the stack,
 * and we will compute a real C-L for the head request. RBB
 *
 * Allow modification of this behavior through the
 * HttpContentLengthHeadZero directive.
 *
 * The default (unset) behavior is to squelch the C-L in this case.
 */
if (r-header_only
 (clheader = apr_table_get(r-headers_out, Content-Length))
 !strcmp(clheader, 0)
 conf-http_cl_head_zero != AP_HTTP_CL_HEAD_ZERO_ENABLE) {
apr_table_unset(r-headers_out, Content-Length);
}

I find this workaround a bit too much hacky because Content-Length:
0 could be the real one for the corresponding GET request, either
given by a module or forwarded from a backend.

Hence how about removing this whole block (is there any module today
outsmarting httpd that cannot be considered as buggy?) or least
disable it for forwarded responses, eg:

Index: modules/http/http_filters.c
===
--- modules/http/http_filters.c(revision 1676716)
+++ modules/http/http_filters.c(working copy)
@@ -1292,6 +1292,7 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_heade
  * The default (unset) behavior is to squelch the C-L in this case.
  */
 if (r-header_only
+ !r-proxyreq
  (clheader = apr_table_get(r-headers_out, Content-Length))
  !strcmp(clheader, 0)
  conf-http_cl_head_zero != AP_HTTP_CL_HEAD_ZERO_ENABLE) {
--
?


Re: HEAD response's Content-Length stripped when zero

2015-04-29 Thread Yann Ylavic
On Wed, Apr 29, 2015 at 2:46 PM, Eric Covener cove...@gmail.com wrote:
 On Wed, Apr 29, 2015 at 8:19 AM, Yann Ylavic ylavic@gmail.com wrote:
 Hence how about removing this whole block (is there any module today
 outsmarting httpd that cannot be considered as buggy?) or least
 disable it for forwarded responses, eg:

 Index: modules/http/http_filters.c
 ===
 --- modules/http/http_filters.c(revision 1676716)
 +++ modules/http/http_filters.c(working copy)
 @@ -1292,6 +1292,7 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_heade
   * The default (unset) behavior is to squelch the C-L in this case.
   */
  if (r-header_only
 + !r-proxyreq
   (clheader = apr_table_get(r-headers_out, Content-Length))
   !strcmp(clheader, 0)
   conf-http_cl_head_zero != AP_HTTP_CL_HEAD_ZERO_ENABLE) {


 Maybe we could remember here if the CL was set by
 ap_content_length_filter or someone else?


Yes, I first thought about this, hence checking r-clength instead,
but that would probably require to initialize it to something like
UNSET (-1), or we still could not distinguish it from a zero length
set...

That would be:

Index: modules/http/http_core.c
===
--- modules/http/http_core.c(revision 1676716)
+++ modules/http/http_core.c(working copy)
@@ -254,6 +254,9 @@ static int ap_process_http_connection(conn_rec *c)

 static int http_create_request(request_rec *r)
 {
+/* Content-Length unset by default. */
+r-clength = -1;
+
 if (!r-main  !r-prev) {
 ap_add_output_filter_handle(ap_byterange_filter_handle,
 NULL, r, r-connection);
Index: modules/http/http_filters.c
===
--- modules/http/http_filters.c(revision 1676716)
+++ modules/http/http_filters.c(working copy)
@@ -1292,6 +1292,7 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_heade
  * The default (unset) behavior is to squelch the C-L in this case.
  */
 if (r-header_only
+ (r-clength  0)
  (clheader = apr_table_get(r-headers_out, Content-Length))
  !strcmp(clheader, 0)
  conf-http_cl_head_zero != AP_HTTP_CL_HEAD_ZERO_ENABLE) {
--


Re: HEAD response's Content-Length stripped when zero

2015-04-29 Thread Yann Ylavic
On Wed, Apr 29, 2015 at 2:46 PM, Eric Covener cove...@gmail.com wrote:
 On Wed, Apr 29, 2015 at 8:19 AM, Yann Ylavic ylavic@gmail.com wrote:
 Hence how about removing this whole block (is there any module today
 outsmarting httpd that cannot be considered as buggy?) or least
 disable it for forwarded responses, eg:

 Index: modules/http/http_filters.c
 ===
 --- modules/http/http_filters.c(revision 1676716)
 +++ modules/http/http_filters.c(working copy)
 @@ -1292,6 +1292,7 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_heade
   * The default (unset) behavior is to squelch the C-L in this case.
   */
  if (r-header_only
 + !r-proxyreq
   (clheader = apr_table_get(r-headers_out, Content-Length))
   !strcmp(clheader, 0)
   conf-http_cl_head_zero != AP_HTTP_CL_HEAD_ZERO_ENABLE) {


 Maybe we could remember here if the CL was set by
 ap_content_length_filter or someone else?

The patch below tries your proposal...

Set a note If we detect that the header_only CL is from the origin in
ap_content_length_filter(), and don't strip the Content-Length if that
note is set in ap_http_header_filter().
We could also avoid the note by setting r-clength = -1 instead in
ap_content_length_filter().

This should work both with buggy modules and the normal cases (including proxy).
I guess we wouldn't need HttpContentLengthHeadZero from r1554303
anymore (and several third-party patches that simply disable the whole
unconditionally).

Do it sound better?

Index: server/protocol.c
===
--- server/protocol.c(revision 1676716)
+++ server/protocol.c(working copy)
@@ -1533,7 +1533,7 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_content_le
  * We can only set a C-L in the response header if we haven't already
  * sent any buckets on to the next output filter for this request.
  */
-if (ctx-data_sent == 0  eos 
+if (ctx-data_sent == 0  eos) {
 /* don't whack the C-L if it has already been set for a HEAD
  * by something like proxy.  the brigade only has an EOS bucket
  * in this case, making r-bytes_sent zero.
@@ -1544,9 +1544,13 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_content_le
  * such filters update or remove the C-L header, and just use it
  * if present.
  */
-!(r-header_only  r-bytes_sent == 0 
-apr_table_get(r-headers_out, Content-Length))) {
-ap_set_content_length(r, r-bytes_sent);
+if (r-header_only  r-bytes_sent == 0 
+apr_table_get(r-headers_out, Content-Length)) {
+apr_table_setn(r-notes, origin-ho, 1);
+}
+else {
+ap_set_content_length(r, r-bytes_sent);
+}
 }

 ctx-data_sent = 1;
Index: modules/http/http_filters.c
===
--- modules/http/http_filters.c(revision 1676716)
+++ modules/http/http_filters.c(working copy)
@@ -1292,9 +1292,11 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_heade
  * The default (unset) behavior is to squelch the C-L in this case.
  */
 if (r-header_only
- (clheader = apr_table_get(r-headers_out, Content-Length))
- !strcmp(clheader, 0)
- conf-http_cl_head_zero != AP_HTTP_CL_HEAD_ZERO_ENABLE) {
+ !r-clength
+ !apr_table_get(r-notes, origin-ho)
+ (clheader = apr_table_get(r-headers_out, Content-Length))
+ !strcmp(clheader, 0)
+ conf-http_cl_head_zero != AP_HTTP_CL_HEAD_ZERO_ENABLE) {
 apr_table_unset(r-headers_out, Content-Length);
 }

--


Re: HEAD response's Content-Length stripped when zero

2015-04-29 Thread Yann Ylavic
(sorry for the patches spam / confused proposal)

On Wed, Apr 29, 2015 at 6:07 PM, Yann Ylavic ylavic@gmail.com wrote:
 We could also avoid the note by setting r-clength = -1 instead in
 ap_content_length_filter().

Another candidate could be r-sent_bodyct = 1, eg:

Index: server/protocol.c
===
--- server/protocol.c(revision 1676716)
+++ server/protocol.c(working copy)
@@ -1533,7 +1533,7 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_content_le
  * We can only set a C-L in the response header if we haven't already
  * sent any buckets on to the next output filter for this request.
  */
-if (ctx-data_sent == 0  eos 
+if (ctx-data_sent == 0  eos) {
 /* don't whack the C-L if it has already been set for a HEAD
  * by something like proxy.  the brigade only has an EOS bucket
  * in this case, making r-bytes_sent zero.
@@ -1544,9 +1544,16 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_content_le
  * such filters update or remove the C-L header, and just use it
  * if present.
  */
-!(r-header_only  r-bytes_sent == 0 
-apr_table_get(r-headers_out, Content-Length))) {
-ap_set_content_length(r, r-bytes_sent);
+if (r-header_only  r-bytes_sent == 0 
+apr_table_get(r-headers_out, Content-Length)) {
+/* Tell ap_http_header_filter() we don't want the C-L to
+ * be stripped (ie. the original no-body is sent now).
+ */
+r-sent_bodyct = 1;
+}
+else {
+ap_set_content_length(r, r-bytes_sent);
+}
 }

 ctx-data_sent = 1;
Index: modules/http/http_filters.c
===
--- modules/http/http_filters.c(revision 1676716)
+++ modules/http/http_filters.c(working copy)
@@ -1292,9 +1292,9 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_heade
  * The default (unset) behavior is to squelch the C-L in this case.
  */
 if (r-header_only
- (clheader = apr_table_get(r-headers_out, Content-Length))
- !strcmp(clheader, 0)
- conf-http_cl_head_zero != AP_HTTP_CL_HEAD_ZERO_ENABLE) {
+ !r-sent_bodyct
+ (clheader = apr_table_get(r-headers_out, Content-Length))
+ !strcmp(clheader, 0)) {
 apr_table_unset(r-headers_out, Content-Length);
 }

--


Re: HEAD response's Content-Length stripped when zero

2015-04-29 Thread Yann Ylavic
On Wed, Apr 29, 2015 at 3:17 PM, Yann Ylavic ylavic@gmail.com wrote:
 On Wed, Apr 29, 2015 at 2:46 PM, Eric Covener cove...@gmail.com wrote:
 On Wed, Apr 29, 2015 at 8:19 AM, Yann Ylavic ylavic@gmail.com wrote:
 Hence how about removing this whole block (is there any module today
 outsmarting httpd that cannot be considered as buggy?) or least
 disable it for forwarded responses, eg:

 Index: modules/http/http_filters.c
 ===
 --- modules/http/http_filters.c(revision 1676716)
 +++ modules/http/http_filters.c(working copy)
 @@ -1292,6 +1292,7 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_heade
   * The default (unset) behavior is to squelch the C-L in this case.
   */
  if (r-header_only
 + !r-proxyreq
   (clheader = apr_table_get(r-headers_out, Content-Length))
   !strcmp(clheader, 0)
   conf-http_cl_head_zero != AP_HTTP_CL_HEAD_ZERO_ENABLE) {


 Maybe we could remember here if the CL was set by
 ap_content_length_filter or someone else?


 Yes, I first thought about this, hence checking r-clength instead,

Hmm, I have read ap_content_length_filter() instead of
ap_set_content_length(), please forget about my previous answer(s)...
I need to think more about this.


Re: HEAD response's Content-Length stripped when zero

2015-04-29 Thread Yann Ylavic
On Wed, Apr 29, 2015 at 3:39 PM, Yann Ylavic ylavic@gmail.com wrote:
 On Wed, Apr 29, 2015 at 3:17 PM, Yann Ylavic ylavic@gmail.com wrote:
 On Wed, Apr 29, 2015 at 2:46 PM, Eric Covener cove...@gmail.com wrote:
 On Wed, Apr 29, 2015 at 8:19 AM, Yann Ylavic ylavic@gmail.com wrote:
 Hence how about removing this whole block (is there any module today
 outsmarting httpd that cannot be considered as buggy?) or least
 disable it for forwarded responses, eg:

 Index: modules/http/http_filters.c
 ===
 --- modules/http/http_filters.c(revision 1676716)
 +++ modules/http/http_filters.c(working copy)
 @@ -1292,6 +1292,7 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_heade
   * The default (unset) behavior is to squelch the C-L in this case.
   */
  if (r-header_only
 + !r-proxyreq
   (clheader = apr_table_get(r-headers_out, Content-Length))
   !strcmp(clheader, 0)
   conf-http_cl_head_zero != AP_HTTP_CL_HEAD_ZERO_ENABLE) {


 Maybe we could remember here if the CL was set by
 ap_content_length_filter or someone else?


 Yes, I first thought about this, hence checking r-clength instead,

 Hmm, I have read ap_content_length_filter() instead of
 ap_set_content_length(), please forget about my previous answer(s)...
 I need to think more about this.

Actually I found http://svn.apache.org/r1554303 which make it configurable.
Maybe we can backport it instead (why a MAJOR bump?? I'd like to see
it in 2.2.x too...).
I'd argue that the default should be HttpContentLengthHeadZero on
though (at least in trunk), still users of buggy/legacy modules could
turn it off.


Re: HEAD response's Content-Length stripped when zero

2015-04-29 Thread Yann Ylavic
On Wed, Apr 29, 2015 at 3:17 PM, Yann Ylavic ylavic@gmail.com wrote:
 Index: modules/http/http_filters.c
 ===
 --- modules/http/http_filters.c(revision 1676716)
 +++ modules/http/http_filters.c(working copy)
 @@ -1292,6 +1292,7 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_heade
   * The default (unset) behavior is to squelch the C-L in this case.
   */
  if (r-header_only
 + (r-clength  0)

We probably still require:
+ !r-proxyreq
since mod_proxy does not call ap_set_content_length().