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