Lines 40-45
Link Here
|
40 |
fcgi_backend_t backend_type; |
40 |
fcgi_backend_t backend_type; |
41 |
} fcgi_dirconf_t; |
41 |
} fcgi_dirconf_t; |
|
|
42 |
typedef struct { |
43 |
int detect_client_disconnect; |
44 |
} fcgi_serverconf_t; |
45 |
|
42 |
/* |
46 |
/* |
43 |
* Canonicalise http-like URLs. |
47 |
* Canonicalise http-like URLs. |
44 |
* scheme is the scheme for the URL |
48 |
* scheme is the scheme for the URL |
Lines 497-503
Link Here
|
497 |
apr_uint16_t request_id, const char **err, |
501 |
apr_uint16_t request_id, const char **err, |
498 |
int *bad_request, int *has_responded) |
502 |
int *bad_request, int *has_responded) |
499 |
{ |
503 |
{ |
500 |
apr_bucket_brigade *ib, *ob; |
504 |
apr_bucket_brigade *ib, *ob, *cib; |
501 |
int seen_end_of_headers = 0, done = 0, ignore_body = 0; |
505 |
int seen_end_of_headers = 0, done = 0, ignore_body = 0; |
502 |
apr_status_t rv = APR_SUCCESS; |
506 |
apr_status_t rv = APR_SUCCESS; |
503 |
int script_error_status = HTTP_OK; |
507 |
int script_error_status = HTTP_OK; |
Lines 505-511
Link Here
|
505 |
struct iovec vec[2]; |
509 |
struct iovec vec[2]; |
506 |
ap_fcgi_header header; |
510 |
ap_fcgi_header header; |
507 |
unsigned char farray[AP_FCGI_HEADER_LEN]; |
511 |
unsigned char farray[AP_FCGI_HEADER_LEN]; |
508 |
apr_pollfd_t pfd; |
512 |
apr_pollfd_t pfd[2]; |
509 |
int header_state = HDR_STATE_READING_HEADERS; |
513 |
int header_state = HDR_STATE_READING_HEADERS; |
510 |
char stack_iobuf[AP_IOBUFSIZE]; |
514 |
char stack_iobuf[AP_IOBUFSIZE]; |
511 |
apr_size_t iobuf_size = AP_IOBUFSIZE; |
515 |
apr_size_t iobuf_size = AP_IOBUFSIZE; |
Lines 517-530
Link Here
|
517 |
iobuf = apr_palloc(r->pool, iobuf_size); |
521 |
iobuf = apr_palloc(r->pool, iobuf_size); |
518 |
} |
522 |
} |
519 |
pfd.desc_type = APR_POLL_SOCKET; |
523 |
pfd[0].desc_type = APR_POLL_SOCKET; |
520 |
pfd.desc.s = conn->sock; |
524 |
pfd[0].desc.s = conn->sock; |
521 |
pfd.p = r->pool; |
525 |
pfd[0].p = r->pool; |
522 |
pfd.reqevents = APR_POLLIN | APR_POLLOUT; |
526 |
pfd[0].reqevents = APR_POLLIN | APR_POLLOUT; |
|
|
527 |
/* Specific pollfd to detect client connection aborts */ |
528 |
pfd[1].desc_type = APR_POLL_SOCKET; |
529 |
pfd[1].desc.s = (apr_socket_t*) ap_get_module_config(r->connection->conn_config, |
530 |
&core_module); |
531 |
pfd[1].p = r->connection->pool; |
532 |
pfd[1].reqevents = APR_POLLIN; |
533 |
|
523 |
ib = apr_brigade_create(r->pool, c->bucket_alloc); |
534 |
ib = apr_brigade_create(r->pool, c->bucket_alloc); |
524 |
ob = apr_brigade_create(r->pool, c->bucket_alloc); |
535 |
ob = apr_brigade_create(r->pool, c->bucket_alloc); |
|
|
536 |
cib = apr_brigade_create(r->connection->pool, c->bucket_alloc); |
537 |
fcgi_serverconf_t *cfg = ap_get_module_config(r->server->module_config, |
538 |
&proxy_fcgi_module); |
539 |
|
525 |
while (! done) { |
540 |
while (! done) { |
526 |
apr_interval_time_t timeout; |
541 |
apr_interval_time_t timeout; |
527 |
apr_size_t len; |
542 |
apr_size_t len; |
Lines 534-540
Link Here
|
534 |
* cause timeout errors. */ |
549 |
* cause timeout errors. */ |
535 |
apr_socket_timeout_get(conn->sock, &timeout); |
550 |
apr_socket_timeout_get(conn->sock, &timeout); |
536 |
rv = apr_poll(&pfd, 1, &n, timeout); |
551 |
rv = apr_poll(pfd, 2, &n, timeout); |
537 |
if (rv != APR_SUCCESS) { |
552 |
if (rv != APR_SUCCESS) { |
538 |
if (APR_STATUS_IS_EINTR(rv)) { |
553 |
if (APR_STATUS_IS_EINTR(rv)) { |
539 |
continue; |
554 |
continue; |
Lines 543-549
Link Here
|
543 |
break; |
558 |
break; |
544 |
} |
559 |
} |
545 |
if (pfd.rtnevents & APR_POLLOUT) { |
560 |
if (pfd[0].rtnevents & APR_POLLOUT) { |
546 |
apr_size_t to_send, writebuflen; |
561 |
apr_size_t to_send, writebuflen; |
547 |
int last_stdin = 0; |
562 |
int last_stdin = 0; |
548 |
char *iobuf_cursor; |
563 |
char *iobuf_cursor; |
Lines 608-614
Link Here
|
608 |
} |
623 |
} |
609 |
if (last_stdin) { |
624 |
if (last_stdin) { |
610 |
pfd.reqevents = APR_POLLIN; /* Done with input data */ |
625 |
pfd[0].reqevents = APR_POLLIN; /* Done with input data */ |
611 |
/* signal EOF (empty FCGI_STDIN) */ |
626 |
/* signal EOF (empty FCGI_STDIN) */ |
612 |
ap_fcgi_fill_in_header(&header, AP_FCGI_STDIN, request_id, |
627 |
ap_fcgi_fill_in_header(&header, AP_FCGI_STDIN, request_id, |
Lines 626-632
Link Here
|
626 |
} |
641 |
} |
627 |
} |
642 |
} |
628 |
if (pfd.rtnevents & APR_POLLIN) { |
643 |
/* |
|
|
644 |
* Client connection aborted before any attempt to flush |
645 |
* data out has been made. This can happen for long running FCGI |
646 |
* tasks. According to the FCGI specs, an FCGI_ABORT should be sent |
647 |
* and the FCGI backend should respond with an FCGI_END_REQUEST, but as of |
648 |
* today (December 2016) there seems to be no FCGI backend implementation |
649 |
* that really honor/care about this functionality. Since this module |
650 |
* does not implement FCGI request multiplexing, it seems more consistent |
651 |
* to follow this bit of the FCGI_ABORT spec: |
652 |
* "When a Web server is not multiplexing requests over a transport |
653 |
* connection, the Web server can abort a request by closing |
654 |
* the request's transport connection." |
655 |
*/ |
656 |
if (pfd[1].rtnevents & APR_POLLIN) { |
657 |
if (cfg->detect_client_disconnect) { |
658 |
rv = ap_get_brigade(r->connection->input_filters, cib, |
659 |
AP_MODE_SPECULATIVE, APR_NONBLOCK_READ, 8); |
660 |
if(rv == APR_EOF) { |
661 |
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, |
662 |
"EOF detected from the main client connection."); |
663 |
r->connection->aborted = 1; |
664 |
break; |
665 |
} |
666 |
} else { |
667 |
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, |
668 |
"Client disconnect detector disabled!"); |
669 |
} |
670 |
} |
671 |
|
672 |
if (pfd[0].rtnevents & APR_POLLIN) { |
629 |
apr_size_t readbuflen; |
673 |
apr_size_t readbuflen; |
630 |
apr_uint16_t clen, rid; |
674 |
apr_uint16_t clen, rid; |
631 |
apr_bucket *b; |
675 |
apr_bucket *b; |
Lines 855-860
Link Here
|
855 |
apr_brigade_destroy(ib); |
899 |
apr_brigade_destroy(ib); |
856 |
apr_brigade_destroy(ob); |
900 |
apr_brigade_destroy(ob); |
|
|
901 |
apr_brigade_destroy(cib); |
857 |
if (script_error_status != HTTP_OK) { |
902 |
if (script_error_status != HTTP_OK) { |
858 |
ap_die(script_error_status, r); /* send ErrorDocument */ |
903 |
ap_die(script_error_status, r); /* send ErrorDocument */ |
Lines 1052-1057
Link Here
|
1052 |
return a; |
1097 |
return a; |
1053 |
} |
1098 |
} |
|
|
1099 |
static void *fcgi_create_sconf(apr_pool_t *p, server_rec *s) |
1100 |
{ |
1101 |
fcgi_serverconf_t *a; |
1102 |
|
1103 |
a = (fcgi_serverconf_t *) apr_pcalloc(p, sizeof(fcgi_serverconf_t)); |
1104 |
a->detect_client_disconnect = 0; |
1105 |
return a; |
1106 |
} |
1107 |
|
1108 |
static void *fcgi_merge_sconf(apr_pool_t *p, void *basev, void *overridesv) |
1109 |
{ |
1110 |
fcgi_serverconf_t *a, *override; |
1111 |
|
1112 |
override = (fcgi_serverconf_t *) overridesv; |
1113 |
a = (fcgi_serverconf_t *) apr_pcalloc(p, sizeof(fcgi_serverconf_t)); |
1114 |
a->detect_client_disconnect = override->detect_client_disconnect; |
1115 |
return a; |
1116 |
} |
1117 |
|
1054 |
static const char *cmd_servertype(cmd_parms *cmd, void *in_dconf, |
1118 |
static const char *cmd_servertype(cmd_parms *cmd, void *in_dconf, |
1055 |
const char *val) |
1119 |
const char *val) |
1056 |
{ |
1120 |
{ |
Lines 1071-1076
Link Here
|
1071 |
return NULL; |
1135 |
return NULL; |
1072 |
} |
1136 |
} |
|
|
1137 |
const char *cmd_client_disconnect(cmd_parms *cmd, void *cfg, const char *arg) |
1138 |
{ |
1139 |
fcgi_serverconf_t *config = ap_get_module_config(cmd->server->module_config, |
1140 |
&proxy_fcgi_module); |
1141 |
if(!strcasecmp(arg, "on")) { |
1142 |
config->detect_client_disconnect = 1; |
1143 |
} else { |
1144 |
config->detect_client_disconnect = 0; |
1145 |
} |
1146 |
return NULL; |
1147 |
} |
1148 |
|
1073 |
static void register_hooks(apr_pool_t *p) |
1149 |
static void register_hooks(apr_pool_t *p) |
1074 |
{ |
1150 |
{ |
1075 |
proxy_hook_scheme_handler(proxy_fcgi_handler, NULL, NULL, APR_HOOK_FIRST); |
1151 |
proxy_hook_scheme_handler(proxy_fcgi_handler, NULL, NULL, APR_HOOK_FIRST); |
Lines 1080-1085
Link Here
|
1080 |
static const command_rec command_table[] = { |
1156 |
static const command_rec command_table[] = { |
1081 |
AP_INIT_TAKE1("ProxyFCGIBackendType", cmd_servertype, NULL, OR_FILEINFO, |
1157 |
AP_INIT_TAKE1("ProxyFCGIBackendType", cmd_servertype, NULL, OR_FILEINFO, |
1082 |
"Specify the type of FastCGI server: 'Generic', 'FPM'"), |
1158 |
"Specify the type of FastCGI server: 'Generic', 'FPM'"), |
|
|
1159 |
AP_INIT_TAKE1("ProxyFCGIDetectClientDisconnect", cmd_client_disconnect, |
1160 |
NULL, RSRC_CONF, "Detect when a client connection is dropped" |
1161 |
" and close the connection with the FCGI backend."), |
1083 |
{ NULL } |
1162 |
{ NULL } |
1084 |
}; |
1163 |
}; |
Lines 1087-1094
Link Here
|
1087 |
STANDARD20_MODULE_STUFF, |
1166 |
STANDARD20_MODULE_STUFF, |
1088 |
fcgi_create_dconf, /* create per-directory config structure */ |
1167 |
fcgi_create_dconf, /* create per-directory config structure */ |
1089 |
fcgi_merge_dconf, /* merge per-directory config structures */ |
1168 |
fcgi_merge_dconf, /* merge per-directory config structures */ |
1090 |
NULL, /* create per-server config structure */ |
1169 |
fcgi_create_sconf, /* create per-server config structure */ |
1091 |
NULL, /* merge per-server config structures */ |
1170 |
fcgi_merge_sconf, /* merge per-server config structures */ |
1092 |
command_table, /* command apr_table_t */ |
1171 |
command_table, /* command apr_table_t */ |
1093 |
register_hooks /* register hooks */ |
1172 |
register_hooks /* register hooks */ |
1094 |
}; |
1173 |
}; |