--- modules/proxy/mod_proxy_fcgi.c +++ modules/proxy/mod_proxy_fcgi.c @@ -444,7 +444,7 @@ apr_uint16_t request_id, const char **err, int *bad_request, int *has_responded) { - apr_bucket_brigade *ib, *ob; + apr_bucket_brigade *ib, *ob, *cib; int seen_end_of_headers = 0, done = 0, ignore_body = 0; apr_status_t rv = APR_SUCCESS; int script_error_status = HTTP_OK; @@ -452,7 +452,7 @@ struct iovec vec[2]; ap_fcgi_header header; unsigned char farray[AP_FCGI_HEADER_LEN]; - apr_pollfd_t pfd; + apr_pollfd_t pfd[2]; int header_state = HDR_STATE_READING_HEADERS; char stack_iobuf[AP_IOBUFSIZE]; apr_size_t iobuf_size = AP_IOBUFSIZE; @@ -464,13 +464,21 @@ iobuf = apr_palloc(r->pool, iobuf_size); } - pfd.desc_type = APR_POLL_SOCKET; - pfd.desc.s = conn->sock; - pfd.p = r->pool; - pfd.reqevents = APR_POLLIN | APR_POLLOUT; + pfd[0].desc_type = APR_POLL_SOCKET; + pfd[0].desc.s = conn->sock; + pfd[0].p = r->pool; + pfd[0].reqevents = APR_POLLIN | APR_POLLOUT; + /* Specific pollfd to detect client connection aborts */ + pfd[1].desc_type = APR_POLL_SOCKET; + pfd[1].desc.s = (apr_socket_t*) ap_get_module_config(r->connection->conn_config, + &core_module); + pfd[1].p = r->connection->pool; + pfd[1].reqevents = APR_POLLIN; + ib = apr_brigade_create(r->pool, c->bucket_alloc); ob = apr_brigade_create(r->pool, c->bucket_alloc); + cib = apr_brigade_create(r->connection->pool, c->bucket_alloc); while (! done) { apr_interval_time_t timeout; @@ -481,7 +489,7 @@ * cause timeout errors. */ apr_socket_timeout_get(conn->sock, &timeout); - rv = apr_poll(&pfd, 1, &n, timeout); + rv = apr_poll(pfd, 2, &n, timeout); if (rv != APR_SUCCESS) { if (APR_STATUS_IS_EINTR(rv)) { continue; @@ -490,7 +498,7 @@ break; } - if (pfd.rtnevents & APR_POLLOUT) { + if (pfd[0].rtnevents & APR_POLLOUT) { apr_size_t to_send, writebuflen; int last_stdin = 0; char *iobuf_cursor; @@ -555,7 +563,7 @@ } if (last_stdin) { - pfd.reqevents = APR_POLLIN; /* Done with input data */ + pfd[0].reqevents = APR_POLLIN; /* Done with input data */ /* signal EOF (empty FCGI_STDIN) */ ap_fcgi_fill_in_header(&header, AP_FCGI_STDIN, request_id, @@ -573,7 +581,36 @@ } } - if (pfd.rtnevents & APR_POLLIN) { + /* + * If a client connection abort is detected, + * a FCGI abort request (AP_FCGI_ABORT_REQUEST) + * is issued. This helps aborting FCGI scripts taking + * a long time to complete when the client does not + * need their response anymore. + */ + if (pfd[1].rtnevents & APR_POLLIN) { + rv = ap_get_brigade(r->connection->input_filters, cib, + AP_MODE_SPECULATIVE, APR_NONBLOCK_READ, 8); + if(rv != APR_SUCCESS && rv != APR_EAGAIN) { + ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, + "Error reading from the input filters chain, " + "sending FCGI_ABORT_REQUEST"); + ap_fcgi_fill_in_header(&header, AP_FCGI_ABORT_REQUEST, + request_id, 0, 0); + ap_fcgi_header_to_array(&header, farray); + vec[0].iov_base = (void *)farray; + vec[0].iov_len = sizeof(farray); + apr_status_t rv_abort = send_data(conn, vec, 1, &len); + if (rv_abort != APR_SUCCESS) { + *err = "sending FCGI_ABORT_REQUEST"; + rv = rv_abort; + } + apr_brigade_destroy(cib); + break; + } + } + + if (pfd[0].rtnevents & APR_POLLIN) { apr_size_t readbuflen; apr_uint16_t clen, rid; apr_bucket *b; @@ -777,6 +814,7 @@ case AP_FCGI_END_REQUEST: done = 1; + apr_brigade_destroy(cib); break; default: