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