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
20struct connect_base
21{
22	struct evhttp_connection *evcon;
23	struct evhttp_uri *location;
24};
25
26static 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}
34static 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}
48static 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
58static 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
71static 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
89int 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