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