-mod-proxy-fdpass (0.1.1-1) unstable; urgency=low
+mod-proxy-fdpass2 (0.1.1-1) unstable; urgency=low
* Log for debugging disabled
-- Matteo Nastasi <nastasi@alternativeoutput.it> Thu, 21 Mar 2013 10:07:13 +0100
-mod-proxy-fdpass (0.1.0-1) unstable; urgency=low
+mod-proxy-fdpass2 (0.1.0-1) unstable; urgency=low
* First backport of fdpass module
+++ /dev/null
-# Depends: proxy
-LoadModule proxy_fdpass_module /usr/lib/apache2/modules/mod_proxy_fdpass.so
--- /dev/null
+# Depends: proxy
+LoadModule proxy_fdpass2_module /usr/lib/apache2/modules/mod_proxy_fdpass2.so
-Source: mod-proxy-fdpass
+Source: mod-proxy-fdpass2
Section: web
Priority: optional
Maintainer: Emmanuel Lacour <elacour@home-dn.net>
Build-Depends: debhelper (>= 4.0.0), apache2-prefork-dev (>> 2.2), libxml2-dev (>> 2.5.10)
Standards-Version: 0.1.0
-Package: libapache2-mod-proxy-fdpass
+Package: libapache2-mod-proxy-fdpass2
Architecture: any
-Depends: ${shlibs:Depends}, apache2, apache2.2-common, libxml2 (>> 2.5.10)
+Depends: ${shlibs:Depends}, apache2, apache2-data, libxml2 (>> 2.5.10)
Description: Apache2 filter module for HTML links rewriting
- mod_proxy_fdpass is an output filter to rewrite HTML links in a proxy
+ mod_proxy_fdpass2 is an output filter to rewrite HTML links in a proxy
situation, to ensure that links work for users outside the proxy. It
serves the same purpose as Apache's ProxyPassReverse directive does for
HTTP headers, and is an essential component of a reverse proxy.
-debian/conf/proxy_fdpass.load /etc/apache2/mods-available/
-proxy_fdpass.conf /etc/apache2/mods-available/
-.libs/mod_proxy_fdpass.so /usr/lib/apache2/modules/
+debian/conf/proxy_fdpass2.load /etc/apache2/mods-available/
+proxy_fdpass2.conf /etc/apache2/mods-available/
+.libs/mod_proxy_fdpass2.so /usr/lib/apache2/modules/
#! /bin/sh
-# postinst script for libapache2-mod-proxy-fdpass
+# postinst script for libapache2-mod-proxy-fdpass2
#
# see: dh_installdeb(1)
configure)
# Reload the module on upgrade if enabled
if [ -n "$2" ]; then
- if [ -e /etc/apache2/mods-enabled/proxy_fdpass.load ]; then
+ if [ -e /etc/apache2/mods-enabled/proxy_fdpass2.load ]; then
# We must reenable this module to enable the new configuration file
if dpkg --compare-versions "$2" lt "3.0.0-1" ; then
- a2dismod proxy_fdpass >/dev/null || true
- a2enmod proxy_fdpass >/dev/null || true
+ a2dismod proxy_fdpass2 >/dev/null || true
+ a2enmod proxy_fdpass2 >/dev/null || true
fi
reload_apache
fi
else
# Enable the module
if [ -e /etc/apache2/apache2.conf ]; then
- a2enmod proxy_fdpass >/dev/null || true
+ a2enmod proxy_fdpass2 >/dev/null || true
reload_apache
fi
fi
#! /bin/sh
-# prerm script for libapache2-mod-proxy-fdpass
+# prerm script for libapache2-mod-proxy-fdpass2
#
# see: dh_installdeb(1)
case "$1" in
remove)
- if [ -e /etc/apache2/mods-enabled/proxy_fdpass.load ]; then
- a2dismod proxy_fdpass >/dev/null || true
- reload_apache
- fi
- ;;
+ if [ -e /etc/apache2/mods-enabled/proxy_fdpass2.load ]; then
+ a2dismod proxy_fdpass2 >/dev/null || true
+ reload_apache
+ fi
+ ;;
upgrade|failed-upgrade|deconfigure)
- ;;
+ ;;
*)
echo "prerm called with unknown argument \`$1'" >&2
exit 1
build-stamp:
dh_testdir
- apxs2 -c -I/usr/include/libxml2 mod_proxy_fdpass.c
+ apxs2 -c -I/usr/include/libxml2 mod_proxy_fdpass2.c
touch build-stamp
clean:
dh_testdir
dh_testroot
- rm -f build-stamp mod_proxy_fdpass.la mod_proxy_fdpass.lo mod_proxy_fdpass.o mod_proxy_fdpass.slo
+ rm -f build-stamp mod_proxy_fdpass2.la mod_proxy_fdpass2.lo mod_proxy_fdpass2.o mod_proxy_fdpass2.slo
rm -rf .libs
dh_clean
+++ /dev/null
-/* Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "mod_proxy.h"
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-
-#ifndef CMSG_DATA
-#error This module only works on unix platforms with the correct OS support
-#endif
-
-#include "apr_version.h"
-#if APR_MAJOR_VERSION < 2
-/* for apr_wait_for_io_or_timeout */
-#include "apr_support.h"
-#endif
-
-#include "mod_proxy_fdpass.h"
-
-module AP_MODULE_DECLARE_DATA proxy_fdpass_module;
-
-#define MOP_DEBUG 0
-
-static int proxy_fdpass_canon(request_rec *r, char *url)
-{
- const char *path;
-
- if (MOP_DEBUG == 1) {
- int mop_fd;
- char mop_bf[512];
-
- mop_fd = open("/tmp/apache_mop.log", O_WRONLY | O_APPEND | O_CREAT, 0644);
- sprintf(mop_bf, "proxy_http_canon: start\n");
- write(mop_fd, mop_bf, strlen(mop_bf));
- close(mop_fd);
-
- }
-
- if (strncasecmp(url, "fd://", 5) == 0) {
- url += 5;
- }
- else {
- return DECLINED;
- }
-
- path = ap_server_root_relative(r->pool, url);
-
- r->filename = apr_pstrcat(r->pool, "proxy:fd://", path, NULL);
-
- /* ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
- "proxy: FD: set r->filename to %s", r->filename); */
- return OK;
-}
-
-/* TODO: In APR 2.x: Extend apr_sockaddr_t to possibly be a path !!! */
-static apr_status_t socket_connect_un(request_rec *r, apr_socket_t *sock,
- struct sockaddr_un *sa)
-{
- apr_status_t rv;
- apr_os_sock_t rawsock;
- apr_interval_time_t t;
-
- rv = apr_os_sock_get(&rawsock, sock);
- if (rv != APR_SUCCESS) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
- "proxy: FD: apr_os_sock_get failed");
- return rv;
- }
-
- rv = apr_socket_timeout_get(sock, &t);
- if (rv != APR_SUCCESS) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
- "proxy: FD: apr_socket_timeout_get failed");
- return rv;
- }
-
- do {
- /* ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
- "proxy: FD: pre_connect"); */
- rv = connect(rawsock, (struct sockaddr*)sa,
- sizeof(*sa) /* + strlen(sa->sun_path)*/ );
- /* ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
- "proxy: FD: post_connect %d", rv); */
- } while (rv == -1 && errno == EINTR);
-
- if ((rv == -1) && (errno == EINPROGRESS || errno == EALREADY)
- && (t > 0)) {
-#if APR_MAJOR_VERSION < 2
- rv = apr_wait_for_io_or_timeout(NULL, sock, 0);
-#else
- rv = apr_socket_wait(sock, APR_WAIT_WRITE);
-#endif
-
- if (rv != APR_SUCCESS) {
- ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, NULL,
- "proxy: FD: apr_socket_wait failed");
- return rv;
- }
- }
-
- if (rv == -1 && errno != EISCONN) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
- "proxy: FD: socket_connect_un preexit %d", errno);
- return errno;
- }
-
- return APR_SUCCESS;
-}
-
-static apr_status_t get_socket_from_path(request_rec *r, apr_pool_t *p,
- const char* path,
- apr_socket_t **out_sock)
-{
- struct sockaddr_un sa;
- apr_socket_t *s;
- apr_status_t rv;
- *out_sock = NULL;
-
- /*
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
- "proxy: FD: Failed to connect to '%s' %d xxx",
- url, rv);
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
- "proxy: FD: get_socket_from_path::START");
- */
-
- rv = apr_socket_create(&s, AF_UNIX, SOCK_STREAM, 0, p);
-
- if (rv != APR_SUCCESS) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
- "proxy: FD: get_socket_from_path::create %d", rv);
- return rv;
- }
-
- sa.sun_family = AF_UNIX;
- apr_cpystrn(sa.sun_path, path, sizeof(sa.sun_path));
-
- rv = socket_connect_un(r, s, &sa);
- if (rv != APR_SUCCESS) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
- "proxy: FD: get_socket_from_path::connect_un %d", rv);
- return rv;
- }
-
- *out_sock = s;
-
- return APR_SUCCESS;
-}
-
-#define ANCIL_FD_BUFFER(n) \
- struct { \
- struct cmsghdr h; \
- int fd[n]; \
- }
-
-static apr_status_t send_socket(apr_pool_t *p,
- apr_socket_t *s,
- apr_socket_t *outbound,
- apr_socket_t *ctrlsock)
-{
- apr_status_t rv;
- apr_os_sock_t rawsock;
- apr_os_sock_t srawsock;
- apr_os_sock_t sctrlsock;
- struct msghdr msg;
- struct cmsghdr *cmsg;
- struct iovec iov;
- char b = '\0', *buf;
- ANCIL_FD_BUFFER(2) ancil_buf;
-
- if (MOP_DEBUG == 1) {
- int mop_fd;
- char mop_bf[512];
-
- mop_fd = open("/tmp/apache_mop.log", O_WRONLY | O_APPEND | O_CREAT, 0644);
- sprintf(mop_bf, "send_socket: start\n");
- write(mop_fd, mop_bf, strlen(mop_bf));
- close(mop_fd);
- }
-
- rv = apr_os_sock_get(&rawsock, outbound);
- if (rv != APR_SUCCESS) {
- return rv;
- }
-
- rv = apr_os_sock_get(&srawsock, s);
- if (rv != APR_SUCCESS) {
- return rv;
- }
-
- rv = apr_os_sock_get(&sctrlsock, ctrlsock);
- if (rv != APR_SUCCESS) {
- return rv;
- }
-
- if (MOP_DEBUG == 1) {
- int mop_fd;
- char mop_bf[512];
-
- mop_fd = open("/tmp/apache_mop.log", O_WRONLY | O_APPEND | O_CREAT, 0644);
- write(mop_fd, "XX", 2);
- write(mop_fd, &srawsock, sizeof(apr_os_sock_t));
- write(mop_fd, "XX", 2);
- close(mop_fd);
- }
-
- memset(&msg, 0, sizeof(msg));
-
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
-
- iov.iov_base = &b;
- iov.iov_len = 1;
-
- msg.msg_control = &ancil_buf;
- msg.msg_controllen = sizeof(struct cmsghdr) + sizeof(rawsock) * 2;
-
- // cmsg = apr_palloc(p, sizeof(*cmsg) + sizeof(rawsock));
- cmsg = CMSG_FIRSTHDR(&msg);
- cmsg->cmsg_len = sizeof(*cmsg) + sizeof(rawsock) * 2;
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
-
- ((int *)CMSG_DATA(cmsg))[0] = rawsock;
- ((int *)CMSG_DATA(cmsg))[1] = sctrlsock;
-
- rv = sendmsg(srawsock, &msg, 0);
-
- if (MOP_DEBUG == 1) {
- int mop_fd;
- char mop_bf[512];
-
- mop_fd = open("/tmp/apache_mop.log", O_WRONLY | O_APPEND | O_CREAT, 0644);
- sprintf(mop_bf, "SENT BYTES: %d\n", rv);
- write(mop_fd, mop_bf, strlen(mop_bf));
- close(mop_fd);
- }
-
- if (rv == -1) {
- return errno;
- }
-
-
- return APR_SUCCESS;
-}
-
-static int headers_builder(void *rec, const char *key, const char *value)
-{
- char *s;
-
- s = (char *)rec;
-
- // TODO: verify length
- sprintf(s, "%s%s:%s\n", s, key, value);
-}
-
-#define CTRL_BUFF_MAX_SZ (8*1024)
-
-#define DEFAULT_ENCTYPE "application/x-www-form-urlencoded"
-
-int util_read(request_rec *r, const char **rbuf)
-{
- int rc;
-
- if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR)) != OK) {
- return rc;
- }
-
- if (ap_should_client_block(r)) {
- char argsbuffer[HUGE_STRING_LEN];
- int rsize, len_read, rpos=0;
- long length = r->remaining;
- *rbuf = (char *)apr_pcalloc(r->pool, length +1);
- if ((len_read = ap_get_client_block(r, argsbuffer,
- sizeof(argsbuffer))) > 0) {
- if ((rpos + len_read) > length) {
- rsize = length - rpos;
- } else {
- rsize = len_read;
- }
-
- memcpy((char *)*rbuf + rpos, argsbuffer, rsize);
- rpos += rsize;
- }
-
- }
-
- return rc;
-}
-
-int read_post(request_rec *r, const char **data)
-{
- const char *type;
- char *p, s_type[256];
- int rc = OK;
-
- s_type[255] = '\0';
- if (MOP_DEBUG == 1) {
- int mop_fd;
- char mop_bf[512];
-
- mop_fd = open("/tmp/apache_mop.log", O_WRONLY | O_APPEND | O_CREAT, 0644);
- sprintf(mop_bf, "read_post: start: numb: %d %d head_in: [%s]\n", r->method_number, M_POST, apr_table_get(r->headers_in, "Content-Type"));
- write(mop_fd, mop_bf, strlen(mop_bf));
- close(mop_fd);
- }
-
-
- if (r->method_number != M_POST) {
- return rc;
- }
-
- type = apr_table_get(r->headers_in, "Content-Type");
- strncpy(s_type, type, 255);
- if (p = strchr(s_type, ';')) {
- *p = '\0';
- }
- if (strcasecmp(s_type, DEFAULT_ENCTYPE) != 0) {
- return DECLINED;
- }
-
- if ((rc = util_read(r, data)) != OK) {
- return rc;
- }
-
- if (MOP_DEBUG == 1) {
- int mop_fd;
- char mop_bf[512];
-
- mop_fd = open("/tmp/apache_mop.log", O_WRONLY | O_APPEND | O_CREAT, 0644);
- sprintf(mop_bf, "read_post: finish\n");
- write(mop_fd, mop_bf, strlen(mop_bf));
- close(mop_fd);
- }
-
- return OK;
-}
-
-
-// TODO: sanitize calloc
-static int proxy_fdpass_handler(request_rec *r, proxy_worker *worker,
- proxy_server_conf *conf,
- char *url, const char *proxyname,
- apr_port_t proxyport)
-{
- apr_status_t rv;
- apr_socket_t *sock;
- apr_socket_t *clientsock;
- char *buf;
- char *headers_out = NULL;
- int ctrlrawsock[2];
- apr_socket_t *ctrlsock = NULL, *clientctrlsock = NULL;
- apr_size_t wrlen;
- const char *post_data = NULL;
-
- ap_filter_t *f;
- ap_filter_rec_t *fg;
-
- if (strncasecmp(url, "fd://", 5) == 0) {
- url += 5;
- }
- else {
- return DECLINED;
- }
-
- rv = get_socket_from_path(r, r->pool, url, &sock);
-
- if (rv != APR_SUCCESS) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
- "proxy: FD: Failed to connect to '%s' %d xxx",
- url, rv);
- return HTTP_INTERNAL_SERVER_ERROR;
- }
-
- fg = ap_get_output_filter_handle("HTTP_HEADER");
-
- /*
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "proxy: FD: filter fg: %lx func %lx", fg, ap_http_header_filter);
- */
-
- for (f = r->output_filters ; f != NULL ; f = f->next) {
- /* ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "proxy: FD: filter loop: %lx", f->frec);
- */
- if (f->frec == fg) {
- /*
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "proxy: FD: filter found, remove it");
- */
- ap_remove_output_filter(f);
- break;
- }
- }
-
- if ((headers_out = calloc(CTRL_BUFF_MAX_SZ, 1)) != NULL) {
- sprintf(headers_out, "The-Request:%s\n", r->the_request);
- apr_table_do(headers_builder, headers_out, r->headers_in, NULL);
- }
- read_post(r, &post_data);
-
- if (MOP_DEBUG == 1) {
- int mop_fd;
- char mop_bf[512];
-
- mop_fd = open("/tmp/apache_mop.log", O_WRONLY | O_APPEND | O_CREAT, 0644);
- sprintf(mop_bf, "proxy_fdpass_handler: start\n");
- write(mop_fd, mop_bf, strlen(mop_bf));
- write(mop_fd, headers_out, strlen(headers_out));
- close(mop_fd);
- }
- /* create a couple of sockets and pass one to the client for headers and so on */
- if (socketpair(AF_UNIX, SOCK_STREAM, 0, ctrlrawsock)) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
- "proxy: FD: Failed create socketpair");
- return HTTP_INTERNAL_SERVER_ERROR;
- }
- rv = apr_os_sock_put(&ctrlsock, &(ctrlrawsock[0]), r->connection->pool);
- if (rv != APR_SUCCESS) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
- "proxy: FD: apr_os_sock_put failed");
- return HTTP_INTERNAL_SERVER_ERROR;
- }
- rv = apr_os_sock_put(&clientctrlsock, &(ctrlrawsock[1]), r->connection->pool);
- if (rv != APR_SUCCESS) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
- "proxy: FD: apr_os_sock_put failed");
- return HTTP_INTERNAL_SERVER_ERROR;
- }
-
- {
- int status;
- /* const char *flush_method = worker->flusher ? worker->flusher : "flush"; */
- const char *flush_method = "flush";
-
- proxy_fdpass_flush *flush = ap_lookup_provider(PROXY_FDPASS_FLUSHER,
- flush_method, "0");
-
- if (!flush) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
- "proxy: FD: Unable to find configured flush "
- "provider '%s'", flush_method);
- return HTTP_INTERNAL_SERVER_ERROR;
- }
-
- status = flush->flusher(r);
- if (status) {
- return status;
- }
- }
-
- /*
- if ((buf = apr_table_get(r->headers_in, "Host"))) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
- "proxy: FD: Host is: [%s]", buf);
- }
- */
-
- /* XXXXX: THIS IS AN EVIL HACK */
- /* There should really be a (documented) public API for this ! */
- clientsock = ap_get_module_config(r->connection->conn_config, &core_module);
-
- rv = send_socket(r->pool, sock, clientsock, clientctrlsock);
- if (rv != APR_SUCCESS) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
- "proxy: FD: send_socket failed:");
- return HTTP_INTERNAL_SERVER_ERROR;
- }
- strcat(headers_out, "\n");
- wrlen = strlen(headers_out);
- rv = apr_socket_send(ctrlsock, headers_out, &wrlen);
- if (rv != APR_SUCCESS) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
- "proxy: FD: send headers failed");
- return HTTP_INTERNAL_SERVER_ERROR;
- }
- if (post_data) {
- wrlen = strlen(post_data);
- rv = apr_socket_send(ctrlsock, post_data, &wrlen);
- if (rv != APR_SUCCESS) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
- "proxy: FD: send post failed");
- return HTTP_INTERNAL_SERVER_ERROR;
- }
- }
- apr_socket_shutdown(ctrlsock, APR_SHUTDOWN_READWRITE);
- if (headers_out)
- free(headers_out);
-
- {
- apr_socket_t *dummy;
- /* Create a dummy unconnected socket, and set it as the one we were
- * connected to, so that when the core closes it, it doesn't close
- * the tcp connection to the client.
- */
- rv = apr_socket_create(&dummy, APR_INET, SOCK_STREAM, APR_PROTO_TCP,
- r->connection->pool);
- if (rv != APR_SUCCESS) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
- "proxy: FD: failed to create dummy socket");
- return HTTP_INTERNAL_SERVER_ERROR;
- }
- ap_set_module_config(r->connection->conn_config, &core_module, dummy);
- }
-
-
- return OK;
-}
-
-static int standard_flush(request_rec *r)
-{
- int status;
- apr_bucket_brigade *bb;
- apr_bucket *e;
- apr_pool_t *p = r->pool;
-
- r->connection->keepalive = AP_CONN_CLOSE;
- /* MOP NOTE: set here the content type */
- // ap_set_content_type(r, apr_pstrdup(p, NO_CONTENT_TYPE));
- bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
- e = apr_bucket_flush_create(r->connection->bucket_alloc);
-
- APR_BRIGADE_INSERT_TAIL(bb, e);
-
- status = ap_pass_brigade(r->output_filters, bb);
-
- if (status != OK) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r,
- "proxy: FD: ap_pass_brigade failed:");
- return status;
- }
-
- return OK;
-}
-
-static const proxy_fdpass_flush builtin_flush =
-{
- "flush",
- &standard_flush,
- NULL
-};
-
-static void ap_proxy_fdpass_register_hooks(apr_pool_t *p)
-{
- ap_register_provider(p, PROXY_FDPASS_FLUSHER, "flush", "0", &builtin_flush);
- proxy_hook_scheme_handler(proxy_fdpass_handler, NULL, NULL, APR_HOOK_FIRST);
- proxy_hook_canon_handler(proxy_fdpass_canon, NULL, NULL, APR_HOOK_FIRST);
-}
-
-module AP_MODULE_DECLARE_DATA proxy_fdpass_module = {
- 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_fdpass_register_hooks /* register hooks */
-};
+++ /dev/null
-/* Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * @file mod_proxy_fdpass.h
- * @brief FD Passing interfaces
- *
- * @addtogroup FDPass_provider
- * @{
- */
-
- #include "mod_proxy.h"
-
-#ifndef _PROXY_FDPASS_H_
-#define _PROXY_FDPASS_H_
-
-#define PROXY_FDPASS_FLUSHER "proxy_fdpass_flusher"
-
-typedef struct proxy_fdpass_flush proxy_fdpass_flush;
-struct proxy_fdpass_flush {
- const char *name;
- int (*flusher)(request_rec *r);
- void *context;
-};
-
-#endif /* _PROXY_FDPASS_H_ */
-/** @} */
-
--- /dev/null
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mod_proxy.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#ifndef CMSG_DATA
+#error This module only works on unix platforms with the correct OS support
+#endif
+
+#include "apr_version.h"
+#if APR_MAJOR_VERSION < 2
+/* for apr_wait_for_io_or_timeout */
+#include "apr_support.h"
+#endif
+
+#include "mod_proxy_fdpass2.h"
+
+module AP_MODULE_DECLARE_DATA proxy_fdpass2_module;
+
+#define MOP_DEBUG 1
+
+static int proxy_fdpass2_canon(request_rec *r, char *url)
+{
+ const char *path;
+
+ if (MOP_DEBUG == 1) {
+ int mop_fd;
+ char mop_bf[512];
+
+ mop_fd = open("/tmp/apache_mop.log", O_WRONLY | O_APPEND | O_CREAT, 0644);
+ sprintf(mop_bf, "proxy_http_canon: start [%p]\n", r->headers_in);
+ write(mop_fd, mop_bf, strlen(mop_bf));
+ close(mop_fd);
+
+ }
+
+ if (strncasecmp(url, "fd://", 5) == 0) {
+ url += 5;
+ }
+ else {
+ return DECLINED;
+ }
+
+ path = ap_server_root_relative(r->pool, url);
+
+ r->filename = apr_pstrcat(r->pool, "proxy:fd://", path, NULL);
+
+ /* ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+ "proxy: FD: set r->filename to %s", r->filename); */
+ return OK;
+}
+
+/* TODO: In APR 2.x: Extend apr_sockaddr_t to possibly be a path !!! */
+static apr_status_t socket_connect_un(request_rec *r, apr_socket_t *sock,
+ struct sockaddr_un *sa)
+{
+ apr_status_t rv;
+ apr_os_sock_t rawsock;
+ apr_interval_time_t t;
+
+ rv = apr_os_sock_get(&rawsock, sock);
+ if (rv != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ "proxy: FD: apr_os_sock_get failed");
+ return rv;
+ }
+
+ rv = apr_socket_timeout_get(sock, &t);
+ if (rv != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ "proxy: FD: apr_socket_timeout_get failed");
+ return rv;
+ }
+
+ do {
+ /* ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ "proxy: FD: pre_connect"); */
+ rv = connect(rawsock, (struct sockaddr*)sa,
+ sizeof(*sa) /* + strlen(sa->sun_path)*/ );
+ /* ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ "proxy: FD: post_connect %d", rv); */
+ } while (rv == -1 && errno == EINTR);
+
+ if ((rv == -1) && (errno == EINPROGRESS || errno == EALREADY)
+ && (t > 0)) {
+#if APR_MAJOR_VERSION < 2
+ rv = apr_wait_for_io_or_timeout(NULL, sock, 0);
+#else
+ rv = apr_socket_wait(sock, APR_WAIT_WRITE);
+#endif
+
+ if (rv != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, NULL,
+ "proxy: FD: apr_socket_wait failed");
+ return rv;
+ }
+ }
+
+ if (rv == -1 && errno != EISCONN) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ "proxy: FD: socket_connect_un preexit %d", errno);
+ return errno;
+ }
+
+ return APR_SUCCESS;
+}
+
+static apr_status_t get_socket_from_path(request_rec *r, apr_pool_t *p,
+ const char* path,
+ apr_socket_t **out_sock)
+{
+ struct sockaddr_un sa;
+ apr_socket_t *s;
+ apr_status_t rv;
+ *out_sock = NULL;
+
+ /*
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ "proxy: FD: Failed to connect to '%s' %d xxx",
+ url, rv);
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ "proxy: FD: get_socket_from_path::START");
+ */
+
+ rv = apr_socket_create(&s, AF_UNIX, SOCK_STREAM, 0, p);
+
+ if (rv != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ "proxy: FD: get_socket_from_path::create %d", rv);
+ return rv;
+ }
+
+ sa.sun_family = AF_UNIX;
+ apr_cpystrn(sa.sun_path, path, sizeof(sa.sun_path));
+
+ rv = socket_connect_un(r, s, &sa);
+ if (rv != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ "proxy: FD: get_socket_from_path::connect_un %d", rv);
+ return rv;
+ }
+
+ *out_sock = s;
+
+ return APR_SUCCESS;
+}
+
+#define ANCIL_FD_BUFFER(n) \
+ struct { \
+ struct cmsghdr h; \
+ int fd[n]; \
+ }
+
+static apr_status_t send_socket(apr_pool_t *p,
+ apr_socket_t *s,
+ apr_socket_t *outbound,
+ apr_socket_t *ctrlsock)
+{
+ apr_status_t rv;
+ apr_os_sock_t rawsock;
+ apr_os_sock_t srawsock;
+ apr_os_sock_t sctrlsock;
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ struct iovec iov;
+ char b = '\0', *buf;
+ ANCIL_FD_BUFFER(2) ancil_buf;
+
+ if (MOP_DEBUG == 1) {
+ int mop_fd;
+ char mop_bf[512];
+
+ mop_fd = open("/tmp/apache_mop.log", O_WRONLY | O_APPEND | O_CREAT, 0644);
+ sprintf(mop_bf, "send_socket: start\n");
+ write(mop_fd, mop_bf, strlen(mop_bf));
+ close(mop_fd);
+ }
+
+ rv = apr_os_sock_get(&rawsock, outbound);
+ if (rv != APR_SUCCESS) {
+ return rv;
+ }
+
+ rv = apr_os_sock_get(&srawsock, s);
+ if (rv != APR_SUCCESS) {
+ return rv;
+ }
+
+ rv = apr_os_sock_get(&sctrlsock, ctrlsock);
+ if (rv != APR_SUCCESS) {
+ return rv;
+ }
+
+ if (MOP_DEBUG == 1) {
+ int mop_fd;
+ char mop_bf[512];
+
+ mop_fd = open("/tmp/apache_mop.log", O_WRONLY | O_APPEND | O_CREAT, 0644);
+ write(mop_fd, "XX", 2);
+ write(mop_fd, &srawsock, sizeof(apr_os_sock_t));
+ write(mop_fd, "XX", 2);
+ close(mop_fd);
+ }
+
+ memset(&msg, 0, sizeof(msg));
+
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ iov.iov_base = &b;
+ iov.iov_len = 1;
+
+ msg.msg_control = &ancil_buf;
+ msg.msg_controllen = sizeof(struct cmsghdr) + sizeof(rawsock) * 2;
+
+ // cmsg = apr_palloc(p, sizeof(*cmsg) + sizeof(rawsock));
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_len = sizeof(*cmsg) + sizeof(rawsock) * 2;
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+
+ ((int *)CMSG_DATA(cmsg))[0] = rawsock;
+ ((int *)CMSG_DATA(cmsg))[1] = sctrlsock;
+
+ rv = sendmsg(srawsock, &msg, 0);
+
+ if (MOP_DEBUG == 1) {
+ int mop_fd;
+ char mop_bf[512];
+
+ mop_fd = open("/tmp/apache_mop.log", O_WRONLY | O_APPEND | O_CREAT, 0644);
+ sprintf(mop_bf, "SENT BYTES: %d\n", rv);
+ write(mop_fd, mop_bf, strlen(mop_bf));
+ close(mop_fd);
+ }
+
+ if (rv == -1) {
+ return errno;
+ }
+
+
+ return APR_SUCCESS;
+}
+
+static int headers_builder(void *rec, const char *key, const char *value)
+{
+ char *s;
+
+ s = (char *)rec;
+
+ if (MOP_DEBUG == 1) {
+ int mop_fd;
+ char mop_bf[512];
+
+ mop_fd = open("/tmp/apache_mop.log", O_WRONLY | O_APPEND | O_CREAT, 0644);
+ sprintf(mop_bf, "HEADERS_BUILDER: [%s:%s]\n", key, value);
+ write(mop_fd, mop_bf, strlen(mop_bf));
+ close(mop_fd);
+ }
+
+
+ // TODO: verify length
+ // sprintf(s, "%s%s:%s\n", s, key, value);
+ strcat(s, key);
+ strcat(s, ":");
+ strcat(s, value);
+ strcat(s, "\n");
+}
+
+#define CTRL_BUFF_MAX_SZ (8*1024)
+
+#define DEFAULT_ENCTYPE "application/x-www-form-urlencoded"
+
+int util_read(request_rec *r, const char **rbuf)
+{
+ int rc;
+
+ if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR)) != OK) {
+ return rc;
+ }
+
+ if (ap_should_client_block(r)) {
+ char argsbuffer[HUGE_STRING_LEN];
+ int rsize, len_read, rpos=0;
+ long length = r->remaining;
+ *rbuf = (char *)apr_pcalloc(r->pool, length +1);
+ if ((len_read = ap_get_client_block(r, argsbuffer,
+ sizeof(argsbuffer))) > 0) {
+ if ((rpos + len_read) > length) {
+ rsize = length - rpos;
+ } else {
+ rsize = len_read;
+ }
+
+ memcpy((char *)*rbuf + rpos, argsbuffer, rsize);
+ rpos += rsize;
+ }
+
+ }
+
+ return rc;
+}
+
+int read_post(request_rec *r, const char **data)
+{
+ const char *type;
+ char *p, s_type[256];
+ int rc = OK;
+
+ s_type[255] = '\0';
+ if (MOP_DEBUG == 1) {
+ int mop_fd;
+ char mop_bf[512];
+
+ mop_fd = open("/tmp/apache_mop.log", O_WRONLY | O_APPEND | O_CREAT, 0644);
+ sprintf(mop_bf, "read_post: start: numb: %d %d head_in: [%s]\n", r->method_number, M_POST, apr_table_get(r->headers_in, "Content-Type"));
+ write(mop_fd, mop_bf, strlen(mop_bf));
+ close(mop_fd);
+ }
+
+
+ if (r->method_number != M_POST) {
+ return rc;
+ }
+
+ type = apr_table_get(r->headers_in, "Content-Type");
+ strncpy(s_type, type, 255);
+ if (p = strchr(s_type, ';')) {
+ *p = '\0';
+ }
+
+ if (strcasecmp(s_type, DEFAULT_ENCTYPE) != 0) {
+ return DECLINED;
+ }
+
+ if ((rc = util_read(r, data)) != OK) {
+ return rc;
+ }
+
+ if (MOP_DEBUG == 1) {
+ int mop_fd;
+ char mop_bf[512];
+
+ mop_fd = open("/tmp/apache_mop.log", O_WRONLY | O_APPEND | O_CREAT, 0644);
+ sprintf(mop_bf, "read_post: finish\n");
+ write(mop_fd, mop_bf, strlen(mop_bf));
+ close(mop_fd);
+ }
+
+ return OK;
+}
+
+
+// TODO: sanitize calloc
+static int proxy_fdpass2_handler(request_rec *r, proxy_worker *worker,
+ proxy_server_conf *conf,
+ char *url, const char *proxyname,
+ apr_port_t proxyport)
+{
+ apr_status_t rv;
+ apr_socket_t *sock;
+ apr_socket_t *clientsock;
+ char *buf;
+ char *headers_out = NULL;
+ int ctrlrawsock[2];
+ apr_socket_t *ctrlsock = NULL, *clientctrlsock = NULL;
+ apr_size_t wrlen;
+ const char *post_data = NULL;
+
+ ap_filter_t *f;
+ ap_filter_rec_t *fg;
+
+ if (strncasecmp(url, "fd://", 5) == 0) {
+ url += 5;
+ }
+ else {
+ return DECLINED;
+ }
+
+ rv = get_socket_from_path(r, r->pool, url, &sock);
+
+ if (rv != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ "proxy: FD: Failed to connect to '%s' %d xxx",
+ url, rv);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ fg = ap_get_output_filter_handle("HTTP_HEADER");
+
+ /*
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "proxy: FD: filter fg: %lx func %lx", fg, ap_http_header_filter);
+ */
+
+ for (f = r->output_filters ; f != NULL ; f = f->next) {
+ /* ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "proxy: FD: filter loop: %lx", f->frec);
+ */
+ if (f->frec == fg) {
+ /*
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "proxy: FD: filter found, remove it");
+ */
+ ap_remove_output_filter(f);
+ break;
+ }
+ }
+
+ if ((headers_out = calloc(CTRL_BUFF_MAX_SZ, 1)) != NULL) {
+ sprintf(headers_out, "The-Request:%s\n", r->the_request);
+ apr_table_do(headers_builder, headers_out, r->headers_in, NULL);
+ }
+ read_post(r, &post_data);
+
+ if (MOP_DEBUG == 1) {
+ int mop_fd;
+ char mop_bf[512];
+
+ mop_fd = open("/tmp/apache_mop.log", O_WRONLY | O_APPEND | O_CREAT, 0644);
+ sprintf(mop_bf, "proxy_fdpass2_handler: start\n");
+ write(mop_fd, mop_bf, strlen(mop_bf));
+ write(mop_fd, headers_out, strlen(headers_out));
+ close(mop_fd);
+ }
+ /* create a couple of sockets and pass one to the client for headers and so on */
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, ctrlrawsock)) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ "proxy: FD: Failed create socketpair");
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+ rv = apr_os_sock_put(&ctrlsock, &(ctrlrawsock[0]), r->connection->pool);
+ if (rv != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ "proxy: FD: apr_os_sock_put failed");
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+ rv = apr_os_sock_put(&clientctrlsock, &(ctrlrawsock[1]), r->connection->pool);
+ if (rv != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ "proxy: FD: apr_os_sock_put failed");
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ {
+ int status;
+ /* const char *flush_method = worker->flusher ? worker->flusher : "flush"; */
+ const char *flush_method = "flush";
+
+ proxy_fdpass2_flush *flush = ap_lookup_provider(PROXY_FDPASS_FLUSHER,
+ flush_method, "0");
+
+ if (!flush) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ "proxy: FD: Unable to find configured flush "
+ "provider '%s'", flush_method);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ status = flush->flusher(r);
+ if (status) {
+ return status;
+ }
+ }
+
+ /*
+ if ((buf = apr_table_get(r->headers_in, "Host"))) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ "proxy: FD: Host is: [%s]", buf);
+ }
+ */
+
+ /* XXXXX: THIS IS AN EVIL HACK */
+ /* There should really be a (documented) public API for this ! */
+ clientsock = ap_get_module_config(r->connection->conn_config, &core_module);
+
+ rv = send_socket(r->pool, sock, clientsock, clientctrlsock);
+ if (rv != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ "proxy: FD: send_socket failed:");
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+ strcat(headers_out, "\n");
+ wrlen = strlen(headers_out);
+ rv = apr_socket_send(ctrlsock, headers_out, &wrlen);
+
+ if (MOP_DEBUG == 1) {
+ int mop_fd;
+ char mop_bf[512];
+
+ mop_fd = open("/tmp/apache_mop.log", O_WRONLY | O_APPEND | O_CREAT, 0644);
+ write(mop_fd, "HEADERS_OUT\n", 12);
+ write(mop_fd, headers_out, wrlen);
+ close(mop_fd);
+ }
+
+
+ if (rv != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ "proxy: FD: send headers failed");
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+ if (post_data) {
+ wrlen = strlen(post_data);
+ rv = apr_socket_send(ctrlsock, post_data, &wrlen);
+ if (rv != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ "proxy: FD: send post failed");
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+ }
+ apr_socket_shutdown(ctrlsock, APR_SHUTDOWN_READWRITE);
+ if (headers_out)
+ free(headers_out);
+
+ {
+ apr_socket_t *dummy;
+ /* Create a dummy unconnected socket, and set it as the one we were
+ * connected to, so that when the core closes it, it doesn't close
+ * the tcp connection to the client.
+ */
+ rv = apr_socket_create(&dummy, APR_INET, SOCK_STREAM, APR_PROTO_TCP,
+ r->connection->pool);
+ if (rv != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ "proxy: FD: failed to create dummy socket");
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+ ap_set_module_config(r->connection->conn_config, &core_module, dummy);
+ }
+
+
+ return OK;
+}
+
+static int standard_flush(request_rec *r)
+{
+ int status;
+ apr_bucket_brigade *bb;
+ apr_bucket *e;
+ apr_pool_t *p = r->pool;
+
+ r->connection->keepalive = AP_CONN_CLOSE;
+ /* MOP NOTE: set here the content type */
+ // ap_set_content_type(r, apr_pstrdup(p, NO_CONTENT_TYPE));
+ bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
+ e = apr_bucket_flush_create(r->connection->bucket_alloc);
+
+ APR_BRIGADE_INSERT_TAIL(bb, e);
+
+ status = ap_pass_brigade(r->output_filters, bb);
+
+ if (status != OK) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r,
+ "proxy: FD: ap_pass_brigade failed:");
+ return status;
+ }
+
+ return OK;
+}
+
+static const proxy_fdpass2_flush builtin_flush =
+{
+ "flush",
+ &standard_flush,
+ NULL
+};
+
+static void ap_proxy_fdpass2_register_hooks(apr_pool_t *p)
+{
+ ap_register_provider(p, PROXY_FDPASS_FLUSHER, "flush", "0", &builtin_flush);
+ proxy_hook_scheme_handler(proxy_fdpass2_handler, NULL, NULL, APR_HOOK_FIRST);
+ proxy_hook_canon_handler(proxy_fdpass2_canon, NULL, NULL, APR_HOOK_FIRST);
+}
+
+module AP_MODULE_DECLARE_DATA proxy_fdpass2_module = {
+ 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_fdpass2_register_hooks /* register hooks */
+};
--- /dev/null
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file mod_proxy_fdpass2.h
+ * @brief FD Passing interfaces
+ *
+ * @addtogroup FDPass_provider
+ * @{
+ */
+
+ #include "mod_proxy.h"
+
+#ifndef _PROXY_FDPASS_H_
+#define _PROXY_FDPASS_H_
+
+#define PROXY_FDPASS_FLUSHER "proxy_fdpass2_flusher"
+
+typedef struct proxy_fdpass2_flush proxy_fdpass2_flush;
+struct proxy_fdpass2_flush {
+ const char *name;
+ int (*flusher)(request_rec *r);
+ void *context;
+};
+
+#endif /* _PROXY_FDPASS_H_ */
+/** @} */
+
+++ /dev/null
-<IfModule mod_proxy_fdpass.c>
-
-</IfModule>
--- /dev/null
+<IfModule mod_proxy_fdpass2.c>
+
+</IfModule>