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