-*- coding: utf-8 -*-
Changes with Apache 2.4.30
+ *) ab: Make the TLS layer aware that the underlying socket is nonblocking,
+ and use/handle POLLOUT where needed to avoid busy IOs and recover write
+ errors when appropriate. [Yann Ylavic]
+
+ *) ab: Keep reading nonblocking to exhaust TCP or SSL buffers when previous
+ read was incomplete (the SSL case can cause the next poll() to timeout
+ since data are buffered already). PR 61301 [Luca Toscano, Yann Ylavic]
+
*) mod_http2: avoid unnecessary data retrieval for a trace log. Allow certain
information retrievals on null bucket beams where it makes sense. [Stefan Eissing]
PATCHES ACCEPTED TO BACKPORT FROM TRUNK:
[ start all new proposals below, under PATCHES PROPOSED. ]
- *) ab: Keep reading nonblocking to exhaust TCP or SSL buffers when previous
- read was incomplete. PR 61301
- trunk patch: https://svn.apache.org/r1811649
- 2.4.x patch: trunk works modulo CHANGES
- svn merge -c 1811649 ^/httpd/httpd/trunk .
- +1: elukey, icing, ylavic
-
*) core, mod_rewrite: introduce the 'keeps-redirect-vary' note in the internal redirect
workflow to keep the Vary headers set by RewriteCond/Rule
directives combinations in the directory context. PR: 58231
2.4.x: svn merge -c 1811744 ^/httpd/httpd/trunk .
+1: elukey, icing, ylavic
- *) ab: Make the TLS layer aware that the underlying socket is nonblocking,
- and use/handle POLLOUT where needed to avoid busy IOs and recover write
- errors when appropriate.
- trunk patch: http://svn.apache.org/r1811664
- http://svn.apache.org/r1814118
- 2.4.x patch: trunk works (modulo CHANGES)
- svn merge -c 1811664,1814118 ^/httpd/httpd/trunk .
- +1: ylavic, jim, icing
-
PATCHES PROPOSED TO BACKPORT FROM TRUNK:
[ New proposals should be added at the end of the list ]
do_next = 0;
break;
case SSL_ERROR_WANT_WRITE:
- /* Try again */
- do_next = 1;
+ set_polled_events(c, APR_POLLOUT);
+ do_next = 0;
break;
case SSL_ERROR_WANT_CONNECT:
case SSL_ERROR_SSL:
#ifdef USE_SSL
if (c->ssl) {
- apr_size_t e_ssl;
- e_ssl = SSL_write(c->ssl,request + c->rwrote, l);
- if (e_ssl != l) {
- BIO_printf(bio_err, "SSL write failed - closing connection\n");
- ERR_print_errors(bio_err);
- close_connection (c);
+ e = SSL_write(c->ssl, request + c->rwrote, l);
+ if (e <= 0) {
+ switch (SSL_get_error(c->ssl, e)) {
+ case SSL_ERROR_WANT_READ:
+ set_polled_events(c, APR_POLLIN);
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ set_polled_events(c, APR_POLLOUT);
+ break;
+ default:
+ BIO_printf(bio_err, "SSL write failed - closing connection\n");
+ ERR_print_errors(bio_err);
+ close_connection (c);
+ break;
+ }
return;
}
- l = e_ssl;
- e = APR_SUCCESS;
+ l = e;
}
else
#endif
+ {
e = apr_socket_send(c->aprsock, request + c->rwrote, &l);
-
- if (e != APR_SUCCESS && !APR_STATUS_IS_EAGAIN(e)) {
- epipe++;
- printf("Send request failed!\n");
- close_connection(c);
- return;
+ if (e != APR_SUCCESS && !l) {
+ if (!APR_STATUS_IS_EAGAIN(e)) {
+ epipe++;
+ printf("Send request failed!\n");
+ close_connection(c);
+ }
+ else {
+ set_polled_events(c, APR_POLLOUT);
+ }
+ return;
+ }
}
totalposted += l;
c->rwrote += l;
ssl_rand_seed();
apr_os_sock_get(&fd, c->aprsock);
bio = BIO_new_socket(fd, BIO_NOCLOSE);
+ BIO_set_nbio(bio, 1);
SSL_set_bio(c->ssl, bio, bio);
SSL_set_connect_state(c->ssl);
if (verbosity >= 4) {
char respcode[4]; /* 3 digits and null */
r = sizeof(buffer);
+read_more:
#ifdef USE_SSL
if (c->ssl) {
status = SSL_read(c->ssl, buffer, r);
good++;
close_connection(c);
}
- else if (scode != SSL_ERROR_WANT_WRITE
- && scode != SSL_ERROR_WANT_READ) {
+ else if (scode == SSL_ERROR_WANT_READ) {
+ set_polled_events(c, APR_POLLIN);
+ }
+ else if (scode == SSL_ERROR_WANT_WRITE) {
+ set_polled_events(c, APR_POLLOUT);
+ }
+ else {
/* some fatal error: */
c->read = 0;
BIO_printf(bio_err, "SSL read failed (%d) - closing connection\n", scode);
c->bread += r;
totalbread += r;
}
+ if (r == sizeof(buffer) && c->bread < c->length) {
+ /* read was full, try more immediately (nonblocking already) */
+ goto read_more;
+ }
if (c->keepalive && (c->bread >= c->length)) {
/* finished a keep-alive connection */
c->read = c->bread = 0;
/* zero connect time with keep-alive */
c->start = c->connect = lasttime = apr_time_now();
+ set_conn_state(c, STATE_CONNECTED);
write_request(c);
}
}
}
if (rtnev & APR_POLLOUT) {
if (c->state == STATE_CONNECTING) {
+ /* call connect() again to detect errors */
rv = apr_socket_connect(c->aprsock, destsa);
if (rv != APR_SUCCESS) {
set_conn_state(c, STATE_UNCONNECTED);
}
}
else {
- write_request(c);
+ /* POLLOUT is one shot */
+ set_polled_events(c, APR_POLLIN);
+ if (c->state == STATE_READ) {
+ read_connection(c);
+ }
+ else {
+ write_request(c);
+ }
}
}
}