From: Matteo Nastasi Date: Mon, 10 Jul 2017 08:59:08 +0000 (+0200) Subject: move to proxy_fdpass2 name plugin to avoid clash names X-Git-Tag: v2.0.0~1 X-Git-Url: http://mop.ddnsfree.com/gitweb/?a=commitdiff_plain;h=a10c60232480678fdc9ea2314df64e0655eb169b;p=mod-proxy-fdpass.git move to proxy_fdpass2 name plugin to avoid clash names --- diff --git a/debian/changelog b/debian/changelog index 5d7a3b6..48552da 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,10 +1,10 @@ -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 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 diff --git a/debian/conf/proxy_fdpass.load b/debian/conf/proxy_fdpass.load deleted file mode 100644 index b27bcdb..0000000 --- a/debian/conf/proxy_fdpass.load +++ /dev/null @@ -1,2 +0,0 @@ -# Depends: proxy -LoadModule proxy_fdpass_module /usr/lib/apache2/modules/mod_proxy_fdpass.so diff --git a/debian/conf/proxy_fdpass2.load b/debian/conf/proxy_fdpass2.load new file mode 100644 index 0000000..29a0f8f --- /dev/null +++ b/debian/conf/proxy_fdpass2.load @@ -0,0 +1,2 @@ +# Depends: proxy +LoadModule proxy_fdpass2_module /usr/lib/apache2/modules/mod_proxy_fdpass2.so diff --git a/debian/control b/debian/control index 8ed91bf..5567697 100644 --- a/debian/control +++ b/debian/control @@ -1,15 +1,15 @@ -Source: mod-proxy-fdpass +Source: mod-proxy-fdpass2 Section: web Priority: optional Maintainer: Emmanuel Lacour 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. diff --git a/debian/install b/debian/install index 0cb76a2..489c254 100644 --- a/debian/install +++ b/debian/install @@ -1,3 +1,3 @@ -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/ diff --git a/debian/postinst b/debian/postinst index e3cf6f7..da6d769 100644 --- a/debian/postinst +++ b/debian/postinst @@ -1,5 +1,5 @@ #! /bin/sh -# postinst script for libapache2-mod-proxy-fdpass +# postinst script for libapache2-mod-proxy-fdpass2 # # see: dh_installdeb(1) @@ -31,18 +31,18 @@ case "$1" in 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 diff --git a/debian/prerm b/debian/prerm index 9f64884..a6ada29 100644 --- a/debian/prerm +++ b/debian/prerm @@ -1,5 +1,5 @@ #! /bin/sh -# prerm script for libapache2-mod-proxy-fdpass +# prerm script for libapache2-mod-proxy-fdpass2 # # see: dh_installdeb(1) @@ -28,13 +28,13 @@ reload_apache() 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 diff --git a/debian/rules b/debian/rules index b0f820e..271f838 100755 --- a/debian/rules +++ b/debian/rules @@ -13,13 +13,13 @@ build: build-stamp 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 diff --git a/mod_proxy_fdpass.c b/mod_proxy_fdpass.c deleted file mode 100644 index ff3e684..0000000 --- a/mod_proxy_fdpass.c +++ /dev/null @@ -1,573 +0,0 @@ -/* 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 -#include -#include - -#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 */ -}; diff --git a/mod_proxy_fdpass.h b/mod_proxy_fdpass.h deleted file mode 100644 index b9d2231..0000000 --- a/mod_proxy_fdpass.h +++ /dev/null @@ -1,41 +0,0 @@ -/* 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_ */ -/** @} */ - diff --git a/mod_proxy_fdpass2.c b/mod_proxy_fdpass2.c new file mode 100644 index 0000000..7d4c6ae --- /dev/null +++ b/mod_proxy_fdpass2.c @@ -0,0 +1,601 @@ +/* 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 +#include +#include + +#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 */ +}; diff --git a/mod_proxy_fdpass2.h b/mod_proxy_fdpass2.h new file mode 100644 index 0000000..194dbb3 --- /dev/null +++ b/mod_proxy_fdpass2.h @@ -0,0 +1,41 @@ +/* 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_ */ +/** @} */ + diff --git a/proxy_fdpass.conf b/proxy_fdpass.conf deleted file mode 100644 index c9ab012..0000000 --- a/proxy_fdpass.conf +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/proxy_fdpass2.conf b/proxy_fdpass2.conf new file mode 100644 index 0000000..7deb73e --- /dev/null +++ b/proxy_fdpass2.conf @@ -0,0 +1,3 @@ + + +