Files
apache-http-server/modules/proxy/mod_proxy_fdpass.c
Christophe Jaillet f991ae076b Fix the use of the default 'flush' provider.
Improve documentation for the "flusher" parameter.
Remove useless empty lines.

See http://mail-archives.apache.org/mod_mbox/httpd-dev/200812.mbox/%3C494226C0.4050407@force-elite.com%3E for some more explanation.
A python script is given there to test.
I had to tweak it to have it work
(use:
        fd, payload = passfd.recvfd(conn.fileno())
instead of:
        fd = passfd.recvfd(conn.fileno())
)


This is a r1058621 regression, where somehow "char *flusher" has been turned into a "char flusher[]". So it is been broken since the beginning of 2.4.x

After this change (i.e. r1058621), 'flusher' is no more a pointer (NULL'ed when the structure it belongs to is created) but the address of an array within a structure. It can not be NULL anymore.
So, we now have to look at the content of the array itself to see if it has been initialized or if we have to use the default value instead.

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1717063 13f79535-47bb-0310-9956-ffa450edef68
2015-11-29 13:26:03 +00:00

242 lines
6.7 KiB
C

/* 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 "mod_proxy_fdpass.h"
module AP_MODULE_DECLARE_DATA proxy_fdpass_module;
static int proxy_fdpass_canon(request_rec *r, char *url)
{
const char *path;
if (ap_casecmpstrn(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, APLOGNO(01151)
"set r->filename to %s", r->filename);
return OK;
}
static apr_status_t get_socket_from_path(apr_pool_t *p,
const char* path,
apr_socket_t **out_sock)
{
apr_socket_t *s;
apr_status_t rv;
*out_sock = NULL;
rv = apr_socket_create(&s, AF_UNIX, SOCK_STREAM, 0, p);
if (rv != APR_SUCCESS) {
return rv;
}
rv = ap_proxy_connect_uds(s, path, p);
if (rv != APR_SUCCESS) {
return rv;
}
*out_sock = s;
return APR_SUCCESS;
}
static apr_status_t send_socket(apr_pool_t *p,
apr_socket_t *s,
apr_socket_t *outbound)
{
apr_status_t rv;
apr_os_sock_t rawsock;
apr_os_sock_t srawsock;
struct msghdr msg;
struct cmsghdr *cmsg;
struct iovec iov;
char b = '\0';
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;
}
memset(&msg, 0, sizeof(msg));
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
iov.iov_base = &b;
iov.iov_len = 1;
cmsg = apr_palloc(p, sizeof(*cmsg) + sizeof(rawsock));
cmsg->cmsg_len = sizeof(*cmsg) + sizeof(rawsock);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
memcpy(CMSG_DATA(cmsg), &rawsock, sizeof(rawsock));
msg.msg_control = cmsg;
msg.msg_controllen = cmsg->cmsg_len;
rv = sendmsg(srawsock, &msg, 0);
if (rv == -1) {
return errno;
}
return APR_SUCCESS;
}
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;
if (ap_casecmpstrn(url, "fd://", 5) == 0) {
url += 5;
}
else {
return DECLINED;
}
rv = get_socket_from_path(r->pool, url, &sock);
if (rv != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01152)
"Failed to connect to '%s'", url);
return HTTP_INTERNAL_SERVER_ERROR;
}
{
int status;
const char *flush_method = *worker->s->flusher ? worker->s->flusher : "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, APLOGNO(01153)
"Unable to find configured flush provider '%s'",
flush_method);
return HTTP_INTERNAL_SERVER_ERROR;
}
status = flush->flusher(r);
if (status) {
return status;
}
}
clientsock = ap_get_conn_socket(r->connection);
rv = send_socket(r->pool, sock, clientsock);
if (rv != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01154) "send_socket failed:");
return HTTP_INTERNAL_SERVER_ERROR;
}
{
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, APLOGNO(01155)
"failed to create dummy socket");
return HTTP_INTERNAL_SERVER_ERROR;
}
ap_set_core_module_config(r->connection->conn_config, dummy);
}
return OK;
}
static int standard_flush(request_rec *r)
{
int status;
apr_bucket_brigade *bb;
apr_bucket *e;
r->connection->keepalive = AP_CONN_CLOSE;
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, APLOGNO(01156)
"ap_pass_brigade failed:");
return status;
}
return OK;
}
static const proxy_fdpass_flush builtin_flush =
{
"flush",
&standard_flush,
NULL
};
static void 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);
}
AP_DECLARE_MODULE(proxy_fdpass) = {
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 */
register_hooks /* register hooks */
};