Merge branch 'pr_81'

This commit is contained in:
Nick Mathewson 2013-10-14 11:22:40 -04:00
commit 515ed87943
4 changed files with 98 additions and 0 deletions

View File

@ -99,6 +99,13 @@ struct evhttp_connection {
struct event_base *base;
struct evdns_base *dns_base;
/* Saved conn_addr, to extract IP address from it.
*
* Because some servers may reset/close connection without waiting clients,
* in that case we can't extract IP address even in close_cb.
* So we need to save it, just after we connected to remote server. */
struct sockaddr_storage *conn_address;
};
/* A callback for an http server */

18
http.c
View File

@ -1168,6 +1168,9 @@ evhttp_connection_free(struct evhttp_connection *evcon)
if (evcon->address != NULL)
mm_free(evcon->address);
if (evcon->conn_address != NULL)
mm_free(evcon->conn_address);
mm_free(evcon);
}
@ -1404,6 +1407,7 @@ evhttp_connection_cb(struct bufferevent *bufev, short what, void *arg)
struct evhttp_connection *evcon = arg;
int error;
ev_socklen_t errsz = sizeof(error);
socklen_t conn_address_len = sizeof(*evcon->conn_address);
if (evcon->fd == -1)
evcon->fd = bufferevent_getfd(bufev);
@ -1454,6 +1458,14 @@ evhttp_connection_cb(struct bufferevent *bufev, short what, void *arg)
evcon->retry_cnt = 0;
evcon->state = EVCON_IDLE;
if (!evcon->conn_address) {
evcon->conn_address = mm_malloc(sizeof(*evcon->conn_address));
}
if (getpeername(evcon->fd, (struct sockaddr *)evcon->conn_address, &conn_address_len)) {
mm_free(evcon->conn_address);
evcon->conn_address = NULL;
}
/* reset the bufferevent cbs */
bufferevent_setcb(evcon->bufev,
evhttp_read_cb,
@ -2348,6 +2360,12 @@ evhttp_connection_get_peer(struct evhttp_connection *evcon,
*port = evcon->port;
}
const struct sockaddr*
evhttp_connection_get_addr(struct evhttp_connection *evcon)
{
return (struct sockaddr *)evcon->conn_address;
}
int
evhttp_connection_connect_(struct evhttp_connection *evcon)
{

View File

@ -614,6 +614,15 @@ void evhttp_connection_set_closecb(struct evhttp_connection *evcon,
void evhttp_connection_get_peer(struct evhttp_connection *evcon,
char **address, ev_uint16_t *port);
/** Get the remote address associated with this connection.
* extracted from getpeername().
*
* @return NULL if getpeername() return non success,
* or connection is not connected,
* otherwise it return pointer to struct sockaddr_storage */
const struct sockaddr*
evhttp_connection_get_addr(struct evhttp_connection *evcon);
/**
Make an HTTP request over the specified connection.

View File

@ -3664,6 +3664,69 @@ http_ipv6_for_domain_test(void *arg)
regress_clean_dnsserver();
}
static void
http_request_get_addr_on_close(struct evhttp_connection *evcon, void *arg)
{
const struct sockaddr *storage;
char addrbuf[128];
char local[] = "127.0.0.1:";
test_ok = 0;
tt_assert(evcon);
storage = evhttp_connection_get_addr(evcon);
tt_assert(storage);
evutil_format_sockaddr_port_((struct sockaddr *)storage, addrbuf, sizeof(addrbuf));
tt_assert(!strncmp(addrbuf, local, sizeof(local) - 1));
test_ok = 1;
return;
end:
test_ok = 0;
}
static void
http_get_addr_test(void *arg)
{
struct basic_test_data *data = arg;
ev_uint16_t port = 0;
struct evhttp_connection *evcon = NULL;
struct evhttp_request *req = NULL;
test_ok = 0;
exit_base = data->base;
http = http_setup(&port, data->base, 0);
evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
tt_assert(evcon);
evhttp_connection_set_closecb(evcon, http_request_get_addr_on_close, arg);
/*
* At this point, we want to schedule a request to the HTTP
* server using our make request method.
*/
req = evhttp_request_new(http_request_done, (void *)BASIC_REQUEST_BODY);
/* We give ownership of the request to the connection */
if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
tt_abort_msg("Couldn't make request");
}
event_base_dispatch(data->base);
http_request_get_addr_on_close(evcon, NULL);
end:
if (evcon)
evhttp_connection_free(evcon);
if (http)
evhttp_free(http);
}
#define HTTP_LEGACY(name) \
{ #name, run_legacy_test_fn, TT_ISOLATED|TT_LEGACY, &legacy_setup, \
http_##name##_test }
@ -3713,6 +3776,7 @@ struct testcase_t http_testcases[] = {
HTTP(data_length_constraints),
HTTP(ipv6_for_domain),
HTTP(get_addr),
END_OF_TESTCASES
};