8000 Support unix domain sockets in the http client [MERGED] by seanyoung · Pull Request #322 · libevent/libevent · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Support unix domain sockets in the http client [MERGED] #322

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions http-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ struct evhttp_connection {
char *address; /* address to connect to */
ev_uint16_t port;

#ifndef _WIN32
char *unixsocket;
#endif
size_t max_headers_size;
ev_uint64_t max_body_size;

Expand Down
190 changes: 156 additions & 34 deletions http.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
#include "event2/event-config.h"
#include "evconfig-private.h"

#define member_size(type, member) sizeof(((type *)0)->member)

#ifdef EVENT__HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
Expand Down Expand Up @@ -2513,21 +2515,16 @@ evhttp_connection_new(const char *address, ev_uint16_t port)
return (evhttp_connection_base_new(NULL, NULL, address, port));
}

struct evhttp_connection *
evhttp_connection_base_bufferevent_new(struct event_base *base, struct evdns_base *dnsbase, struct bufferevent* bev,
const char *address, ev_uint16_t port)
static struct evhttp_connection *
evhttp_connection_new_(struct event_base *base, struct bufferevent* bev)
{
struct evhttp_connection *evcon = NULL;

event_debug(("Attempting connection to %s:%d\n", address, port));
struct evhttp_connection *evcon;

if ((evcon = mm_calloc(1, sizeof(struct evhttp_connection))) == NULL) {
event_warn("%s: calloc failed", __func__);
goto error;
}

evcon->port = port;

evcon->max_headers_size = EV_SIZE_MAX;
evcon->max_body_size = EV_SIZE_MAX;

Expand All @@ -2538,11 +2535,6 @@ evhttp_connection_base_bufferevent_new(struct event_base *base, struct evdns_bas

evcon->retry_cnt = evcon->retry_max = 0;

if ((evcon->address = mm_strdup(address)) == NULL) {
event_warn("%s: strdup failed", __func__);
goto error;
}

if (bev == NULL) {
if (!(bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE))) {
event_warn("%s: bufferevent_socket_new failed", __func__);
Expand All @@ -2567,7 +2559,6 @@ evhttp_connection_base_bufferevent_new(struct event_base *base, struct evdns_bas
bufferevent_get_priority(bev),
evhttp_deferred_read_cb, evcon);

evcon->dns_base = dnsbase;
evcon->ai_family = AF_UNSPEC;

return (evcon);
Expand All @@ -2578,6 +2569,63 @@ evhttp_connection_base_bufferevent_new(struct event_base *base, struct evdns_bas
return (NULL);
}

#ifndef _WIN32
struct evhttp_connection *
evhttp_connection_base_bufferevent_unix_new(struct event_base *base, struct bufferevent* bev, const char *unixsocket)
{
struct evhttp_connection *evcon;

if (strlen(unixsocket) >= member_size(struct sockaddr_un, sun_path)) {
event_warn("%s: unix socket too long", __func__);
return NULL;
}

evcon = evhttp_connection_new_(base, bev);
if (evcon == NULL)
goto error;

if ((evcon->unixsocket = mm_strdup(unixsocket)) == NULL) {
event_warn("%s: strdup failed", __func__);
goto error;
}

evcon->ai_family = AF_UNIX;

return (evcon);
error:
if (evcon != NULL)
evhttp_connection_free(evcon);
return (NULL);
}
#endif

struct evhttp_connection *
evhttp_connection_base_bufferevent_new(struct event_base *base, struct evdns_base *dnsbase, struct bufferevent* bev,
const char *address, unsigned short port)
{
struct evhttp_connection *evcon;

event_debug(("Attempting connection to %s:%d\n", address, port));

evcon = evhttp_connection_new_(base, bev);
if (evcon == NULL)
goto error;

if ((evcon->address = mm_strdup(address)) == NULL) {
event_warn("%s: strdup failed", __func__);
goto error;
}
evcon->port = port;
evcon->dns_base = dnsbase;

return (evcon);
error:
if (evcon != NULL)
evhttp_connection_free(evcon);
return (NULL);
}


struct bufferevent* evhttp_connection_get_bufferevent(struct evhttp_connection *evcon)
{
return evcon->bufev;
Expand Down Expand Up @@ -2792,7 +2840,16 @@ evhttp_connection_connect_(struct evhttp_connection *evcon)
socklen = sizeof(struct sockaddr_in6);
}
ret = bufferevent_socket_connect(evcon->bufev, sa, socklen);
} else {
}
#ifndef _WIN32
else if (evcon->unixsocket) {
struct sockaddr_un sockaddr;
sockaddr.sun_family = AF_UNIX;
strcpy(sockaddr.sun_path, evcon->unixsocket);
ret = bufferevent_socket_connect(evcon->bufev, (const struct sockaddr*)&sockaddr, sizeof(sockaddr));
}
#endif
else {
ret = bufferevent_socket_connect_hostname(evcon->bufev,
evcon->dns_base, evcon->ai_family, address, evcon->port);
}
Expand Down Expand Up @@ -4456,7 +4513,6 @@ evhttp_get_request_connection(
evutil_socket_t fd, struct sockaddr *sa, ev_socklen_t salen)
{
struct evhttp_connection *evcon;
char *hostname = NULL, *portname = NULL;
struct bufferevent* bev = NULL;

#ifdef EVENT__HAVE_STRUCT_SOCKADDR_UN
Expand All @@ -4466,24 +4522,46 @@ evhttp_get_request_connection(
}
#endif

name_from_addr(sa, salen, &hostname, &portname);
if (hostname == NULL || portname == NULL) {
if (hostname) mm_free(hostname);
if (portname) mm_free(portname);
return (NULL);
#ifndef _WIN32
if (sa->sa_family == AF_UNIX) {
struct sockaddr_un *sockaddr = (struct sockaddr_un *)sa;

event_debug(("%s: new request from unix socket %s on "
EV_SOCK_FMT"\n", __func__, sockaddr->sun_path,
EV_SOCK_ARG(fd)));

/* we need a connection object to put the http request on */
if (http->bevcb != NULL) {
bev = (*http->bevcb)(http->base, http->bevcbarg);
}

evcon = evhttp_connection_base_bufferevent_unix_new(http->base,
bev, sockaddr->sun_path);
}
else
#endif
{
char *hostname = NULL, *portname = NULL;

name_from_addr(sa, salen, &hostname, &portname);
if (hostname == NULL || portname == NULL) {
if (hostname) mm_free(hostname);
if (portname) mm_free(portname);
return (NULL);
}

event_debug(("%s: new request from %s:%s on "EV_SOCK_FMT"\n",
__func__, hostname, portname, EV_SOCK_ARG(fd)));
event_debug(("%s: new request from %s:%s on "EV_SOCK_FMT"\n",
__func__, hostname, portname, EV_SOCK_ARG(fd)));

/* we need a connection object to put the http request on */
if (http->bevcb != NULL) {
bev = (*http->bevcb)(http->base, http->bevcbarg);
/* we need a connection object to put the http request on */
if (http->bevcb != NULL) {
bev = (*http->bevcb)(http->base, http->bevcbarg);
}
evcon = evhttp_connection_base_bufferevent_new(
http->base, NULL, bev, hostname, atoi(portname));
mm_free(hostname);
mm_free(portname);
}
evcon = evhttp_connection_base_bufferevent_new(
http->base, NULL, bev, hostname, atoi(portname));
mm_free(hostname);
mm_free(portname);
if (evcon == NULL)
return (NULL);

Expand Down Expand Up @@ -4518,10 +4596,12 @@ evhttp_associate_new_request_with_connection(struct evhttp_connection *evcon)
if ((req = evhttp_request_new(evhttp_handle_request, http)) == NULL)
return (-1);

if ((req->remote_host = mm_strdup(evcon->address)) == NULL) {
event_warn("%s: strdup", __func__);
evhttp_request_free(req);
return (-1);
if (evcon->address != NULL) {
if ((req->remote_host = mm_strdup(evcon->address)) == NULL) {
event_warn("%s: strdup", __func__);
evhttp_request_free(req);
return (-1);
}
}
req->remote_port = evcon->port;

Expand Down Expand Up @@ -4739,6 +4819,9 @@ struct evhttp_uri {
char *userinfo; /* userinfo (typically username:pass), or NULL */
char *host; /* hostname, IP address, or NULL */
int port; /* port, or zero */
#ifndef _WIN32
char *unixsocket; /* unix domain socket or NULL */
#endif
char *path; /* path, or "". */
char *query; /* query, or NULL */
char *fragment; /* fragment or NULL */
Expand Down Expand Up @@ -4910,6 +4993,18 @@ parse_authority(struct evhttp_uri *uri, char *s, char *eos, unsigned *flags)
} else {
cp = s;
}

#ifndef _WIN32
if (*flags & EVHTTP_URI_UNIX_SOCKET && !strncmp(cp, "unix:", 5)) {
char *e = strchr(cp + 5, ':');
if (e) {
*e = '\0';
uri->unixsocket = mm_strdup(cp + 5);
return 0;
}
}
#endif

/* Optionally, we end with ":port" */
for (port=eos-1; port >= cp && EVUTIL_ISDIGIT_(*port); --port)
;
Expand Down Expand Up @@ -5203,6 +5298,9 @@ evhttp_uri_free(struct evhttp_uri *uri)
URI_FREE_STR_(scheme);
URI_FREE_STR_(userinfo);
URI_FREE_STR_(host);
#ifndef _WIN32
URI_FREE_STR_(unixsocket);
#endif
URI_FREE_STR_(path);
URI_FREE_STR_(query);
URI_FREE_STR_(fragment);
Expand Down Expand Up @@ -5231,6 +5329,15 @@ evhttp_uri_join(struct evhttp_uri *uri, char *buf, size_t limit)
URI_ADD_(scheme);
evbuffer_add(tmp, ":", 1);
}
#ifndef _WIN32
if (uri->unixsocket) {
evbuffer_add(tmp, "//", 2);
if (uri->userinfo)
evbuffer_add_printf(tmp,"%s@", uri->userinfo);
evbuffer_add_printf(tmp, "unix:%s:", uri->unixsocket);
}
else
#endif
if (uri->host) {
evbuffer_add(tmp, "//", 2);
if (uri->userinfo)
Expand Down Expand Up @@ -5296,6 +5403,13 @@ evhttp_uri_get_host(const struct evhttp_uri *uri)
{
return uri->host;
}
#ifndef _WIN32
const char *
evhttp_uri_get_unixsocket(const struct evhttp_uri *uri)
{
return uri->unixsocket;
}
#endif
int
evhttp_uri_get_port(const struct evhttp_uri *uri)
{
Expand Down Expand Up @@ -5385,6 +5499,14 @@ evhttp_uri_set_host(struct evhttp_uri *uri, const char *host)

return 0;
}
#ifndef _WIN32
int
evhttp_uri_set_unixsocket(struct evhttp_uri *uri, const char *unixsocket)
{
URI_SET_STR_(unixsocket);
return 0;
}
#endif
int
evhttp_uri_set_port(struct evhttp_uri *uri, int port)
{
Expand Down
34 changes: 33 additions & 1 deletion include/event2/http.h
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,7 @@ enum evhttp_request_kind { EVHTTP_REQUEST, EVHTTP_RESPONSE };
* @param dnsbase the dns_base to use for resolving host names; if not
* specified host name resolution will block.
* @param bev a bufferevent to use for connecting to the server; if NULL, a
* socket-based bufferevent will be created. This buffrevent will be freed
* socket-based bufferevent will be created. This bufferevent will be freed
* when the connection closes. It must have no fd set on it.
* @param address the address to which to connect
* @param port the port to connect to
Expand All @@ -663,6 +663,21 @@ EVENT2_EXPORT_SYMBOL
struct evhttp_connection *evhttp_connection_base_bufferevent_new(
struct event_base *base, struct evdns_base *dnsbase, struct bufferevent* bev, const char *address, ev_uint16_t port);

/**
* Create and return a connection object that can be used to for making HTTP
* requests over an unix domain socket.
*
* @param base the event_base to use for handling the connection
* @param bev a bufferevent to use for connecting to the server; if NULL, a
* socket-based bufferevent will be created. This bufferevent will be freed
* when the connection closes. It must have no fd set on it.
* @param path path of unix domain socket
* @return an evhttp_connection object that can be used for making requests
*/
EVENT2_EXPORT_SYMBOL
struct evhttp_connection *evhttp_connection_base_bufferevent_unix_new(
struct event_base *base, struct bufferevent* bev, const char *path);

/**
* Return the bufferevent that an evhttp_connection is using.
*/
Expand Down Expand Up @@ -1285,6 +1300,10 @@ const char *evhttp_uri_get_userinfo(const struct evhttp_uri *uri);
*/
EVENT2_EXPORT_SYMBOL
const char *evhttp_uri_get_host(const struct evhttp_uri *uri);
/** Return the unix socket part of an evhttp_uri, or NULL if there is no unix
* socket set */
EVENT2_EXPORT_SYMBOL
const char *evhttp_uri_get_unixsocket(const struct evhttp_uri *uri);
/** Return the port part of an evhttp_uri, or -1 if there is no port set. */
EVENT2_EXPORT_SYMBOL
int evhttp_uri_get_port(const struct evhttp_uri *uri);
Expand Down Expand Up @@ -1312,6 +1331,11 @@ int evhttp_uri_set_userinfo(struct evhttp_uri *uri, const char *userinfo);
* Returns 0 on success, -1 if host is not well-formed. */
EVENT2_EXPORT_SYMBOL
int evhttp_uri_set_host(struct evhttp_uri *uri, const char *host);
/** Set the unix socket of an evhttp_uri, or clear the unix socket if unixsocket==NULL.
* Returns 0 on success, -1 if unixsocket is not well-formed */
EVENT2_EXPORT_SYMBOL
int evhttp_uri_set_unixsocket(struct evhttp_uri *uri, const char *unixsocket);

/** Set the port of an evhttp_uri, or clear the port if port==-1.
* Returns 0 on success, -1 if port is not well-formed. */
EVENT2_EXPORT_SYMBOL
Expand Down Expand Up @@ -1382,6 +1406,7 @@ struct evhttp_uri *evhttp_uri_parse_with_flags(const char *source_uri,
* </ul>
*/
#define EVHTTP_URI_NONCONFORMANT 0x01

/**
* Strip brackets from the IPv6 address and only for evhttp_uri_get_host(),
* evhttp_uri_join() returns the host with brackets.
Expand All @@ -1392,6 +1417,13 @@ struct evhttp_uri *evhttp_uri_parse_with_flags(const char *source_uri,
*/
#define EVHTTP_URI_HOST_STRIP_BRACKETS 0x04

/**
* Parse unix domain socket URIs, for example:
*
* http://unix:/run/control.sock:/controller
*/
#define EVHTTP_URI_UNIX_SOCKET 0x02

/** Alias for evhttp_uri_parse_with_flags(source_uri, 0) */
EVENT2_EXPORT_SYMBOL
struct evhttp_uri *evhttp_uri_parse(const char *source_uri);
Expand Down
Loading
0