Home | History | Annotate | Line # | Download | only in sample
      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 
     23 struct connect_base
     24 {
     25 	struct evhttp_connection *evcon;
     26 	struct evhttp_uri *location;
     27 };
     28 
     29 static 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 }
     37 static 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 }
     51 static 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 
     61 static 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 
     74 static 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 
     92 int 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