View | Details | Raw Unified | Return to bug 56188
Collapse All | Expand All

(-)modules/proxy/mod_proxy_fcgi.c (-12 / +87 lines)
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
};

Return to bug 56188