Permalink
Browse files

Merge remote-tracking branch 'sodabrew/feature/evhtp_client' into fea…

…ture/sodabrew_client

Conflicts:
	.gitignore
	evhtp.c
	evhtp.h
  • Loading branch information...
2 parents 95fff67 + c150c2e commit f652e60e9b13e2e8c42a55b1dd5227a57618d0be Mark Ellzey committed Nov 26, 2012
Showing with 390 additions and 23 deletions.
  1. +2 −0 .gitignore
  2. +6 −0 CMakeLists.txt
  3. +148 −14 evhtp.c
  4. +43 −6 evhtp.h
  5. +8 −3 htparse/htparse.c
  6. +1 −0 htparse/htparse.h
  7. +74 −0 test_client.c
  8. +108 −0 test_proxy.c
View
@@ -17,3 +17,5 @@
/test_basic
/test_vhost
+/test_client
+/test_proxy
View
@@ -199,8 +199,14 @@ endif()
add_executable(test test.c)
target_link_libraries(test libevhtp ${LIBEVHTP_EXTERNAL_LIBS} ${SYS_LIBS})
+add_executable(test_client test_client.c)
+target_link_libraries(test_client libevhtp ${LIBEVHTP_EXTERNAL_LIBS} ${SYS_LIBS})
+
add_executable(test_basic test_basic.c)
target_link_libraries(test_basic libevhtp ${LIBEVHTP_EXTERNAL_LIBS} ${SYS_LIBS})
add_executable(test_vhost test_vhost.c)
target_link_libraries(test_vhost libevhtp ${LIBEVHTP_EXTERNAL_LIBS} ${SYS_LIBS})
+
+add_executable(test_proxy test_proxy.c)
+target_link_libraries(test_proxy libevhtp ${LIBEVHTP_EXTERNAL_LIBS} ${SYS_LIBS})
View
162 evhtp.c
@@ -33,7 +33,7 @@ static int _evhtp_request_parser_headers_start(htparser * p);
static void _evhtp_connection_readcb(evbev_t * bev, void * arg);
-static evhtp_connection_t * _evhtp_connection_new(evhtp_t * htp, int sock);
+static evhtp_connection_t * _evhtp_connection_new(evhtp_t * htp, int sock, evhtp_type type);
static evhtp_uri_t * _evhtp_uri_new(void);
static void _evhtp_uri_free(evhtp_uri_t * uri);
@@ -632,7 +632,7 @@ _evhtp_request_new(evhtp_connection_t * c) {
}
req->conn = c;
- req->htp = c->htp;
+ req->htp = c ? c->htp : NULL;
req->status = EVHTP_RES_OK;
req->buffer_in = evbuffer_new();
req->buffer_out = evbuffer_new();
@@ -832,6 +832,10 @@ static int
_evhtp_request_parser_start(htparser * p) {
evhtp_connection_t * c = htparser_get_userdata(p);
+ if (c->type == evhtp_type_client) {
+ return 0;
+ }
+
if (c->request) {
if (c->request->finished == 1) {
_evhtp_request_free(c->request);
@@ -852,6 +856,13 @@ _evhtp_request_parser_args(htparser * p, const char * data, size_t len) {
evhtp_connection_t * c = htparser_get_userdata(p);
evhtp_uri_t * uri = c->request->uri;
+ if (c->type == evhtp_type_client) {
+ /* as a client, technically we should never get here, but just in case
+ * we return a 0 to the parser to continue.
+ */
+ return 0;
+ }
+
if (!(uri->query = evhtp_parse_query(data, len))) {
c->request->status = EVHTP_RES_ERROR;
return -1;
@@ -1520,14 +1531,19 @@ _evhtp_connection_writecb(evbev_t * bev, void * arg) {
static void
_evhtp_connection_eventcb(evbev_t * bev, short events, void * arg) {
- evhtp_connection_t * c;
+ evhtp_connection_t * c = arg;
if ((events & BEV_EVENT_CONNECTED)) {
+ if (c->type == evhtp_type_client) {
+ bufferevent_setcb(bev,
+ _evhtp_connection_readcb,
+ _evhtp_connection_writecb,
+ _evhtp_connection_eventcb, c);
+ }
+
return;
}
- c = arg;
-
if (c->ssl && !(events & BEV_EVENT_EOF)) {
/* XXX need to do better error handling for SSL specific errors */
c->error = 1;
@@ -1635,22 +1651,44 @@ _evhtp_default_request_cb(evhtp_request_t * request, void * arg) {
}
static evhtp_connection_t *
-_evhtp_connection_new(evhtp_t * htp, int sock) {
+_evhtp_connection_new(evhtp_t * htp, int sock, evhtp_type type) {
evhtp_connection_t * connection;
+ htp_type ptype;
+
+ switch (type) {
+ case evhtp_type_client:
+ ptype = htp_type_response;
+ break;
+ case evhtp_type_server:
+ ptype = htp_type_request;
+ break;
+ default:
+ return NULL;
+ }
if (!(connection = calloc(sizeof(evhtp_connection_t), 1))) {
return NULL;
}
- connection->error = 0;
- connection->owner = 1;
- connection->sock = sock;
- connection->htp = htp;
- connection->parser = htparser_new();
-
- htparser_init(connection->parser, htp_type_request);
+ connection->evbase = NULL;
+ connection->bev = NULL;
+ connection->thread = NULL;
+ connection->hooks = NULL;
+ connection->request = NULL;
+ connection->resume_ev = NULL;
+ connection->saddr = NULL;
+ connection->error = 0;
+ connection->owner = 1;
+ connection->sock = sock;
+ connection->htp = htp;
+ connection->type = type;
+ connection->parser = htparser_new();
+
+ htparser_init(connection->parser, ptype);
htparser_set_userdata(connection->parser, connection);
+ TAILQ_INIT(&connection->pending);
+
return connection;
}
@@ -1711,7 +1749,7 @@ _evhtp_accept_cb(evserv_t * serv, int fd, struct sockaddr * s, int sl, void * ar
evhtp_t * htp = arg;
evhtp_connection_t * connection;
- if (!(connection = _evhtp_connection_new(htp, fd))) {
+ if (!(connection = _evhtp_connection_new(htp, fd, evhtp_type_server))) {
return;
}
@@ -1730,6 +1768,10 @@ _evhtp_accept_cb(evserv_t * serv, int fd, struct sockaddr * s, int sl, void * ar
#endif
connection->evbase = htp->evbase;
+ if (_evhtp_run_pre_accept(connection->htp, connection) < 0) {
+ return evhtp_connection_free(connection);
+ }
+
if (_evhtp_connection_accept(htp->evbase, connection) < 0) {
evhtp_connection_free(connection);
return;
@@ -2116,6 +2158,19 @@ evhtp_kvs_add_kv(evhtp_kvs_t * kvs, evhtp_kv_t * kv) {
TAILQ_INSERT_TAIL(kvs, kv, next);
}
+void
+evhtp_kvs_add_kvs(evhtp_kvs_t * dst, evhtp_kvs_t * src) {
+ if (dst == NULL || src == NULL) {
+ return;
+ }
+
+ evhtp_kv_t * kv;
+
+ TAILQ_FOREACH(kv, src, next) {
+ evhtp_kvs_add_kv(dst, evhtp_kv_new(kv->key, kv->val, kv->k_heaped, kv->v_heaped));
+ }
+}
+
typedef enum {
s_query_start = 0,
s_query_question_mark,
@@ -3503,3 +3558,82 @@ evhtp_free(evhtp_t * evhtp) {
free(evhtp);
}
+/*****************************************************************
+* client request functions *
+*****************************************************************/
+
+evhtp_connection_t *
+evhtp_connection_new(evbase_t * evbase, const char * addr, uint16_t port) {
+ evhtp_connection_t * conn;
+ struct sockaddr_in sin;
+
+ if (evbase == NULL) {
+ return NULL;
+ }
+
+ if (!(conn = _evhtp_connection_new(NULL, -1, evhtp_type_client))) {
+ return NULL;
+ }
+
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = inet_addr(addr);
+ sin.sin_port = htons(port);
+
+ conn->evbase = evbase;
+ conn->bev = bufferevent_socket_new(evbase, -1, BEV_OPT_CLOSE_ON_FREE);
+
+ bufferevent_enable(conn->bev, EV_READ);
+
+ bufferevent_setcb(conn->bev, NULL, NULL,
+ _evhtp_connection_eventcb, conn);
+
+ bufferevent_socket_connect(conn->bev,
+ (struct sockaddr *)&sin, sizeof(sin));
+
+ return conn;
+}
+
+evhtp_request_t *
+evhtp_request_new(evhtp_callback_cb cb, void * arg) {
+ evhtp_request_t * r;
+
+ if (!(r = _evhtp_request_new(NULL))) {
+ return NULL;
+ }
+
+ r->cb = cb;
+ r->cbarg = arg;
+ r->proto = EVHTP_PROTO_11;
+
+ return r;
+}
+
+int
+evhtp_make_request(evhtp_connection_t * c, evhtp_request_t * r,
+ htp_method meth, const char * uri) {
+ evbuf_t * obuf;
+ char * proto;
+
+ obuf = bufferevent_get_output(c->bev);
+ r->conn = c;
+ c->request = r;
+
+ switch (r->proto) {
+ case EVHTP_PROTO_10:
+ proto = "1.0";
+ break;
+ case EVHTP_PROTO_11:
+ default:
+ proto = "1.1";
+ break;
+ }
+
+ evbuffer_add_printf(obuf, "%s %s HTTP/%s\r\n",
+ htparser_get_methodstr_m(meth), uri, proto);
+
+ evhtp_headers_for_each(r->headers_out, _evhtp_create_headers, obuf);
+ evbuffer_add_reference(obuf, "\r\n", 2, NULL, NULL);
+
+ return 0;
+}
+
View
49 evhtp.h
@@ -127,6 +127,7 @@ typedef enum evhtp_hook_type evhtp_hook_type;
typedef enum evhtp_callback_type evhtp_callback_type;
typedef enum evhtp_proto evhtp_proto;
typedef enum evhtp_ssl_scache_type evhtp_ssl_scache_type;
+typedef enum evhtp_type evhtp_type;
typedef void (*evhtp_thread_init_cb)(evhtp_t * htp, evthr_t * thr, void * arg);
typedef void (*evhtp_callback_cb)(evhtp_request_t * req, void * arg);
@@ -231,6 +232,11 @@ typedef void * (*evhtp_ssl_scache_init)(evhtp_t *);
#define EVHTP_RES_VERNSUPPORT 505
#define EVHTP_RES_BWEXEED 509
+enum evhtp_type {
+ evhtp_type_client,
+ evhtp_type_server
+};
+
struct evhtp_defaults_s {
evhtp_callback_cb cb;
evhtp_pre_accept_cb pre_accept;
@@ -402,6 +408,8 @@ struct evhtp_request_s {
evhtp_callback_cb cb; /**< the function to call when fully processed */
void * cbarg; /**< argument which is passed to the cb function */
int error;
+
+ TAILQ_ENTRY(evhtp_request_s) next;
};
#define evhtp_request_content_len(r) htparser_get_content_length(r->conn->parser)
@@ -416,16 +424,18 @@ struct evhtp_connection_s {
htparser * parser;
event_t * resume_ev;
struct sockaddr * saddr;
- struct timeval recv_timeo; /**< conn read timeouts (overrides global) */
- struct timeval send_timeo; /**< conn write timeouts (overrides global) */
+ struct timeval recv_timeo; /**< conn read timeouts (overrides global) */
+ struct timeval send_timeo; /**< conn write timeouts (overrides global) */
int sock;
uint8_t error;
- uint8_t owner; /**< set to 1 if this structure owns the bufferevent */
- uint8_t vhost_via_sni; /**< set to 1 if the vhost was found via SSL SNI */
- evhtp_request_t * request; /**< the request currently being processed */
+ uint8_t owner; /**< set to 1 if this structure owns the bufferevent */
+ uint8_t vhost_via_sni; /**< set to 1 if the vhost was found via SSL SNI */
+ evhtp_request_t * request; /**< the request currently being processed */
uint64_t max_body_size;
uint64_t body_bytes_read;
uint64_t num_requests;
+ evhtp_type type; /**< server or client */
+ TAILQ_HEAD(, evhtp_request_s) pending; /**< client pending data */
};
struct evhtp_hooks_s {
@@ -806,6 +816,14 @@ evhtp_kv_t * evhtp_kvs_find_kv(evhtp_kvs_t * kvs, const char * key);
*/
void evhtp_kvs_add_kv(evhtp_kvs_t * kvs, evhtp_kv_t * kv);
+/**
+ * @brief appends all key/val structures from src tailq onto dst tailq
+ *
+ * @param dst an evhtp_kvs_t structure
+ * @param src an evhtp_kvs_t structure
+ */
+void evhtp_kvs_add_kvs(evhtp_kvs_t * dst, evhtp_kvs_t * src);
+
int evhtp_kvs_for_each(evhtp_kvs_t * kvs, evhtp_kvs_iterator cb, void * arg);
/**
@@ -896,6 +914,7 @@ const char * evhtp_header_find(evhtp_headers_t * headers, const char * key);
#define evhtp_headers_free evhtp_kvs_free
#define evhtp_header_rm_and_free evhtp_kv_rm_and_free
#define evhtp_headers_add_header evhtp_kvs_add_kv
+#define evhtp_headers_add_headers evhtp_kvs_add_kvs
#define evhtp_query_new evhtp_kvs_new
#define evhtp_query_free evhtp_kvs_free
@@ -996,7 +1015,6 @@ void evhtp_connection_free(evhtp_connection_t * connection);
void evhtp_request_free(evhtp_request_t * request);
-
/**
* @brief set a max body size to accept for an incoming request, this will
* default to unlimited.
@@ -1032,6 +1050,25 @@ void evhtp_request_set_max_body_size(evhtp_request_t * request, uint64_t len);
*/
void evhtp_set_max_keepalive_requests(evhtp_t * htp, uint64_t num);
+/*****************************************************************
+* client request functions *
+*****************************************************************/
+
+/**
+ * @brief allocate a new connection
+ */
+evhtp_connection_t * evhtp_connection_new(evbase_t * evbase, const char * addr, uint16_t port);
+
+/**
+ * @brief allocate a new request
+ */
+evhtp_request_t * evhtp_request_new(evhtp_callback_cb cb, void * arg);
+
+/**
+ * @brief make a client request
+ */
+int evhtp_make_request(evhtp_connection_t * c, evhtp_request_t * r, htp_method meth, const char * uri);
+
#ifdef __cplusplus
}
#endif
View
@@ -368,12 +368,17 @@ htparser_get_method(htparser * p) {
}
const char *
-htparser_get_methodstr(htparser * p) {
- if (p->method >= htp_method_UNKNOWN) {
+htparser_get_methodstr_m(htp_method meth) {
+ if (meth >= htp_method_UNKNOWN) {
return NULL;
}
- return method_strmap[p->method];
+ return method_strmap[meth];
+}
+
+const char *
+htparser_get_methodstr(htparser * p) {
+ return htparser_get_methodstr_m(p->method);
}
void
Oops, something went wrong.

0 comments on commit f652e60

Please sign in to comment.