1c43e99fdSEd Maste #include "event2/event-config.h"
2c43e99fdSEd Maste 
3c43e99fdSEd Maste #include <event2/event.h>
4c43e99fdSEd Maste #include <event2/http.h>
5c43e99fdSEd Maste #include <event2/http_struct.h>
6c43e99fdSEd Maste #include <event2/buffer.h>
7c43e99fdSEd Maste #include <stdlib.h>
8c43e99fdSEd Maste #include <stdio.h>
9c43e99fdSEd Maste #include <limits.h>
10c43e99fdSEd Maste 
11c43e99fdSEd Maste #define VERIFY(cond) do {                       \
12c43e99fdSEd Maste 	if (!(cond)) {                              \
13c43e99fdSEd Maste 		fprintf(stderr, "[error] %s\n", #cond); \
14*b50261e2SCy Schubert 		exit(EXIT_FAILURE);                     \
15c43e99fdSEd Maste 	}                                           \
16c43e99fdSEd Maste } while (0);                                    \
17c43e99fdSEd Maste 
18c43e99fdSEd Maste #define URL_MAX 4096
19c43e99fdSEd Maste 
20c43e99fdSEd Maste struct connect_base
21c43e99fdSEd Maste {
22c43e99fdSEd Maste 	struct evhttp_connection *evcon;
23c43e99fdSEd Maste 	struct evhttp_uri *location;
24c43e99fdSEd Maste };
25c43e99fdSEd Maste 
uri_parse(const char * str)26*b50261e2SCy Schubert static struct evhttp_uri* uri_parse(const char *str)
27*b50261e2SCy Schubert {
28*b50261e2SCy Schubert 	struct evhttp_uri *uri;
29*b50261e2SCy Schubert 	VERIFY(uri = evhttp_uri_parse(str));
30*b50261e2SCy Schubert 	VERIFY(evhttp_uri_get_host(uri));
31*b50261e2SCy Schubert 	VERIFY(evhttp_uri_get_port(uri) > 0);
32*b50261e2SCy Schubert 	return uri;
33*b50261e2SCy Schubert }
uri_path(struct evhttp_uri * uri,char buffer[URL_MAX])34*b50261e2SCy Schubert static char* uri_path(struct evhttp_uri *uri, char buffer[URL_MAX])
35*b50261e2SCy Schubert {
36*b50261e2SCy Schubert 	struct evhttp_uri *path;
37*b50261e2SCy Schubert 
38*b50261e2SCy Schubert 	VERIFY(evhttp_uri_join(uri, buffer, URL_MAX));
39*b50261e2SCy Schubert 
40*b50261e2SCy Schubert 	path = evhttp_uri_parse(buffer);
41*b50261e2SCy Schubert 	evhttp_uri_set_scheme(path, NULL);
42*b50261e2SCy Schubert 	evhttp_uri_set_userinfo(path, 0);
43*b50261e2SCy Schubert 	evhttp_uri_set_host(path, NULL);
44*b50261e2SCy Schubert 	evhttp_uri_set_port(path, -1);
45*b50261e2SCy Schubert 	VERIFY(evhttp_uri_join(path, buffer, URL_MAX));
46*b50261e2SCy Schubert 	return buffer;
47*b50261e2SCy Schubert }
uri_hostport(struct evhttp_uri * uri,char buffer[URL_MAX])48*b50261e2SCy Schubert static char* uri_hostport(struct evhttp_uri *uri, char buffer[URL_MAX])
49*b50261e2SCy Schubert {
50*b50261e2SCy Schubert 	VERIFY(evhttp_uri_join(uri, buffer, URL_MAX));
51*b50261e2SCy Schubert 	VERIFY(evhttp_uri_get_host(uri));
52*b50261e2SCy Schubert 	VERIFY(evhttp_uri_get_port(uri) > 0);
53*b50261e2SCy Schubert 	evutil_snprintf(buffer, URL_MAX, "%s:%d",
54*b50261e2SCy Schubert 		evhttp_uri_get_host(uri), evhttp_uri_get_port(uri));
55*b50261e2SCy Schubert 	return buffer;
56*b50261e2SCy Schubert }
57*b50261e2SCy Schubert 
get_cb(struct evhttp_request * req,void * arg)58c43e99fdSEd Maste static void get_cb(struct evhttp_request *req, void *arg)
59c43e99fdSEd Maste {
60c43e99fdSEd Maste 	ev_ssize_t len;
61c43e99fdSEd Maste 	struct evbuffer *evbuf;
62c43e99fdSEd Maste 
63c43e99fdSEd Maste 	VERIFY(req);
64c43e99fdSEd Maste 
65c43e99fdSEd Maste 	evbuf = evhttp_request_get_input_buffer(req);
66c43e99fdSEd Maste 	len = evbuffer_get_length(evbuf);
67c43e99fdSEd Maste 	fwrite(evbuffer_pullup(evbuf, len), len, 1, stdout);
68c43e99fdSEd Maste 	evbuffer_drain(evbuf, len);
69c43e99fdSEd Maste }
70c43e99fdSEd Maste 
connect_cb(struct evhttp_request * proxy_req,void * arg)71c43e99fdSEd Maste static void connect_cb(struct evhttp_request *proxy_req, void *arg)
72c43e99fdSEd Maste {
73c43e99fdSEd Maste 	struct connect_base *base = arg;
74c43e99fdSEd Maste 	struct evhttp_connection *evcon = base->evcon;
75c43e99fdSEd Maste 	struct evhttp_uri *location = base->location;
76*b50261e2SCy Schubert 	struct evhttp_request *req;
77*b50261e2SCy Schubert 	char buffer[URL_MAX];
78c43e99fdSEd Maste 
79c43e99fdSEd Maste 	VERIFY(proxy_req);
80*b50261e2SCy Schubert 	VERIFY(evcon);
81*b50261e2SCy Schubert 
82*b50261e2SCy Schubert 	req = evhttp_request_new(get_cb, NULL);
83c43e99fdSEd Maste 	evhttp_add_header(req->output_headers, "Connection", "close");
84*b50261e2SCy Schubert 	evhttp_add_header(req->output_headers, "Host", evhttp_uri_get_host(location));
85c43e99fdSEd Maste 	VERIFY(!evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
86*b50261e2SCy Schubert 		uri_path(location, buffer)));
87c43e99fdSEd Maste }
88c43e99fdSEd Maste 
main(int argc,const char ** argv)89c43e99fdSEd Maste int main(int argc, const char **argv)
90c43e99fdSEd Maste {
91*b50261e2SCy Schubert 	char hostport[URL_MAX];
92c43e99fdSEd Maste 
93c43e99fdSEd Maste 	struct evhttp_uri *location;
94c43e99fdSEd Maste 	struct evhttp_uri *proxy;
95c43e99fdSEd Maste 
96c43e99fdSEd Maste 	struct event_base *base;
97c43e99fdSEd Maste 	struct evhttp_connection *evcon;
98c43e99fdSEd Maste 	struct evhttp_request *req;
99c43e99fdSEd Maste 
100c43e99fdSEd Maste 	struct connect_base connect_base;
101c43e99fdSEd Maste 
102c43e99fdSEd Maste 	if (argc != 3) {
103c43e99fdSEd Maste 		printf("Usage: %s proxy url\n", argv[0]);
104c43e99fdSEd Maste 		return 1;
105c43e99fdSEd Maste 	}
106c43e99fdSEd Maste 
107*b50261e2SCy Schubert 	proxy    = uri_parse(argv[1]);
108*b50261e2SCy Schubert 	location = uri_parse(argv[2]);
109c43e99fdSEd Maste 
110c43e99fdSEd Maste 	VERIFY(base = event_base_new());
111c43e99fdSEd Maste 	VERIFY(evcon = evhttp_connection_base_new(base, NULL,
112c43e99fdSEd Maste 		evhttp_uri_get_host(proxy), evhttp_uri_get_port(proxy)));
113c43e99fdSEd Maste 	connect_base.evcon = evcon;
114c43e99fdSEd Maste 	connect_base.location = location;
115c43e99fdSEd Maste 	VERIFY(req = evhttp_request_new(connect_cb, &connect_base));
116c43e99fdSEd Maste 
117*b50261e2SCy Schubert 	uri_hostport(location, hostport);
118c43e99fdSEd Maste 	evhttp_add_header(req->output_headers, "Connection", "keep-alive");
119c43e99fdSEd Maste 	evhttp_add_header(req->output_headers, "Proxy-Connection", "keep-alive");
120*b50261e2SCy Schubert 	evhttp_add_header(req->output_headers, "Host", hostport);
121*b50261e2SCy Schubert 	evhttp_make_request(evcon, req, EVHTTP_REQ_CONNECT, hostport);
122c43e99fdSEd Maste 
123c43e99fdSEd Maste 	event_base_dispatch(base);
124*b50261e2SCy Schubert 
125c43e99fdSEd Maste 	evhttp_connection_free(evcon);
126c43e99fdSEd Maste 	event_base_free(base);
127c43e99fdSEd Maste 	evhttp_uri_free(proxy);
128c43e99fdSEd Maste 	evhttp_uri_free(location);
129*b50261e2SCy Schubert 
130c43e99fdSEd Maste 	return 0;
131c43e99fdSEd Maste }
132