| 5572 | } |
| 5573 | |
| 5574 | static int core_upgrade_handler(request_rec *r) |
| 5575 | { |
| 5576 | conn_rec *c = r->connection; |
| 5577 | const char *upgrade; |
| 5578 | |
| 5579 | if (c->master) { |
| 5580 | /* Not possible to perform an HTTP/1.1 upgrade from a slave |
| 5581 | * connection. */ |
| 5582 | return DECLINED; |
| 5583 | } |
| 5584 | |
| 5585 | upgrade = apr_table_get(r->headers_in, "Upgrade"); |
| 5586 | if (upgrade && *upgrade) { |
| 5587 | const char *conn = apr_table_get(r->headers_in, "Connection"); |
| 5588 | if (ap_find_token(r->pool, conn, "upgrade")) { |
| 5589 | apr_array_header_t *offers = NULL; |
| 5590 | const char *err; |
| 5591 | |
| 5592 | err = ap_parse_token_list_strict(r->pool, upgrade, &offers, 0); |
| 5593 | if (err) { |
| 5594 | ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02910) |
| 5595 | "parsing Upgrade header: %s", err); |
| 5596 | return DECLINED; |
| 5597 | } |
| 5598 | |
| 5599 | if (offers && offers->nelts > 0) { |
| 5600 | const char *protocol = ap_select_protocol(c, r, NULL, offers); |
| 5601 | if (protocol && strcmp(protocol, ap_get_protocol(c))) { |
| 5602 | ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02909) |
| 5603 | "Upgrade selects '%s'", protocol); |
| 5604 | /* Let the client know what we are upgrading to. */ |
| 5605 | apr_table_clear(r->headers_out); |
| 5606 | apr_table_setn(r->headers_out, "Upgrade", protocol); |
| 5607 | apr_table_setn(r->headers_out, "Connection", "Upgrade"); |
| 5608 | |
| 5609 | r->status = HTTP_SWITCHING_PROTOCOLS; |
| 5610 | r->status_line = ap_get_status_line(r->status); |
| 5611 | ap_send_interim_response(r, 1); |
| 5612 | |
| 5613 | ap_switch_protocol(c, r, r->server, protocol); |
| 5614 | |
| 5615 | /* make sure httpd closes the connection after this */ |
| 5616 | c->keepalive = AP_CONN_CLOSE; |
| 5617 | return DONE; |
| 5618 | } |
| 5619 | } |
| 5620 | } |
| 5621 | } |
| 5622 | else if (!c->keepalives) { |
| 5623 | /* first request on a master connection, if we have protocols other |
| 5624 | * than the current one enabled here, announce them to the |
| 5625 | * client. If the client is already talking a protocol with requests |
| 5626 | * on slave connections, leave it be. */ |
| 5627 | const apr_array_header_t *upgrades; |
| 5628 | ap_get_protocol_upgrades(c, r, NULL, 0, &upgrades); |
| 5629 | if (upgrades && upgrades->nelts > 0) { |
| 5630 | char *protocols = apr_array_pstrcat(r->pool, upgrades, ','); |
| 5631 | apr_table_setn(r->headers_out, "Upgrade", protocols); |
no test coverage detected