mod_proxy_wstunnel.c revision ac95effcd4bcdf02e41becbec4e9f2d3c577e7fd
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny/* Licensed to the Apache Software Foundation (ASF) under one or more
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny * contributor license agreements. See the NOTICE file distributed with
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny * this work for additional information regarding copyright ownership.
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny * The ASF licenses this file to You under the Apache License, Version 2.0
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny * (the "License"); you may not use this file except in compliance with
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny * the License. You may obtain a copy of the License at
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny *
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny * http://www.apache.org/licenses/LICENSE-2.0
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny *
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny * Unless required by applicable law or agreed to in writing, software
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny * distributed under the License is distributed on an "AS IS" BASIS,
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny * See the License for the specific language governing permissions and
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny * limitations under the License.
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny */
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny#include "mod_proxy.h"
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny#include "ap_mpm.h"
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zelenymodule AP_MODULE_DECLARE_DATA proxy_wstunnel_module;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zelenytypedef struct ws_baton_t {
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny request_rec *r;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny proxy_conn_rec *proxy_connrec;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny apr_socket_t *server_soc;
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek apr_socket_t *client_soc;
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek apr_pollset_t *pollset;
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek apr_bucket_brigade *bb;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny int is_client;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny apr_pool_t *subpool;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny} ws_baton_t;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zelenystatic int proxy_wstunnel_transfer(request_rec *r, conn_rec *c_i, conn_rec *c_o,
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny apr_bucket_brigade *bb, char *name);
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozekstatic int proxy_wstunnel_pump(ws_baton_t *baton, apr_time_t timeout) {
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek request_rec *r = baton->r;
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek conn_rec *c = r->connection;
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek proxy_conn_rec *conn = baton->proxy_connrec;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny apr_socket_t *sock = conn->sock;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny conn_rec *backconn = conn->connection;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny const apr_pollfd_t *signalled;
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek apr_int32_t pollcnt, pi;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny apr_int16_t pollevent;
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek apr_pollset_t *pollset = baton->pollset;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny apr_socket_t *client_socket = baton->client_soc;
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek apr_status_t rv;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny apr_bucket_brigade *bb = baton->bb;
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny while(1) {
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny if ((rv = apr_pollset_poll(pollset, timeout, &pollcnt, &signalled))
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek != APR_SUCCESS) {
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek if (APR_STATUS_IS_EINTR(rv)) {
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek continue;
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek }
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny else if (APR_STATUS_IS_TIMEUP(rv)) {
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02542) "Attempting to go asynch");
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny return SUSPENDED;
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek }
bdbf4f169e4d5d00b0616df19f7a55debb407f78Pavel Březina else {
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(02444) "error apr_poll()");
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny return HTTP_INTERNAL_SERVER_ERROR;
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek }
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek }
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(02445)
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek "woke from poll(), i=%d", pollcnt);
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny for (pi = 0; pi < pollcnt; pi++) {
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny const apr_pollfd_t *cur = &signalled[pi];
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek if (cur->desc.s == sock) {
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny pollevent = cur->rtnevents;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny if (pollevent & (APR_POLLIN | APR_POLLHUP)) {
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(02446)
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny "sock was readable");
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek rv = proxy_wstunnel_transfer(r, backconn, c, bb, "sock");
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek }
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek else if (pollevent & APR_POLLERR) {
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek rv = APR_EPIPE;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, APLOGNO(02447)
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny "error on backconn");
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny }
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny else {
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny rv = APR_EGENERAL;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, APLOGNO(02605)
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny "unknown event on backconn %d", pollevent);
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny }
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny }
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny else if (cur->desc.s == client_socket) {
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny pollevent = cur->rtnevents;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny if (pollevent & (APR_POLLIN | APR_POLLHUP)) {
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(02448)
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny "client was readable");
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny rv = proxy_wstunnel_transfer(r, c, backconn, bb, "client");
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny }
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny else if (pollevent & APR_POLLERR) {
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny rv = APR_EPIPE;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny c->aborted = 1;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(02607)
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny "error on client conn");
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny }
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny else {
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny rv = APR_EGENERAL;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, APLOGNO(02606)
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny "unknown event on client conn %d", pollevent);
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny }
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny }
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny else {
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny rv = APR_EBADF;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02449)
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny "unknown socket in pollset");
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny }
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny }
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny if (rv != APR_SUCCESS) {
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny break;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny }
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny }
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek "finished with poll() - cleaning up");
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek return OK;
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek}
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozekstatic void proxy_wstunnel_callback(void *b) {
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek int status;
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek ws_baton_t *baton = (ws_baton_t*)b;
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek apr_socket_t *sockets[3] = {NULL, NULL, NULL};
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek apr_thread_mutex_lock(baton->r->invoke_mtx);
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek apr_pool_clear(baton->subpool);
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek status = proxy_wstunnel_pump(baton, apr_time_from_sec(5));
99bac83188601c2b07e0b141aac7dc7d882b464aSumit Bose sockets[0] = baton->client_soc;
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek sockets[1] = baton->server_soc;
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek if (status == SUSPENDED) {
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek ap_mpm_register_socket_callback(sockets, baton->subpool, 1, proxy_wstunnel_callback, baton);
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek }
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek else {
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek ap_mpm_unregister_socket_callback(sockets, baton->subpool);
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek apr_thread_mutex_unlock(baton->r->invoke_mtx);
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek ap_finalize_request_protocol(baton->r);
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek ap_process_request_after_handler(baton->r);
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek return;
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek }
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek apr_thread_mutex_unlock(baton->r->invoke_mtx);
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek}
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek/*
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * Canonicalise http-like URLs.
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny * scheme is the scheme for the URL
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny * url is the URL starting with the first '/'
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * def_port is the default port for this scheme.
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek */
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozekstatic int proxy_wstunnel_canon(request_rec *r, char *url)
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek{
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek char *host, *path, sport[7];
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek char *search = NULL;
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek const char *err;
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek char *scheme;
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek apr_port_t port, def_port;
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek /* ap_port_of_scheme() */
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek if (strncasecmp(url, "ws:", 3) == 0) {
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek url += 3;
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek scheme = "ws:";
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek def_port = apr_uri_port_of_scheme("http");
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek }
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek else if (strncasecmp(url, "wss:", 4) == 0) {
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek url += 4;
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek scheme = "wss:";
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek def_port = apr_uri_port_of_scheme("https");
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek }
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek else {
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek return DECLINED;
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek }
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek port = def_port;
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "canonicalising URL %s", url);
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek /*
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * do syntactic check.
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * We break the URL into host, port, path, search
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek */
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port);
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek if (err) {
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02439) "error parsing URL %s: %s",
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek url, err);
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek return HTTP_BAD_REQUEST;
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek }
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek /*
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * now parse path/search args, according to rfc1738:
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * process the path. With proxy-nocanon set (by
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek * mod_proxy) we use the raw, unparsed uri
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek */
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek if (apr_table_get(r->notes, "proxy-nocanon")) {
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek path = url; /* this is the raw path */
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek }
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek else {
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0,
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek r->proxyreq);
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek search = r->args;
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek }
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek if (path == NULL)
b6d5f2a91fbce15c7ef4d382fa6b52407adb26ddPavel Březina return HTTP_BAD_REQUEST;
b6d5f2a91fbce15c7ef4d382fa6b52407adb26ddPavel Březina
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek apr_snprintf(sport, sizeof(sport), ":%d", port);
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek if (ap_strchr_c(host, ':')) {
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek /* if literal IPv6 address */
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek host = apr_pstrcat(r->pool, "[", host, "]", NULL);
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek }
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek r->filename = apr_pstrcat(r->pool, "proxy:", scheme, "//", host, sport,
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek "/", path, (search) ? "?" : "",
99bac83188601c2b07e0b141aac7dc7d882b464aSumit Bose (search) ? search : "", NULL);
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek return OK;
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek}
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozekstatic int proxy_wstunnel_transfer(request_rec *r, conn_rec *c_i, conn_rec *c_o,
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek apr_bucket_brigade *bb, char *name)
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek{
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek int rv;
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek#ifdef DEBUGGING
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek apr_off_t len;
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek#endif
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek do {
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek apr_brigade_cleanup(bb);
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek rv = ap_get_brigade(c_i->input_filters, bb, AP_MODE_READBYTES,
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek APR_NONBLOCK_READ, AP_IOBUFSIZE);
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek if (rv == APR_SUCCESS) {
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny if (c_o->aborted) {
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny return APR_EPIPE;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny }
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny if (APR_BRIGADE_EMPTY(bb)) {
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek break;
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek }
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny#ifdef DEBUGGING
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny len = -1;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny apr_brigade_length(bb, 0, &len);
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02440)
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek "read %" APR_OFF_T_FMT
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny " bytes from %s", len, name);
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek#endif
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny rv = ap_pass_brigade(c_o->output_filters, bb);
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny if (rv == APR_SUCCESS) {
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny ap_fflush(c_o->output_filters, bb);
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny }
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek else {
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(02441)
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek "error on %s - ap_pass_brigade",
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek name);
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek }
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek } else if (!APR_STATUS_IS_EAGAIN(rv) && !APR_STATUS_IS_EOF(rv)) {
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r, APLOGNO(02442)
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek "error on %s - ap_get_brigade",
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek name);
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek }
99bac83188601c2b07e0b141aac7dc7d882b464aSumit Bose } while (rv == APR_SUCCESS);
bdbf4f169e4d5d00b0616df19f7a55debb407f78Pavel Březina
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek if (APR_STATUS_IS_EAGAIN(rv)) {
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny rv = APR_SUCCESS;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny }
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek return rv;
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek}
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek/* Search thru the input filters and remove the reqtimeout one */
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozekstatic void remove_reqtimeout(ap_filter_t *next)
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek{
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny ap_filter_t *reqto = NULL;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny ap_filter_rec_t *filter;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny filter = ap_get_input_filter_handle("reqtimeout");
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny if (!filter) {
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny return;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny }
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek
8ba8222afca3026fd67af08e224b1d9e848aceaaJakub Hrozek while (next) {
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny if (next->frec == filter) {
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny reqto = next;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny break;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny }
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce next = next->next;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny }
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny if (reqto) {
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny ap_remove_input_filter(reqto);
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny }
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce}
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny/*
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny * process the request and write the response.
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny */
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zelenystatic int ap_proxy_wstunnel_request(apr_pool_t *p, request_rec *r,
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny proxy_conn_rec *conn,
2c68b4a680e64d8e506794d5976367394133504bJan Zeleny proxy_worker *worker,
2c68b4a680e64d8e506794d5976367394133504bJan Zeleny proxy_server_conf *conf,
2c68b4a680e64d8e506794d5976367394133504bJan Zeleny apr_uri_t *uri,
2c68b4a680e64d8e506794d5976367394133504bJan Zeleny char *url, char *server_portstr)
2c68b4a680e64d8e506794d5976367394133504bJan Zeleny{
2c68b4a680e64d8e506794d5976367394133504bJan Zeleny apr_status_t rv = APR_SUCCESS;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny apr_pollset_t *pollset;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny apr_pollfd_t pollfd;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny conn_rec *c = r->connection;
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce apr_socket_t *sock = conn->sock;
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce conn_rec *backconn = conn->connection;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny char *buf;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny apr_bucket_brigade *header_brigade;
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce apr_bucket *e;
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce char *old_cl_val = NULL;
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce char *old_te_val = NULL;
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce apr_bucket_brigade *bb = apr_brigade_create(p, c->bucket_alloc);
aac3ca699a09090072ae4d68bdda8dec990ae393Sumit Bose apr_socket_t *client_socket = ap_get_conn_socket(c);
aac3ca699a09090072ae4d68bdda8dec990ae393Sumit Bose ws_baton_t *baton = apr_pcalloc(r->pool, sizeof(ws_baton_t));
aac3ca699a09090072ae4d68bdda8dec990ae393Sumit Bose apr_socket_t *sockets[3] = {NULL, NULL, NULL};
aac3ca699a09090072ae4d68bdda8dec990ae393Sumit Bose int status;
aac3ca699a09090072ae4d68bdda8dec990ae393Sumit Bose
aac3ca699a09090072ae4d68bdda8dec990ae393Sumit Bose header_brigade = apr_brigade_create(p, backconn->bucket_alloc);
aac3ca699a09090072ae4d68bdda8dec990ae393Sumit Bose
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, "sending request");
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny rv = ap_proxy_create_hdrbrgd(p, header_brigade, r, conn,
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny worker, conf, uri, url, server_portstr,
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny &old_cl_val, &old_te_val);
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny if (rv != OK) {
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny return rv;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny }
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce buf = apr_pstrcat(p, "Upgrade: WebSocket", CRLF, "Connection: Upgrade", CRLF, CRLF, NULL);
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny ap_xlate_proto_to_ascii(buf, strlen(buf));
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc);
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny APR_BRIGADE_INSERT_TAIL(header_brigade, e);
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny if ((rv = ap_proxy_pass_brigade(c->bucket_alloc, r, conn, backconn,
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny header_brigade, 1)) != OK)
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny return rv;
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, "setting up poll()");
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny if ((rv = apr_pollset_create(&pollset, 2, p, 0)) != APR_SUCCESS) {
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(02443)
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny "error apr_pollset_create()");
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny return HTTP_INTERNAL_SERVER_ERROR;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny }
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny#if 0
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny apr_socket_opt_set(sock, APR_SO_NONBLOCK, 1);
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny apr_socket_opt_set(sock, APR_SO_KEEPALIVE, 1);
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny apr_socket_opt_set(client_socket, APR_SO_NONBLOCK, 1);
99bac83188601c2b07e0b141aac7dc7d882b464aSumit Bose apr_socket_opt_set(client_socket, APR_SO_KEEPALIVE, 1);
99bac83188601c2b07e0b141aac7dc7d882b464aSumit Bose#endif
99bac83188601c2b07e0b141aac7dc7d882b464aSumit Bose
99bac83188601c2b07e0b141aac7dc7d882b464aSumit Bose pollfd.p = p;
99bac83188601c2b07e0b141aac7dc7d882b464aSumit Bose pollfd.desc_type = APR_POLL_SOCKET;
99bac83188601c2b07e0b141aac7dc7d882b464aSumit Bose pollfd.reqevents = APR_POLLIN | APR_POLLHUP;
99bac83188601c2b07e0b141aac7dc7d882b464aSumit Bose pollfd.desc.s = sock;
99bac83188601c2b07e0b141aac7dc7d882b464aSumit Bose pollfd.client_data = NULL;
99bac83188601c2b07e0b141aac7dc7d882b464aSumit Bose apr_pollset_add(pollset, &pollfd);
99bac83188601c2b07e0b141aac7dc7d882b464aSumit Bose
99bac83188601c2b07e0b141aac7dc7d882b464aSumit Bose pollfd.desc.s = client_socket;
99bac83188601c2b07e0b141aac7dc7d882b464aSumit Bose apr_pollset_add(pollset, &pollfd);
99bac83188601c2b07e0b141aac7dc7d882b464aSumit Bose
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny remove_reqtimeout(c->input_filters);
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny r->output_filters = c->output_filters;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny r->proto_output_filters = c->output_filters;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny r->input_filters = c->input_filters;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny r->proto_input_filters = c->input_filters;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny /* This handler should take care of the entire connection; make it so that
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny * nothing else is attempted on the connection after returning. */
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny c->keepalive = AP_CONN_CLOSE;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny baton->r = r;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny baton->pollset = pollset;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny baton->client_soc = client_socket;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny baton->server_soc = sock;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny baton->proxy_connrec = conn;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny baton->bb = bb;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny apr_pool_create(&baton->subpool, r->pool);
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny status = proxy_wstunnel_pump(baton, apr_time_from_sec(5));
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny if (status == SUSPENDED) {
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny sockets[0] = baton->client_soc;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny sockets[1] = baton->server_soc;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny status = ap_mpm_register_socket_callback(sockets, baton->subpool, 1, proxy_wstunnel_callback, baton);
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny if (status == APR_SUCCESS) {
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny return SUSPENDED;
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny }
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny else if (status == APR_ENOTIMPL) {
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02544) "No asynch support");
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny status = proxy_wstunnel_pump(baton, -1);
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny }
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny else {
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r,
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny APLOGNO(02543) "error creating websockets tunnel");
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny return HTTP_INTERNAL_SERVER_ERROR;
}
}
return status;
}
/*
*/
static int proxy_wstunnel_handler(request_rec *r, proxy_worker *worker,
proxy_server_conf *conf,
char *url, const char *proxyname,
apr_port_t proxyport)
{
int status;
char server_portstr[32];
proxy_conn_rec *backend = NULL;
char *scheme;
int retry;
conn_rec *c = r->connection;
apr_pool_t *p = r->pool;
apr_uri_t *uri;
if (strncasecmp(url, "wss:", 4) == 0) {
scheme = "WSS";
}
else if (strncasecmp(url, "ws:", 3) == 0) {
scheme = "WS";
}
else {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02450) "declining URL %s", url);
return DECLINED;
}
uri = apr_palloc(p, sizeof(*uri));
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02451) "serving URL %s", url);
/* create space for state information */
status = ap_proxy_acquire_connection(scheme, &backend, worker,
r->server);
if (status != OK) {
if (backend) {
backend->close = 1;
ap_proxy_release_connection(scheme, backend, r->server);
}
return status;
}
backend->is_ssl = 0;
backend->close = 1;
retry = 0;
while (retry < 2) {
char *locurl = url;
/* Step One: Determine Who To Connect To */
status = ap_proxy_determine_connection(p, r, conf, worker, backend,
uri, &locurl, proxyname, proxyport,
server_portstr,
sizeof(server_portstr));
if (status != OK)
break;
/* Step Two: Make the Connection */
if (ap_proxy_connect_backend(scheme, backend, worker, r->server)) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02452)
"failed to make connection to backend: %s",
backend->hostname);
status = HTTP_SERVICE_UNAVAILABLE;
break;
}
/* Step Three: Create conn_rec */
if (!backend->connection) {
if ((status = ap_proxy_connection_create(scheme, backend,
c, r->server)) != OK)
break;
}
/* Step Three: Process the Request */
status = ap_proxy_wstunnel_request(p, r, backend, worker, conf, uri, locurl,
server_portstr);
break;
}
/* Do not close the socket */
if (status != SUSPENDED) {
ap_proxy_release_connection(scheme, backend, r->server);
}
return status;
}
static void ap_proxy_http_register_hook(apr_pool_t *p)
{
proxy_hook_scheme_handler(proxy_wstunnel_handler, NULL, NULL, APR_HOOK_FIRST);
proxy_hook_canon_handler(proxy_wstunnel_canon, NULL, NULL, APR_HOOK_FIRST);
}
AP_DECLARE_MODULE(proxy_wstunnel) = {
STANDARD20_MODULE_STUFF,
NULL, /* create per-directory config structure */
NULL, /* merge per-directory config structures */
NULL, /* create per-server config structure */
NULL, /* merge per-server config structures */
NULL, /* command apr_table_t */
ap_proxy_http_register_hook /* register hooks */
};