Home | History | Annotate | Line # | Download | only in sample
      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