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 = ap_get_conn_socket(r->connection); |
530 |
pfd[1].p = r->connection->pool; |
531 |
pfd[1].reqevents = APR_POLLIN; |
532 |
|
523 |
ib = apr_brigade_create(r->pool, c->bucket_alloc); |
533 |
ib = apr_brigade_create(r->pool, c->bucket_alloc); |
524 |
ob = apr_brigade_create(r->pool, c->bucket_alloc); |
534 |
ob = apr_brigade_create(r->pool, c->bucket_alloc); |
|
|
535 |
cib = apr_brigade_create(r->connection->pool, c->bucket_alloc); |
536 |
fcgi_serverconf_t *cfg = ap_get_module_config(r->server->module_config, |
537 |
&proxy_fcgi_module); |
538 |
|
525 |
while (! done) { |
539 |
while (! done) { |
526 |
apr_interval_time_t timeout; |
540 |
apr_interval_time_t timeout; |
527 |
apr_size_t len; |
541 |
apr_size_t len; |
Lines 534-540
Link Here
|
534 |
* cause timeout errors. */ |
548 |
* cause timeout errors. */ |
535 |
apr_socket_timeout_get(conn->sock, &timeout); |
549 |
apr_socket_timeout_get(conn->sock, &timeout); |
536 |
rv = apr_poll(&pfd, 1, &n, timeout); |
550 |
rv = apr_poll(pfd, 2, &n, timeout); |
537 |
if (rv != APR_SUCCESS) { |
551 |
if (rv != APR_SUCCESS) { |
538 |
if (APR_STATUS_IS_EINTR(rv)) { |
552 |
if (APR_STATUS_IS_EINTR(rv)) { |
539 |
continue; |
553 |
continue; |
Lines 543-549
Link Here
|
543 |
break; |
557 |
break; |
544 |
} |
558 |
} |
545 |
if (pfd.rtnevents & APR_POLLOUT) { |
559 |
if (pfd[0].rtnevents & APR_POLLOUT) { |
546 |
apr_size_t to_send, writebuflen; |
560 |
apr_size_t to_send, writebuflen; |
547 |
int last_stdin = 0; |
561 |
int last_stdin = 0; |
548 |
char *iobuf_cursor; |
562 |
char *iobuf_cursor; |
Lines 608-614
Link Here
|
608 |
} |
622 |
} |
609 |
if (last_stdin) { |
623 |
if (last_stdin) { |
610 |
pfd.reqevents = APR_POLLIN; /* Done with input data */ |
624 |
pfd[0].reqevents = APR_POLLIN; /* Done with input data */ |
611 |
/* signal EOF (empty FCGI_STDIN) */ |
625 |
/* signal EOF (empty FCGI_STDIN) */ |
612 |
ap_fcgi_fill_in_header(&header, AP_FCGI_STDIN, request_id, |
626 |
ap_fcgi_fill_in_header(&header, AP_FCGI_STDIN, request_id, |
Lines 626-632
Link Here
|
626 |
} |
640 |
} |
627 |
} |
641 |
} |
628 |
if (pfd.rtnevents & APR_POLLIN) { |
642 |
/* |
|
|
643 |
* Client connection aborted before any attempt to flush |
644 |
* data out has been made. This can happen for long running FCGI |
645 |
* tasks. According to the FCGI specs, an FCGI_ABORT should be sent |
646 |
* and the FCGI backend should respond with an FCGI_END_REQUEST, but as of |
647 |
* today (December 2016) there seems to be no FCGI backend implementation |
648 |
* that really honor/care about this functionality. Since this module |
649 |
* does not implement FCGI request multiplexing, it seems more consistent |
650 |
* to follow this bit of the FCGI_ABORT spec: |
651 |
* "When a Web server is not multiplexing requests over a transport |
652 |
* connection, the Web server can abort a request by closing |
653 |
* the request's transport connection." |
654 |
*/ |
655 |
if (pfd[1].rtnevents & APR_POLLIN) { |
656 |
if (cfg->detect_client_disconnect) { |
657 |
rv = ap_get_brigade(r->connection->input_filters, cib, |
658 |
AP_MODE_SPECULATIVE, APR_NONBLOCK_READ, 8); |
659 |
if(rv == APR_EOF) { |
660 |
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, |
661 |
"EOF detected from the main client connection."); |
662 |
r->connection->aborted = 1; |
663 |
break; |
664 |
} |
665 |
} |
666 |
} |
667 |
|
668 |
if (pfd[0].rtnevents & APR_POLLIN) { |
629 |
apr_size_t readbuflen; |
669 |
apr_size_t readbuflen; |
630 |
apr_uint16_t clen, rid; |
670 |
apr_uint16_t clen, rid; |
631 |
apr_bucket *b; |
671 |
apr_bucket *b; |
Lines 855-860
Link Here
|
855 |
apr_brigade_destroy(ib); |
895 |
apr_brigade_destroy(ib); |
856 |
apr_brigade_destroy(ob); |
896 |
apr_brigade_destroy(ob); |
|
|
897 |
apr_brigade_destroy(cib); |
857 |
if (script_error_status != HTTP_OK) { |
898 |
if (script_error_status != HTTP_OK) { |
858 |
ap_die(script_error_status, r); /* send ErrorDocument */ |
899 |
ap_die(script_error_status, r); /* send ErrorDocument */ |
Lines 1052-1057
Link Here
|
1052 |
return a; |
1093 |
return a; |
1053 |
} |
1094 |
} |
|
|
1095 |
static void *fcgi_create_sconf(apr_pool_t *p, server_rec *s) |
1096 |
{ |
1097 |
fcgi_serverconf_t *a; |
1098 |
|
1099 |
a = (fcgi_serverconf_t *) apr_pcalloc(p, sizeof(fcgi_serverconf_t)); |
1100 |
a->detect_client_disconnect = 0; |
1101 |
return a; |
1102 |
} |
1103 |
|
1104 |
static void *fcgi_merge_sconf(apr_pool_t *p, void *basev, void *overridesv) |
1105 |
{ |
1106 |
fcgi_serverconf_t *a, *override; |
1107 |
|
1108 |
override = (fcgi_serverconf_t *) overridesv; |
1109 |
a = (fcgi_serverconf_t *) apr_pcalloc(p, sizeof(fcgi_serverconf_t)); |
1110 |
a->detect_client_disconnect = override->detect_client_disconnect; |
1111 |
return a; |
1112 |
} |
1113 |
|
1054 |
static const char *cmd_servertype(cmd_parms *cmd, void *in_dconf, |
1114 |
static const char *cmd_servertype(cmd_parms *cmd, void *in_dconf, |
1055 |
const char *val) |
1115 |
const char *val) |
1056 |
{ |
1116 |
{ |
Lines 1071-1076
Link Here
|
1071 |
return NULL; |
1131 |
return NULL; |
1072 |
} |
1132 |
} |
|
|
1133 |
const char *cmd_client_disconnect(cmd_parms *cmd, void *cfg, const char *arg) |
1134 |
{ |
1135 |
fcgi_serverconf_t *config = ap_get_module_config(cmd->server->module_config, |
1136 |
&proxy_fcgi_module); |
1137 |
if(!strcasecmp(arg, "on")) { |
1138 |
config->detect_client_disconnect = 1; |
1139 |
} else { |
1140 |
config->detect_client_disconnect = 0; |
1141 |
} |
1142 |
return NULL; |
1143 |
} |
1144 |
|
1073 |
static void register_hooks(apr_pool_t *p) |
1145 |
static void register_hooks(apr_pool_t *p) |
1074 |
{ |
1146 |
{ |
1075 |
proxy_hook_scheme_handler(proxy_fcgi_handler, NULL, NULL, APR_HOOK_FIRST); |
1147 |
proxy_hook_scheme_handler(proxy_fcgi_handler, NULL, NULL, APR_HOOK_FIRST); |
Lines 1080-1085
Link Here
|
1080 |
static const command_rec command_table[] = { |
1152 |
static const command_rec command_table[] = { |
1081 |
AP_INIT_TAKE1("ProxyFCGIBackendType", cmd_servertype, NULL, OR_FILEINFO, |
1153 |
AP_INIT_TAKE1("ProxyFCGIBackendType", cmd_servertype, NULL, OR_FILEINFO, |
1082 |
"Specify the type of FastCGI server: 'Generic', 'FPM'"), |
1154 |
"Specify the type of FastCGI server: 'Generic', 'FPM'"), |
|
|
1155 |
AP_INIT_TAKE1("ProxyFCGIDetectClientDisconnect", cmd_client_disconnect, |
1156 |
NULL, RSRC_CONF, "Detect when a client connection is dropped" |
1157 |
" and close the connection with the FCGI backend."), |
1083 |
{ NULL } |
1158 |
{ NULL } |
1084 |
}; |
1159 |
}; |
Lines 1087-1094
Link Here
|
1087 |
STANDARD20_MODULE_STUFF, |
1162 |
STANDARD20_MODULE_STUFF, |
1088 |
fcgi_create_dconf, /* create per-directory config structure */ |
1163 |
fcgi_create_dconf, /* create per-directory config structure */ |
1089 |
fcgi_merge_dconf, /* merge per-directory config structures */ |
1164 |
fcgi_merge_dconf, /* merge per-directory config structures */ |
1090 |
NULL, /* create per-server config structure */ |
1165 |
fcgi_create_sconf, /* create per-server config structure */ |
1091 |
NULL, /* merge per-server config structures */ |
1166 |
fcgi_merge_sconf, /* merge per-server config structures */ |
1092 |
command_table, /* command apr_table_t */ |
1167 |
command_table, /* command apr_table_t */ |
1093 |
register_hooks /* register hooks */ |
1168 |
register_hooks /* register hooks */ |
1094 |
}; |
1169 |
}; |