Re: relayd status code handling

2017-11-17 Thread Rivo Nurges
Hi!

I have 4 digit number of relayd instances and I'v seen plenty of such
products. ownCloud, Nextcloud and some Atlassian products to name few.
relayd seems to be the only one to enforce the RFC so strictly. I'd be
glad if this gets relaxed a bit.

Rivo

On Fri, 2017-11-17 at 18:52 +0100, Sebastian Benoit wrote:
> Hi,
> 
> relayd enforces a rule in rfc section 3.3.2:
> 
> rfc 7230 3.3 Message Body
> 
>All 1xx (Informational), 204 (No Content), and 304 (Not Modified)
>responses do not include a message body.  All other responses do
>include a message body, although the body might be of zero length.
> 
> rfc 7230 3.3.2.  Content-Length
> 
>A server MUST NOT send a Content-Length header field in any
> response
>with a status code of 1xx (Informational) or 204 (No Content).  A
>server MUST NOT send a Content-Length header field in any 2xx
>(Successful) response to a CONNECT request (Section 4.3.6 of
>[RFC7231]).
> 
> 
> There is also this paragraph in Section 3.3.3 thats relevant:
> 
> 
>4.  If a message is received without Transfer-Encoding and with
>either multiple Content-Length header fields having differing
>field-values or a single Content-Length header field having an
>invalid value, then the message framing is invalid and the
>recipient MUST treat it as an unrecoverable error.  If this is
> a
>request message, the server MUST respond with a 400 (Bad
> Request)
>status code and then close the connection.  If this is a
> response
>message received by a proxy, the proxy MUST close the
> connection
>to the server, discard the received response, and send a 502
> (Bad
>Gateway) response to the client.  If this is a response
> message
>received by a user agent, the user agent MUST close the
>connection to the server and discard the received response.
> 
> 
> There are two problems with this:
> 
> * I have found a Tomcat Server that sends "204 No Content" with a
>   "Content-Length: 0" Header.
> 
> * Relayd sends the wrong HTTP Status Code, it should be 502 Bad
> Gateway
> 
> Here is a diff that relaxes the logic: send a 502 Bad Gateway, but
> only if Content-Length != 0.
> 
> ok?
> 
> diff --git usr.sbin/relayd/relay_http.c usr.sbin/relayd/relay_http.c
> index 3b6f8e84e37..ad45cf2d5d6 100644
> --- usr.sbin/relayd/relay_http.c
> +++ usr.sbin/relayd/relay_http.c
> @@ -324,19 +324,6 @@ relay_read_http(struct bufferevent *bev, void
> *arg)
>   relay_abort_http(con, 400,
> "malformed", 0);
>   goto abort;
>   }
> - /*
> -  * response with a status code of 1xx
> -  * (Informational) or 204 (No Content) MUST
> -  * not have a Content-Length (rfc 7230
> 3.3.3)
> -  */
> - if (desc->http_method ==
> HTTP_METHOD_RESPONSE && (
> - ((desc->http_status >= 100 &&
> - desc->http_status < 200) ||
> - desc->http_status == 204))) {
> - relay_abort_http(con, 500,
> - "Internal Server Error", 0);
> - goto abort;
> - }
>   /*
>* Need to read data from the client after
> the
>* HTTP header.
> @@ -349,6 +336,23 @@ relay_read_http(struct bufferevent *bev, void
> *arg)
>   relay_abort_http(con, 500, errstr,
> 0);
>   goto abort;
>   }
> + /*
> +  * response with a status code of 1xx
> +  * (Informational) or 204 (No Content) MUST
> +  * not have a Content-Length (rfc 7230
> 3.3.3)
> +  * Instead we check for value != 0 because
> there are
> +  * servers that do not follow the rfc and
> send
> +  * Content-Length: 0.
> +  */
> + if (desc->http_method ==
> HTTP_METHOD_RESPONSE && (
> + ((desc->http_status >= 100 &&
> + desc->http_status < 200) ||
> + desc->http_status == 204)) &&
> + cre->toread != 0) {
> + relay_abort_http(con, 502,
> + "Bad Gateway", 0);
> + goto abort;
> + }
>   }
>   lookup:
>   if (strcasecmp("Transfer-Encoding", key) == 0 &&
> 

relayd status code handling

2017-11-17 Thread Sebastian Benoit
Hi,

relayd enforces a rule in rfc section 3.3.2:

rfc 7230 3.3 Message Body

   All 1xx (Informational), 204 (No Content), and 304 (Not Modified)
   responses do not include a message body.  All other responses do
   include a message body, although the body might be of zero length.

rfc 7230 3.3.2.  Content-Length

   A server MUST NOT send a Content-Length header field in any response
   with a status code of 1xx (Informational) or 204 (No Content).  A
   server MUST NOT send a Content-Length header field in any 2xx
   (Successful) response to a CONNECT request (Section 4.3.6 of
   [RFC7231]).


There is also this paragraph in Section 3.3.3 thats relevant:


   4.  If a message is received without Transfer-Encoding and with
   either multiple Content-Length header fields having differing
   field-values or a single Content-Length header field having an
   invalid value, then the message framing is invalid and the
   recipient MUST treat it as an unrecoverable error.  If this is a
   request message, the server MUST respond with a 400 (Bad Request)
   status code and then close the connection.  If this is a response
   message received by a proxy, the proxy MUST close the connection
   to the server, discard the received response, and send a 502 (Bad
   Gateway) response to the client.  If this is a response message
   received by a user agent, the user agent MUST close the
   connection to the server and discard the received response.


There are two problems with this:

* I have found a Tomcat Server that sends "204 No Content" with a
  "Content-Length: 0" Header.

* Relayd sends the wrong HTTP Status Code, it should be 502 Bad Gateway

Here is a diff that relaxes the logic: send a 502 Bad Gateway, but
only if Content-Length != 0.

ok?

diff --git usr.sbin/relayd/relay_http.c usr.sbin/relayd/relay_http.c
index 3b6f8e84e37..ad45cf2d5d6 100644
--- usr.sbin/relayd/relay_http.c
+++ usr.sbin/relayd/relay_http.c
@@ -324,19 +324,6 @@ relay_read_http(struct bufferevent *bev, void *arg)
relay_abort_http(con, 400, "malformed", 0);
goto abort;
}
-   /*
-* response with a status code of 1xx
-* (Informational) or 204 (No Content) MUST
-* not have a Content-Length (rfc 7230 3.3.3)
-*/
-   if (desc->http_method == HTTP_METHOD_RESPONSE && (
-   ((desc->http_status >= 100 &&
-   desc->http_status < 200) ||
-   desc->http_status == 204))) {
-   relay_abort_http(con, 500,
-   "Internal Server Error", 0);
-   goto abort;
-   }
/*
 * Need to read data from the client after the
 * HTTP header.
@@ -349,6 +336,23 @@ relay_read_http(struct bufferevent *bev, void *arg)
relay_abort_http(con, 500, errstr, 0);
goto abort;
}
+   /*
+* response with a status code of 1xx
+* (Informational) or 204 (No Content) MUST
+* not have a Content-Length (rfc 7230 3.3.3)
+* Instead we check for value != 0 because there are
+* servers that do not follow the rfc and send
+* Content-Length: 0.
+*/
+   if (desc->http_method == HTTP_METHOD_RESPONSE && (
+   ((desc->http_status >= 100 &&
+   desc->http_status < 200) ||
+   desc->http_status == 204)) &&
+   cre->toread != 0) {
+   relay_abort_http(con, 502,
+   "Bad Gateway", 0);
+   goto abort;
+   }
}
  lookup:
if (strcasecmp("Transfer-Encoding", key) == 0 &&