/* Licensed to the Apache Software Foundation (ASF) under one or more *contributorlicenseagreements.SeetheNOTICEfiledistributedwith *thisworkforadditionalinformationregardingcopyrightownership. *TheASFlicensesthisfiletoYouundertheApacheLicense,Version2.0 *(the"License");youmaynotusethisfileexceptincompliancewith *theLicense.YoumayobtainacopyoftheLicenseat * *http://www.apache.org/licenses/LICENSE-2.0 * *Unlessrequiredbyapplicablelaworagreedtoinwriting,software *distributedundertheLicenseisdistributedonan"ASIS"BASIS, *WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied. *SeetheLicenseforthespecificlanguagegoverningpermissionsand *limitationsundertheLicense.
*/
if (!conn_ctx || !req->protocol || strcmp("websocket", req->protocol)) return req;
if (ap_cstr_casecmp("CONNECT", req->method)) {
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c2, "h2_c2(%s-%d): websocket request with method %s",
conn_ctx->id, conn_ctx->stream_id, req->method); return req;
} if (!req->scheme) {
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c2, "h2_c2(%s-%d): websocket CONNECT without :scheme",
conn_ctx->id, conn_ctx->stream_id); return req;
} if (!req->path) {
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c2, "h2_c2(%s-%d): websocket CONNECT without :path",
conn_ctx->id, conn_ctx->stream_id); return req;
}
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c2, "h2_c2(%s-%d): websocket CONNECT for %s",
conn_ctx->id, conn_ctx->stream_id, req->path); /* Transform the HTTP/2 extended CONNECT to an internal GET using
* the HTTP/1.1 version of websocket connection setup. */
wsreq = h2_request_clone(c2->pool, req);
wsreq->method = "GET";
wsreq->protocol = NULL;
apr_table_set(wsreq->headers, "Upgrade", "websocket");
apr_table_add(wsreq->headers, "Connection", "Upgrade"); /* add Sec-WebSocket-Key header */
rv = apr_generate_random_bytes(key_raw, sizeof(key_raw)); if (rv != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL, APLOGNO(10461) "error generating secret"); return NULL;
}
key_base64 = apr_pencode_base64_binary(c2->pool, key_raw, sizeof(key_raw),
APR_ENCODE_NONE, NULL);
apr_table_set(wsreq->headers, "Sec-WebSocket-Key", key_base64); /* This is now the request to process internally */
/* When this request gets processed and delivers a 101 response, *weexpectittocarrya"Sec-WebSocket-Accept"headerwith
* exactly the following value, as per RFC 6455. */
accept_base64 = gen_ws_accept(c2, key_base64); /* Add an output filter that intercepts generated responses: *-ifavalidWebSocketnegotiationhappens,transformthe *101responsetoa200 *-ifa2xxresponsehappens,thatdoesnotpasstheAccepttest, *returna502indicatingthattheURIseemsnotsupportthewebsocket *protocol(RFC8441doesnotdefinethis,butitseemsthebest *choice) *-ifa3xx,4xxor5xxresponsehappens,forwardthisunchanged.
*/
ws_ctx = apr_pcalloc(c2->pool, sizeof(*ws_ctx));
ws_ctx->ws_accept_base64 = accept_base64; /* insert our filter just before the C2 core filter */
ap_remove_output_filter_byhandle(c2->output_filters, "H2_C2_NET_OUT");
ap_add_output_filter("H2_C2_WS_OUT", ws_ctx, NULL, c2);
ap_add_output_filter("H2_C2_NET_OUT", NULL, NULL, c2); /* Mark the connection as being an Upgrade, with some special handling
* since the request needs an EOS, without the stream being closed */
conn_ctx->is_upgrade = 1;
ap_assert(conn_ctx); if (ws_ctx->override_body) { /* We have overridden the original response and also its body. *Ifthisfilteriscalledagain,wesignalahardabortto
* allow processing to terminate at the earliest. */
f->c->aborted = 1; return APR_ECONNABORTED;
}
/* Inspect the brigade, looking for RESPONSE/HEADER buckets. *Remember,thisfilterisonlyactiveforclientwebsocketCONNECT *requeststhatwetranslatedtoaninternalGETwithwebsocket *headers. *Weinspecttherepsonetoseeiftheinternalresourceactually *agreestotalkwebsocketoris"just"anormalHTTPresourcethat
* ignored the websocket request headers. */ for (b = APR_BRIGADE_FIRST(bb);
b != APR_BRIGADE_SENTINEL(bb);
b = bnext)
{
bnext = APR_BUCKET_NEXT(b); if (APR_BUCKET_IS_METADATA(b)) { #if AP_HAS_RESPONSE_BUCKETS if (AP_BUCKET_IS_RESPONSE(b)) { #else if (H2_BUCKET_IS_HEADERS(b)) { #endif/* !AP_HAS_RESPONSE_BUCKETS */
ws_handle_resp(f->c, conn_ctx, ws_ctx, b); continue;
}
} elseif (ws_ctx->override_body) {
apr_bucket_delete(b);
}
} return ap_pass_brigade(f->next, bb);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.