Commit f6d41b1d authored by Bradley Nicholes's avatar Bradley Nicholes
Browse files

Tokenize the header while parsing it for the upgrade tokens and once the...

Tokenize the header while parsing it for the upgrade tokens and once the protocol has been upgraded, allow the request to complete encrypted.


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk/modules/ssl@104273 13f79535-47bb-0310-9956-ffa450edef68
parent a63ac3b5
Loading
Loading
Loading
Loading
+30 −12
Original line number Diff line number Diff line
@@ -1170,7 +1170,7 @@ static apr_status_t ssl_io_filter_Upgrade(ap_filter_t *f,

{
#define SWITCH_STATUS_LINE "HTTP/1.1 101 Switching Protocols"
#define UPGRADE_HEADER "Upgrade: TLS/1.0 HTTP/1.1"
#define UPGRADE_HEADER "Upgrade: TLS/1.0, HTTP/1.1"
#define CONNECTION_HEADER "Connection: Upgrade"
    const char *upgrade;
    const char *connection;
@@ -1178,6 +1178,9 @@ static apr_status_t ssl_io_filter_Upgrade(ap_filter_t *f,
    request_rec *r = f->r;
    SSLConnRec *sslconn;
    SSL *ssl;
    char *token_string;
    char *token;
    char *token_state;

    /* Just remove the filter, if it doesn't work the first time, it won't
     * work at all for this request.
@@ -1192,19 +1195,30 @@ static apr_status_t ssl_io_filter_Upgrade(ap_filter_t *f,
    if (upgrade == NULL) {
        return ap_pass_brigade(f->next, bb);
    }
    connection = apr_table_get(r->headers_in, "Connection");
    token_string = apr_pstrdup(r->pool,upgrade);
    token = apr_strtok(token_string,", ",&token_state);
    while (token && strcmp(token,"TLS/1.0")) {
        apr_strtok(NULL,", ",&token_state);
    }
    /* "Upgrade: TLS/1.0" header not found, don't do Upgrade */
    if (!token) {
        return ap_pass_brigade(f->next, bb);
    }

    apr_table_unset(r->headers_out, "Upgrade");
    connection = apr_table_get(r->headers_in, "Connection");

    /* XXX: I don't think the requirement that the client sends exactly 
     * "Connection: Upgrade" is correct; the only requirement here is 
     * on the client to send a  Connection header including the "upgrade" 
     * token.
     */
    if (strcmp(connection, "Upgrade") || strcmp(upgrade, "TLS/1.0")) {
    token_string = apr_pstrdup(r->pool,connection);
    token = apr_strtok(token_string,",",&token_state);
    while (token && strcmp(token,"Upgrade")) {
        apr_strtok(NULL,",",&token_state);
    }
    /* "Connection: Upgrade" header not found, don't do Upgrade */
    if (!token) {
        return ap_pass_brigade(f->next, bb);
    }

    apr_table_unset(r->headers_out, "Upgrade");

    if (r->method_number == M_OPTIONS) {
        apr_bucket *b = NULL;
        /* This is a mandatory SSL upgrade. */
@@ -1238,18 +1252,22 @@ static apr_status_t ssl_io_filter_Upgrade(ap_filter_t *f,
     * However, this causes failures in perl-framework currently, 
     * perhaps pre-test if we have already negotiated?
     */
    SSL_set_state(ssl, SSL_ST_ACCEPT);
    SSL_set_accept_state(ssl);
    SSL_do_handshake(ssl);

    if (SSL_get_state(ssl) != SSL_ST_OK) {
        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
                     "Re-negotiation handshake failed: "
                     "TLS Upgrade handshake failed: "
                "Not accepted by client!?");

        return AP_FILTER_ERROR;
    }

    return OK;
    /* Now that we have initialized the ssl connection which added the ssl_io_filter, 
       pass the brigade off to the connection based output filters so that the 
       request can complete encrypted */
    return ap_pass_brigade(f->c->output_filters, bb);

}

static apr_status_t ssl_io_filter_input(ap_filter_t *f,
+1 −1
Original line number Diff line number Diff line
@@ -1013,7 +1013,7 @@ int ssl_hook_Fixup(request_rec *r)
    SSL *ssl;
    int i;

    if (sc->enabled == SSL_ENABLED_OPTIONAL) {
    if (sc->enabled == SSL_ENABLED_OPTIONAL && !(sslconn && sslconn->ssl)) {
        apr_table_setn(r->headers_out, "Upgrade", "TLS/1.0, HTTP/1.1");
    }