xref: /netbsd-src/external/bsd/libevent/dist/sample/http-connect.c (revision 657871a79c9a2060a6255a242fa1a1ef76b56ec6)
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 
uri_parse(const char * str)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 }
uri_path(struct evhttp_uri * uri,char buffer[URL_MAX])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 }
uri_hostport(struct evhttp_uri * uri,char buffer[URL_MAX])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 
get_cb(struct evhttp_request * req,void * arg)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 
connect_cb(struct evhttp_request * proxy_req,void * arg)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 
main(int argc,const char ** argv)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