X-Git-Url: https://mop.ddnsfree.com/gitweb/?p=mod-proxy-fdpass.git;a=blobdiff_plain;f=mod_proxy_fdpass.c;fp=mod_proxy_fdpass.c;h=0000000000000000000000000000000000000000;hp=ff3e684b213004fff888ec6bb6c3d1ae5a03e7a7;hb=a10c60232480678fdc9ea2314df64e0655eb169b;hpb=34a20c86b2a1e8b901cdf1e8583e261dea69b80b 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 */ -};