1*eabc0478Schristos /* $NetBSD: http-connect.c,v 1.2 2024/08/18 20:47:23 christos Exp $ */ 2897be3a4Schristos 3897be3a4Schristos #include "event2/event-config.h" 4897be3a4Schristos 5897be3a4Schristos #include <event2/event.h> 6897be3a4Schristos #include <event2/http.h> 7897be3a4Schristos #include <event2/http_struct.h> 8897be3a4Schristos #include <event2/buffer.h> 9897be3a4Schristos #include <stdlib.h> 10897be3a4Schristos #include <stdio.h> 11897be3a4Schristos #include <limits.h> 12897be3a4Schristos 13897be3a4Schristos #define VERIFY(cond) do { \ 14897be3a4Schristos if (!(cond)) { \ 15897be3a4Schristos fprintf(stderr, "[error] %s\n", #cond); \ 16897be3a4Schristos exit(EXIT_FAILURE); \ 17897be3a4Schristos } \ 18897be3a4Schristos } while (0); \ 19897be3a4Schristos 20897be3a4Schristos #define URL_MAX 4096 21897be3a4Schristos 22897be3a4Schristos struct connect_base 23897be3a4Schristos { 24897be3a4Schristos struct evhttp_connection *evcon; 25897be3a4Schristos struct evhttp_uri *location; 26897be3a4Schristos }; 27897be3a4Schristos 28897be3a4Schristos static struct evhttp_uri* uri_parse(const char *str) 29897be3a4Schristos { 30897be3a4Schristos struct evhttp_uri *uri; 31897be3a4Schristos VERIFY(uri = evhttp_uri_parse(str)); 32897be3a4Schristos VERIFY(evhttp_uri_get_host(uri)); 33897be3a4Schristos VERIFY(evhttp_uri_get_port(uri) > 0); 34897be3a4Schristos return uri; 35897be3a4Schristos } 36897be3a4Schristos static char* uri_path(struct evhttp_uri *uri, char buffer[URL_MAX]) 37897be3a4Schristos { 38897be3a4Schristos struct evhttp_uri *path; 39897be3a4Schristos 40897be3a4Schristos VERIFY(evhttp_uri_join(uri, buffer, URL_MAX)); 41897be3a4Schristos 42897be3a4Schristos path = evhttp_uri_parse(buffer); 43897be3a4Schristos evhttp_uri_set_scheme(path, NULL); 44897be3a4Schristos evhttp_uri_set_userinfo(path, 0); 45897be3a4Schristos evhttp_uri_set_host(path, NULL); 46897be3a4Schristos evhttp_uri_set_port(path, -1); 47897be3a4Schristos VERIFY(evhttp_uri_join(path, buffer, URL_MAX)); 48897be3a4Schristos return buffer; 49897be3a4Schristos } 50897be3a4Schristos static char* uri_hostport(struct evhttp_uri *uri, char buffer[URL_MAX]) 51897be3a4Schristos { 52897be3a4Schristos VERIFY(evhttp_uri_join(uri, buffer, URL_MAX)); 53897be3a4Schristos VERIFY(evhttp_uri_get_host(uri)); 54897be3a4Schristos VERIFY(evhttp_uri_get_port(uri) > 0); 55897be3a4Schristos evutil_snprintf(buffer, URL_MAX, "%s:%d", 56897be3a4Schristos evhttp_uri_get_host(uri), evhttp_uri_get_port(uri)); 57897be3a4Schristos return buffer; 58897be3a4Schristos } 59897be3a4Schristos 60897be3a4Schristos static void get_cb(struct evhttp_request *req, void *arg) 61897be3a4Schristos { 62897be3a4Schristos ev_ssize_t len; 63897be3a4Schristos struct evbuffer *evbuf; 64897be3a4Schristos 65897be3a4Schristos VERIFY(req); 66897be3a4Schristos 67897be3a4Schristos evbuf = evhttp_request_get_input_buffer(req); 68897be3a4Schristos len = evbuffer_get_length(evbuf); 69897be3a4Schristos fwrite(evbuffer_pullup(evbuf, len), len, 1, stdout); 70897be3a4Schristos evbuffer_drain(evbuf, len); 71897be3a4Schristos } 72897be3a4Schristos 73897be3a4Schristos static void connect_cb(struct evhttp_request *proxy_req, void *arg) 74897be3a4Schristos { 75897be3a4Schristos struct connect_base *base = arg; 76897be3a4Schristos struct evhttp_connection *evcon = base->evcon; 77897be3a4Schristos struct evhttp_uri *location = base->location; 78897be3a4Schristos struct evhttp_request *req; 79897be3a4Schristos char buffer[URL_MAX]; 80897be3a4Schristos 81897be3a4Schristos VERIFY(proxy_req); 82897be3a4Schristos VERIFY(evcon); 83897be3a4Schristos 84897be3a4Schristos req = evhttp_request_new(get_cb, NULL); 85897be3a4Schristos evhttp_add_header(req->output_headers, "Connection", "close"); 86897be3a4Schristos evhttp_add_header(req->output_headers, "Host", evhttp_uri_get_host(location)); 87897be3a4Schristos VERIFY(!evhttp_make_request(evcon, req, EVHTTP_REQ_GET, 88897be3a4Schristos uri_path(location, buffer))); 89897be3a4Schristos } 90897be3a4Schristos 91897be3a4Schristos int main(int argc, const char **argv) 92897be3a4Schristos { 93897be3a4Schristos char hostport[URL_MAX]; 94897be3a4Schristos 95897be3a4Schristos struct evhttp_uri *location; 96897be3a4Schristos struct evhttp_uri *proxy; 97897be3a4Schristos 98897be3a4Schristos struct event_base *base; 99897be3a4Schristos struct evhttp_connection *evcon; 100897be3a4Schristos struct evhttp_request *req; 101897be3a4Schristos 102897be3a4Schristos struct connect_base connect_base; 103897be3a4Schristos 104897be3a4Schristos if (argc != 3) { 105897be3a4Schristos printf("Usage: %s proxy url\n", argv[0]); 106897be3a4Schristos return 1; 107897be3a4Schristos } 108897be3a4Schristos 109897be3a4Schristos proxy = uri_parse(argv[1]); 110897be3a4Schristos location = uri_parse(argv[2]); 111897be3a4Schristos 112897be3a4Schristos VERIFY(base = event_base_new()); 113897be3a4Schristos VERIFY(evcon = evhttp_connection_base_new(base, NULL, 114897be3a4Schristos evhttp_uri_get_host(proxy), evhttp_uri_get_port(proxy))); 115897be3a4Schristos connect_base.evcon = evcon; 116897be3a4Schristos connect_base.location = location; 117897be3a4Schristos VERIFY(req = evhttp_request_new(connect_cb, &connect_base)); 118897be3a4Schristos 119897be3a4Schristos uri_hostport(location, hostport); 120897be3a4Schristos evhttp_add_header(req->output_headers, "Connection", "keep-alive"); 121897be3a4Schristos evhttp_add_header(req->output_headers, "Proxy-Connection", "keep-alive"); 122897be3a4Schristos evhttp_add_header(req->output_headers, "Host", hostport); 123897be3a4Schristos evhttp_make_request(evcon, req, EVHTTP_REQ_CONNECT, hostport); 124897be3a4Schristos 125897be3a4Schristos event_base_dispatch(base); 126897be3a4Schristos 127897be3a4Schristos evhttp_connection_free(evcon); 128897be3a4Schristos event_base_free(base); 129897be3a4Schristos evhttp_uri_free(proxy); 130897be3a4Schristos evhttp_uri_free(location); 131897be3a4Schristos 132897be3a4Schristos return 0; 133897be3a4Schristos } 134