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