Hi,
I found a problem with non-blocking write to pipe.
Current code (2.0.43) is as following.
------------------------------------------------------------
httpd-2.0.43/srclib/apr/file_io/unix/readwrite.c:apr_file_write()
------------------------------------------------------------
do {
rv = write(thefile->filedes, buf, *nbytes);
} while (rv == (apr_size_t)-1 && errno == EINTR);
#ifdef USE_WAIT_FOR_IO
if (rv == (apr_size_t)-1 &&
(errno == EAGAIN || errno == EWOULDBLOCK) &&
thefile->timeout != 0) {
apr_status_t arv = apr_wait_for_io_or_timeout(thefile, NULL, 0);
if (arv != APR_SUCCESS) {
*nbytes = 0;
return arv;
}
else {
do {
rv = write(thefile->filedes, buf, *nbytes);
} while (rv == (apr_size_t)-1 && errno == EINTR);
}
}
#endif
------------------------------------------------------------
It seems assuming write request never fail when
apr_wait_for_io_or_timeout() succeeded, but it is not true
for pipe.
"The Single UNIXR Specification, Version 2" is saying :
------------------------------------------------------------
Write requests to a pipe or FIFO will be handled the same as
a regular file with the following exceptions:
[snip]
If the O_NONBLOCK flag is set, write() requests will be
handled differently, in the following ways:
- The write() function will not block the thread.
- A write request for {PIPE_BUF} or fewer bytes will have
the following effect: If there is sufficient space
available in the pipe, write() will transfer all the
data and return the number of bytes requested. Otherwise,
write() will transfer no data and return -1 with errno
set to [EAGAIN].
------------------------------------------------------------
It means that if room on the pipe is smaller than *nbyes and
*nbytes is less than or equal to {PIPE_BUF}, write() can
fail with errno=EAGAIN and return -1, and apr_file_write()
just fails.
I found this problem on HP-UX11.0 whose PIPE_BUF is 8192 with
CGI that receive more than 8kbytes POST request.
This problem can be fixed with the following code, however I
do not know if there is better solution other than looping.
------------------------------------------------------------
do {
rv = write(thefile->filedes, buf, *nbytes);
} while (rv == (apr_size_t)-1 && errno == EINTR);
#ifdef USE_WAIT_FOR_IO
if (rv == (apr_size_t)-1 &&
(errno == EAGAIN || errno == EWOULDBLOCK) &&
thefile->timeout != 0) {
apr_status_t arv = apr_wait_for_io_or_timeout(thefile, NULL, 0);
if (arv != APR_SUCCESS) {
*nbytes = 0;
return arv;
}
else {
do {
rv = write(thefile->filedes, buf, *nbytes);
/* write request of {PIPE_BUF} bytes or less may fail */
/* because it is atomic when writing to pipe or FIFO */
while (rv == (apr_size_t)-1 &&
*nbytes < PIPE_BUF && errno == EAGAIN)
{
apr_sleep(10000); /* sleep ~10ms */
rv = write(thefile->filedes, buf, *nbytes);
}
} while (rv == (apr_size_t)-1 && errno == EINTR);
}
}
#endif
------------------------------------------------------------
--
[EMAIL PROTECTED]