[mod_proxy,mod_scgi] shutdown remote only if local (#2743)

shutdown(fd, SHUT_WR) after sending request to proxy or SCGI
only if remote is local and platform is not *BSD or Darwin.

The reason this fix is special-casing *BSD and Darwin is that the Single
Unix Specification and POSIX.1-2013 clearly specify that POLLHUP event
should be returned by poll only when the stream is no longer writable.
A half-closed socket that is still writable clearly does not match that
condition, yet that is what I am seeing on Darwin (El Capitan), and
presumably what others are seeing on *BSD, from which Apple originally
inherited the Darwin TCP stack.

Single Unix Specification (SUSv2) from 1997
(yes, that is nearly 20 years ago):
http://pubs.opengroup.org/onlinepubs/007908799/xsh/poll.html

    POLLHUP
    The device has been disconnected. This event and POLLOUT are
    mutually exclusive; a stream can never be writable if a hangup has
    occurred. However, this event and POLLIN, POLLRDNORM, POLLRDBAND or
    POLLPRI are not mutually exclusive. This flag is only valid in the
    revents bitmask; it is ignored in the events member.

Updated version of The Open Group Base Specifications Issue 7
(published in 2013):
http://pubs.opengroup.org/onlinepubs/9699919799/

    POLLHUP
    A device has been disconnected, or a pipe or FIFO has been closed
    by the last process that had it open for writing. Once set, the
    hangup state of a FIFO shall persist until some process opens the
    FIFO for writing or until all read-only file descriptors for the
    FIFO are closed.  This event and POLLOUT are mutually-exclusive;
    a stream can never be writable if a hangup has occurred. However,
    this event and POLLIN, POLLRDNORM, POLLRDBAND, or POLLPRI are not
    mutually-exclusive. This flag is only valid in the revents bitmask;
    it shall be ignored in the events member.

x-ref:
  "1.4.40/41 mod_proxy, mod_scgi may trigger POLLHUP on *BSD,Darwin"
  https://redmine.lighttpd.net/issues/2743
personal/stbuehler/mod-csrf-old
Glenn Strauss 2016-08-06 02:04:48 -04:00
parent 156bea3859
commit 1de652f40b
2 changed files with 28 additions and 2 deletions

View File

@ -854,7 +854,20 @@ static handler_t proxy_write_request(server *srv, handler_ctx *hctx) {
if (hctx->wb->bytes_out == hctx->wb_reqlen) {
fdevent_event_clr(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
shutdown(hctx->fd, SHUT_WR);/* future: remove if HTTP/1.1 request */
#if (defined(__APPLE__) && defined(__MACH__)) \
|| defined(__FreeBSD__) || defined(__NetBSD__) \
|| defined(__OpenBSD__) || defined(__DragonflyBSD__)
/*(*BSD stack on remote might signal POLLHUP and remote
* might treat as socket error instead of half-close)*/
#else
/*(remote could be different machine running affected OS,
* so only issue shutdown for known local sockets)*/
if ( '/' == host->host->ptr[0]
|| buffer_is_equal_string(host->host, CONST_STR_LEN("127.0.0.1"))
|| buffer_is_equal_string(host->host, CONST_STR_LEN("::1"))) {
shutdown(hctx->fd, SHUT_WR);/* future: remove if HTTP/1.1 request */
}
#endif
proxy_set_state(srv, hctx, PROXY_STATE_READ);
} else {
off_t wblen = hctx->wb->bytes_in - hctx->wb->bytes_out;

View File

@ -2438,7 +2438,20 @@ static handler_t scgi_write_request(server *srv, handler_ctx *hctx) {
if (hctx->wb->bytes_out == hctx->wb_reqlen) {
fdevent_event_clr(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
shutdown(hctx->fd, SHUT_WR);
#if (defined(__APPLE__) && defined(__MACH__)) \
|| defined(__FreeBSD__) || defined(__NetBSD__) \
|| defined(__OpenBSD__) || defined(__DragonflyBSD__)
/*(*BSD stack on remote might signal POLLHUP and remote
* might treat as socket error instead of half-close)*/
#else
/*(remote could be different machine running affected OS,
* so only issue shutdown for known local sockets)*/
if ( '/' == host->host->ptr[0]
|| buffer_is_equal_string(host->host, CONST_STR_LEN("127.0.0.1"))
|| buffer_is_equal_string(host->host, CONST_STR_LEN("::1"))) {
shutdown(hctx->fd, SHUT_WR);
}
#endif
scgi_set_state(srv, hctx, FCGI_STATE_READ);
} else {
off_t wblen = hctx->wb->bytes_in - hctx->wb->bytes_out;