xref: /minix3/external/bsd/libevent/dist/sample/http-server.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: http-server.c,v 1.1.1.2 2015/01/29 06:38:19 spz Exp $	*/
2e985b929SDavid van Moolenbroek /*
3e985b929SDavid van Moolenbroek   A trivial static http webserver using Libevent's evhttp.
4e985b929SDavid van Moolenbroek 
5e985b929SDavid van Moolenbroek   This is not the best code in the world, and it does some fairly stupid stuff
6e985b929SDavid van Moolenbroek   that you would never want to do in a production webserver. Caveat hackor!
7e985b929SDavid van Moolenbroek 
8e985b929SDavid van Moolenbroek  */
9e985b929SDavid van Moolenbroek 
10e985b929SDavid van Moolenbroek #include <stdio.h>
11e985b929SDavid van Moolenbroek #include <stdlib.h>
12e985b929SDavid van Moolenbroek #include <string.h>
13e985b929SDavid van Moolenbroek 
14e985b929SDavid van Moolenbroek #include <sys/types.h>
15e985b929SDavid van Moolenbroek #include <sys/stat.h>
16e985b929SDavid van Moolenbroek 
17e985b929SDavid van Moolenbroek #ifdef WIN32
18e985b929SDavid van Moolenbroek #include <winsock2.h>
19e985b929SDavid van Moolenbroek #include <ws2tcpip.h>
20e985b929SDavid van Moolenbroek #include <windows.h>
21e985b929SDavid van Moolenbroek #include <io.h>
22e985b929SDavid van Moolenbroek #include <fcntl.h>
23e985b929SDavid van Moolenbroek #ifndef S_ISDIR
24e985b929SDavid van Moolenbroek #define S_ISDIR(x) (((x) & S_IFMT) == S_IFDIR)
25e985b929SDavid van Moolenbroek #endif
26e985b929SDavid van Moolenbroek #else
27e985b929SDavid van Moolenbroek #include <sys/stat.h>
28e985b929SDavid van Moolenbroek #include <sys/socket.h>
29e985b929SDavid van Moolenbroek #include <signal.h>
30e985b929SDavid van Moolenbroek #include <fcntl.h>
31e985b929SDavid van Moolenbroek #include <unistd.h>
32e985b929SDavid van Moolenbroek #include <dirent.h>
33e985b929SDavid van Moolenbroek #endif
34e985b929SDavid van Moolenbroek 
35e985b929SDavid van Moolenbroek #include <event2/event.h>
36e985b929SDavid van Moolenbroek #include <event2/http.h>
37e985b929SDavid van Moolenbroek #include <event2/buffer.h>
38e985b929SDavid van Moolenbroek #include <event2/util.h>
39e985b929SDavid van Moolenbroek #include <event2/keyvalq_struct.h>
40e985b929SDavid van Moolenbroek 
41e985b929SDavid van Moolenbroek #ifdef _EVENT_HAVE_NETINET_IN_H
42e985b929SDavid van Moolenbroek #include <netinet/in.h>
43e985b929SDavid van Moolenbroek # ifdef _XOPEN_SOURCE_EXTENDED
44e985b929SDavid van Moolenbroek #  include <arpa/inet.h>
45e985b929SDavid van Moolenbroek # endif
46e985b929SDavid van Moolenbroek #endif
47e985b929SDavid van Moolenbroek 
48e985b929SDavid van Moolenbroek /* Compatibility for possible missing IPv6 declarations */
49e985b929SDavid van Moolenbroek #include "../util-internal.h"
50e985b929SDavid van Moolenbroek 
51e985b929SDavid van Moolenbroek #ifdef WIN32
52e985b929SDavid van Moolenbroek #define stat _stat
53e985b929SDavid van Moolenbroek #define fstat _fstat
54e985b929SDavid van Moolenbroek #define open _open
55e985b929SDavid van Moolenbroek #define close _close
56e985b929SDavid van Moolenbroek #define O_RDONLY _O_RDONLY
57e985b929SDavid van Moolenbroek #endif
58e985b929SDavid van Moolenbroek 
59e985b929SDavid van Moolenbroek char uri_root[512];
60e985b929SDavid van Moolenbroek 
61e985b929SDavid van Moolenbroek static const struct table_entry {
62e985b929SDavid van Moolenbroek 	const char *extension;
63e985b929SDavid van Moolenbroek 	const char *content_type;
64e985b929SDavid van Moolenbroek } content_type_table[] = {
65e985b929SDavid van Moolenbroek 	{ "txt", "text/plain" },
66e985b929SDavid van Moolenbroek 	{ "c", "text/plain" },
67e985b929SDavid van Moolenbroek 	{ "h", "text/plain" },
68e985b929SDavid van Moolenbroek 	{ "html", "text/html" },
69e985b929SDavid van Moolenbroek 	{ "htm", "text/htm" },
70e985b929SDavid van Moolenbroek 	{ "css", "text/css" },
71e985b929SDavid van Moolenbroek 	{ "gif", "image/gif" },
72e985b929SDavid van Moolenbroek 	{ "jpg", "image/jpeg" },
73e985b929SDavid van Moolenbroek 	{ "jpeg", "image/jpeg" },
74e985b929SDavid van Moolenbroek 	{ "png", "image/png" },
75e985b929SDavid van Moolenbroek 	{ "pdf", "application/pdf" },
76e985b929SDavid van Moolenbroek 	{ "ps", "application/postsript" },
77e985b929SDavid van Moolenbroek 	{ NULL, NULL },
78e985b929SDavid van Moolenbroek };
79e985b929SDavid van Moolenbroek 
80e985b929SDavid van Moolenbroek /* Try to guess a good content-type for 'path' */
81e985b929SDavid van Moolenbroek static const char *
guess_content_type(const char * path)82e985b929SDavid van Moolenbroek guess_content_type(const char *path)
83e985b929SDavid van Moolenbroek {
84e985b929SDavid van Moolenbroek 	const char *last_period, *extension;
85e985b929SDavid van Moolenbroek 	const struct table_entry *ent;
86e985b929SDavid van Moolenbroek 	last_period = strrchr(path, '.');
87e985b929SDavid van Moolenbroek 	if (!last_period || strchr(last_period, '/'))
88e985b929SDavid van Moolenbroek 		goto not_found; /* no exension */
89e985b929SDavid van Moolenbroek 	extension = last_period + 1;
90e985b929SDavid van Moolenbroek 	for (ent = &content_type_table[0]; ent->extension; ++ent) {
91e985b929SDavid van Moolenbroek 		if (!evutil_ascii_strcasecmp(ent->extension, extension))
92e985b929SDavid van Moolenbroek 			return ent->content_type;
93e985b929SDavid van Moolenbroek 	}
94e985b929SDavid van Moolenbroek 
95e985b929SDavid van Moolenbroek not_found:
96e985b929SDavid van Moolenbroek 	return "application/misc";
97e985b929SDavid van Moolenbroek }
98e985b929SDavid van Moolenbroek 
99e985b929SDavid van Moolenbroek /* Callback used for the /dump URI, and for every non-GET request:
100e985b929SDavid van Moolenbroek  * dumps all information to stdout and gives back a trivial 200 ok */
101e985b929SDavid van Moolenbroek static void
dump_request_cb(struct evhttp_request * req,void * arg)102e985b929SDavid van Moolenbroek dump_request_cb(struct evhttp_request *req, void *arg)
103e985b929SDavid van Moolenbroek {
104e985b929SDavid van Moolenbroek 	const char *cmdtype;
105e985b929SDavid van Moolenbroek 	struct evkeyvalq *headers;
106e985b929SDavid van Moolenbroek 	struct evkeyval *header;
107e985b929SDavid van Moolenbroek 	struct evbuffer *buf;
108e985b929SDavid van Moolenbroek 
109e985b929SDavid van Moolenbroek 	switch (evhttp_request_get_command(req)) {
110e985b929SDavid van Moolenbroek 	case EVHTTP_REQ_GET: cmdtype = "GET"; break;
111e985b929SDavid van Moolenbroek 	case EVHTTP_REQ_POST: cmdtype = "POST"; break;
112e985b929SDavid van Moolenbroek 	case EVHTTP_REQ_HEAD: cmdtype = "HEAD"; break;
113e985b929SDavid van Moolenbroek 	case EVHTTP_REQ_PUT: cmdtype = "PUT"; break;
114e985b929SDavid van Moolenbroek 	case EVHTTP_REQ_DELETE: cmdtype = "DELETE"; break;
115e985b929SDavid van Moolenbroek 	case EVHTTP_REQ_OPTIONS: cmdtype = "OPTIONS"; break;
116e985b929SDavid van Moolenbroek 	case EVHTTP_REQ_TRACE: cmdtype = "TRACE"; break;
117e985b929SDavid van Moolenbroek 	case EVHTTP_REQ_CONNECT: cmdtype = "CONNECT"; break;
118e985b929SDavid van Moolenbroek 	case EVHTTP_REQ_PATCH: cmdtype = "PATCH"; break;
119e985b929SDavid van Moolenbroek 	default: cmdtype = "unknown"; break;
120e985b929SDavid van Moolenbroek 	}
121e985b929SDavid van Moolenbroek 
122e985b929SDavid van Moolenbroek 	printf("Received a %s request for %s\nHeaders:\n",
123e985b929SDavid van Moolenbroek 	    cmdtype, evhttp_request_get_uri(req));
124e985b929SDavid van Moolenbroek 
125e985b929SDavid van Moolenbroek 	headers = evhttp_request_get_input_headers(req);
126e985b929SDavid van Moolenbroek 	for (header = headers->tqh_first; header;
127e985b929SDavid van Moolenbroek 	    header = header->next.tqe_next) {
128e985b929SDavid van Moolenbroek 		printf("  %s: %s\n", header->key, header->value);
129e985b929SDavid van Moolenbroek 	}
130e985b929SDavid van Moolenbroek 
131e985b929SDavid van Moolenbroek 	buf = evhttp_request_get_input_buffer(req);
132e985b929SDavid van Moolenbroek 	puts("Input data: <<<");
133e985b929SDavid van Moolenbroek 	while (evbuffer_get_length(buf)) {
134e985b929SDavid van Moolenbroek 		int n;
135e985b929SDavid van Moolenbroek 		char cbuf[128];
136*0a6a1f1dSLionel Sambuc 		n = evbuffer_remove(buf, cbuf, sizeof(cbuf));
137e985b929SDavid van Moolenbroek 		if (n > 0)
138e985b929SDavid van Moolenbroek 			(void) fwrite(cbuf, 1, n, stdout);
139e985b929SDavid van Moolenbroek 	}
140e985b929SDavid van Moolenbroek 	puts(">>>");
141e985b929SDavid van Moolenbroek 
142e985b929SDavid van Moolenbroek 	evhttp_send_reply(req, 200, "OK", NULL);
143e985b929SDavid van Moolenbroek }
144e985b929SDavid van Moolenbroek 
145e985b929SDavid van Moolenbroek /* This callback gets invoked when we get any http request that doesn't match
146e985b929SDavid van Moolenbroek  * any other callback.  Like any evhttp server callback, it has a simple job:
147e985b929SDavid van Moolenbroek  * it must eventually call evhttp_send_error() or evhttp_send_reply().
148e985b929SDavid van Moolenbroek  */
149e985b929SDavid van Moolenbroek static void
send_document_cb(struct evhttp_request * req,void * arg)150e985b929SDavid van Moolenbroek send_document_cb(struct evhttp_request *req, void *arg)
151e985b929SDavid van Moolenbroek {
152e985b929SDavid van Moolenbroek 	struct evbuffer *evb = NULL;
153e985b929SDavid van Moolenbroek 	const char *docroot = arg;
154e985b929SDavid van Moolenbroek 	const char *uri = evhttp_request_get_uri(req);
155e985b929SDavid van Moolenbroek 	struct evhttp_uri *decoded = NULL;
156e985b929SDavid van Moolenbroek 	const char *path;
157e985b929SDavid van Moolenbroek 	char *decoded_path;
158e985b929SDavid van Moolenbroek 	char *whole_path = NULL;
159e985b929SDavid van Moolenbroek 	size_t len;
160e985b929SDavid van Moolenbroek 	int fd = -1;
161e985b929SDavid van Moolenbroek 	struct stat st;
162e985b929SDavid van Moolenbroek 
163e985b929SDavid van Moolenbroek 	if (evhttp_request_get_command(req) != EVHTTP_REQ_GET) {
164e985b929SDavid van Moolenbroek 		dump_request_cb(req, arg);
165e985b929SDavid van Moolenbroek 		return;
166e985b929SDavid van Moolenbroek 	}
167e985b929SDavid van Moolenbroek 
168e985b929SDavid van Moolenbroek 	printf("Got a GET request for <%s>\n",  uri);
169e985b929SDavid van Moolenbroek 
170e985b929SDavid van Moolenbroek 	/* Decode the URI */
171e985b929SDavid van Moolenbroek 	decoded = evhttp_uri_parse(uri);
172e985b929SDavid van Moolenbroek 	if (!decoded) {
173e985b929SDavid van Moolenbroek 		printf("It's not a good URI. Sending BADREQUEST\n");
174e985b929SDavid van Moolenbroek 		evhttp_send_error(req, HTTP_BADREQUEST, 0);
175e985b929SDavid van Moolenbroek 		return;
176e985b929SDavid van Moolenbroek 	}
177e985b929SDavid van Moolenbroek 
178e985b929SDavid van Moolenbroek 	/* Let's see what path the user asked for. */
179e985b929SDavid van Moolenbroek 	path = evhttp_uri_get_path(decoded);
180e985b929SDavid van Moolenbroek 	if (!path) path = "/";
181e985b929SDavid van Moolenbroek 
182e985b929SDavid van Moolenbroek 	/* We need to decode it, to see what path the user really wanted. */
183e985b929SDavid van Moolenbroek 	decoded_path = evhttp_uridecode(path, 0, NULL);
184e985b929SDavid van Moolenbroek 	if (decoded_path == NULL)
185e985b929SDavid van Moolenbroek 		goto err;
186e985b929SDavid van Moolenbroek 	/* Don't allow any ".."s in the path, to avoid exposing stuff outside
187e985b929SDavid van Moolenbroek 	 * of the docroot.  This test is both overzealous and underzealous:
188e985b929SDavid van Moolenbroek 	 * it forbids aceptable paths like "/this/one..here", but it doesn't
189e985b929SDavid van Moolenbroek 	 * do anything to prevent symlink following." */
190e985b929SDavid van Moolenbroek 	if (strstr(decoded_path, ".."))
191e985b929SDavid van Moolenbroek 		goto err;
192e985b929SDavid van Moolenbroek 
193e985b929SDavid van Moolenbroek 	len = strlen(decoded_path)+strlen(docroot)+2;
194e985b929SDavid van Moolenbroek 	if (!(whole_path = malloc(len))) {
195e985b929SDavid van Moolenbroek 		perror("malloc");
196e985b929SDavid van Moolenbroek 		goto err;
197e985b929SDavid van Moolenbroek 	}
198e985b929SDavid van Moolenbroek 	evutil_snprintf(whole_path, len, "%s/%s", docroot, decoded_path);
199e985b929SDavid van Moolenbroek 
200e985b929SDavid van Moolenbroek 	if (stat(whole_path, &st)<0) {
201e985b929SDavid van Moolenbroek 		goto err;
202e985b929SDavid van Moolenbroek 	}
203e985b929SDavid van Moolenbroek 
204e985b929SDavid van Moolenbroek 	/* This holds the content we're sending. */
205e985b929SDavid van Moolenbroek 	evb = evbuffer_new();
206e985b929SDavid van Moolenbroek 
207e985b929SDavid van Moolenbroek 	if (S_ISDIR(st.st_mode)) {
208e985b929SDavid van Moolenbroek 		/* If it's a directory, read the comments and make a little
209e985b929SDavid van Moolenbroek 		 * index page */
210e985b929SDavid van Moolenbroek #ifdef WIN32
211e985b929SDavid van Moolenbroek 		HANDLE d;
212e985b929SDavid van Moolenbroek 		WIN32_FIND_DATAA ent;
213e985b929SDavid van Moolenbroek 		char *pattern;
214e985b929SDavid van Moolenbroek 		size_t dirlen;
215e985b929SDavid van Moolenbroek #else
216e985b929SDavid van Moolenbroek 		DIR *d;
217e985b929SDavid van Moolenbroek 		struct dirent *ent;
218e985b929SDavid van Moolenbroek #endif
219e985b929SDavid van Moolenbroek 		const char *trailing_slash = "";
220e985b929SDavid van Moolenbroek 
221e985b929SDavid van Moolenbroek 		if (!strlen(path) || path[strlen(path)-1] != '/')
222e985b929SDavid van Moolenbroek 			trailing_slash = "/";
223e985b929SDavid van Moolenbroek 
224e985b929SDavid van Moolenbroek #ifdef WIN32
225e985b929SDavid van Moolenbroek 		dirlen = strlen(whole_path);
226e985b929SDavid van Moolenbroek 		pattern = malloc(dirlen+3);
227e985b929SDavid van Moolenbroek 		memcpy(pattern, whole_path, dirlen);
228e985b929SDavid van Moolenbroek 		pattern[dirlen] = '\\';
229e985b929SDavid van Moolenbroek 		pattern[dirlen+1] = '*';
230e985b929SDavid van Moolenbroek 		pattern[dirlen+2] = '\0';
231e985b929SDavid van Moolenbroek 		d = FindFirstFileA(pattern, &ent);
232e985b929SDavid van Moolenbroek 		free(pattern);
233e985b929SDavid van Moolenbroek 		if (d == INVALID_HANDLE_VALUE)
234e985b929SDavid van Moolenbroek 			goto err;
235e985b929SDavid van Moolenbroek #else
236e985b929SDavid van Moolenbroek 		if (!(d = opendir(whole_path)))
237e985b929SDavid van Moolenbroek 			goto err;
238e985b929SDavid van Moolenbroek #endif
239e985b929SDavid van Moolenbroek 
240e985b929SDavid van Moolenbroek 		evbuffer_add_printf(evb, "<html>\n <head>\n"
241e985b929SDavid van Moolenbroek 		    "  <title>%s</title>\n"
242e985b929SDavid van Moolenbroek 		    "  <base href='%s%s%s'>\n"
243e985b929SDavid van Moolenbroek 		    " </head>\n"
244e985b929SDavid van Moolenbroek 		    " <body>\n"
245e985b929SDavid van Moolenbroek 		    "  <h1>%s</h1>\n"
246e985b929SDavid van Moolenbroek 		    "  <ul>\n",
247e985b929SDavid van Moolenbroek 		    decoded_path, /* XXX html-escape this. */
248e985b929SDavid van Moolenbroek 		    uri_root, path, /* XXX html-escape this? */
249e985b929SDavid van Moolenbroek 		    trailing_slash,
250e985b929SDavid van Moolenbroek 		    decoded_path /* XXX html-escape this */);
251e985b929SDavid van Moolenbroek #ifdef WIN32
252e985b929SDavid van Moolenbroek 		do {
253e985b929SDavid van Moolenbroek 			const char *name = ent.cFileName;
254e985b929SDavid van Moolenbroek #else
255e985b929SDavid van Moolenbroek 		while ((ent = readdir(d))) {
256e985b929SDavid van Moolenbroek 			const char *name = ent->d_name;
257e985b929SDavid van Moolenbroek #endif
258e985b929SDavid van Moolenbroek 			evbuffer_add_printf(evb,
259e985b929SDavid van Moolenbroek 			    "    <li><a href=\"%s\">%s</a>\n",
260e985b929SDavid van Moolenbroek 			    name, name);/* XXX escape this */
261e985b929SDavid van Moolenbroek #ifdef WIN32
262e985b929SDavid van Moolenbroek 		} while (FindNextFileA(d, &ent));
263e985b929SDavid van Moolenbroek #else
264e985b929SDavid van Moolenbroek 		}
265e985b929SDavid van Moolenbroek #endif
266e985b929SDavid van Moolenbroek 		evbuffer_add_printf(evb, "</ul></body></html>\n");
267e985b929SDavid van Moolenbroek #ifdef WIN32
268*0a6a1f1dSLionel Sambuc 		FindClose(d);
269e985b929SDavid van Moolenbroek #else
270e985b929SDavid van Moolenbroek 		closedir(d);
271e985b929SDavid van Moolenbroek #endif
272e985b929SDavid van Moolenbroek 		evhttp_add_header(evhttp_request_get_output_headers(req),
273e985b929SDavid van Moolenbroek 		    "Content-Type", "text/html");
274e985b929SDavid van Moolenbroek 	} else {
275e985b929SDavid van Moolenbroek 		/* Otherwise it's a file; add it to the buffer to get
276e985b929SDavid van Moolenbroek 		 * sent via sendfile */
277e985b929SDavid van Moolenbroek 		const char *type = guess_content_type(decoded_path);
278e985b929SDavid van Moolenbroek 		if ((fd = open(whole_path, O_RDONLY)) < 0) {
279e985b929SDavid van Moolenbroek 			perror("open");
280e985b929SDavid van Moolenbroek 			goto err;
281e985b929SDavid van Moolenbroek 		}
282e985b929SDavid van Moolenbroek 
283e985b929SDavid van Moolenbroek 		if (fstat(fd, &st)<0) {
284e985b929SDavid van Moolenbroek 			/* Make sure the length still matches, now that we
285e985b929SDavid van Moolenbroek 			 * opened the file :/ */
286e985b929SDavid van Moolenbroek 			perror("fstat");
287e985b929SDavid van Moolenbroek 			goto err;
288e985b929SDavid van Moolenbroek 		}
289e985b929SDavid van Moolenbroek 		evhttp_add_header(evhttp_request_get_output_headers(req),
290e985b929SDavid van Moolenbroek 		    "Content-Type", type);
291e985b929SDavid van Moolenbroek 		evbuffer_add_file(evb, fd, 0, st.st_size);
292e985b929SDavid van Moolenbroek 	}
293e985b929SDavid van Moolenbroek 
294e985b929SDavid van Moolenbroek 	evhttp_send_reply(req, 200, "OK", evb);
295e985b929SDavid van Moolenbroek 	goto done;
296e985b929SDavid van Moolenbroek err:
297e985b929SDavid van Moolenbroek 	evhttp_send_error(req, 404, "Document was not found");
298e985b929SDavid van Moolenbroek 	if (fd>=0)
299e985b929SDavid van Moolenbroek 		close(fd);
300e985b929SDavid van Moolenbroek done:
301e985b929SDavid van Moolenbroek 	if (decoded)
302e985b929SDavid van Moolenbroek 		evhttp_uri_free(decoded);
303e985b929SDavid van Moolenbroek 	if (decoded_path)
304e985b929SDavid van Moolenbroek 		free(decoded_path);
305e985b929SDavid van Moolenbroek 	if (whole_path)
306e985b929SDavid van Moolenbroek 		free(whole_path);
307e985b929SDavid van Moolenbroek 	if (evb)
308e985b929SDavid van Moolenbroek 		evbuffer_free(evb);
309e985b929SDavid van Moolenbroek }
310e985b929SDavid van Moolenbroek 
311e985b929SDavid van Moolenbroek static void
syntax(void)312e985b929SDavid van Moolenbroek syntax(void)
313e985b929SDavid van Moolenbroek {
314e985b929SDavid van Moolenbroek 	fprintf(stdout, "Syntax: http-server <docroot>\n");
315e985b929SDavid van Moolenbroek }
316e985b929SDavid van Moolenbroek 
317e985b929SDavid van Moolenbroek int
main(int argc,char ** argv)318e985b929SDavid van Moolenbroek main(int argc, char **argv)
319e985b929SDavid van Moolenbroek {
320e985b929SDavid van Moolenbroek 	struct event_base *base;
321e985b929SDavid van Moolenbroek 	struct evhttp *http;
322e985b929SDavid van Moolenbroek 	struct evhttp_bound_socket *handle;
323e985b929SDavid van Moolenbroek 
324e985b929SDavid van Moolenbroek 	unsigned short port = 0;
325e985b929SDavid van Moolenbroek #ifdef WIN32
326e985b929SDavid van Moolenbroek 	WSADATA WSAData;
327e985b929SDavid van Moolenbroek 	WSAStartup(0x101, &WSAData);
328e985b929SDavid van Moolenbroek #else
329e985b929SDavid van Moolenbroek 	if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
330e985b929SDavid van Moolenbroek 		return (1);
331e985b929SDavid van Moolenbroek #endif
332e985b929SDavid van Moolenbroek 	if (argc < 2) {
333e985b929SDavid van Moolenbroek 		syntax();
334e985b929SDavid van Moolenbroek 		return 1;
335e985b929SDavid van Moolenbroek 	}
336e985b929SDavid van Moolenbroek 
337e985b929SDavid van Moolenbroek 	base = event_base_new();
338e985b929SDavid van Moolenbroek 	if (!base) {
339e985b929SDavid van Moolenbroek 		fprintf(stderr, "Couldn't create an event_base: exiting\n");
340e985b929SDavid van Moolenbroek 		return 1;
341e985b929SDavid van Moolenbroek 	}
342e985b929SDavid van Moolenbroek 
343e985b929SDavid van Moolenbroek 	/* Create a new evhttp object to handle requests. */
344e985b929SDavid van Moolenbroek 	http = evhttp_new(base);
345e985b929SDavid van Moolenbroek 	if (!http) {
346e985b929SDavid van Moolenbroek 		fprintf(stderr, "couldn't create evhttp. Exiting.\n");
347e985b929SDavid van Moolenbroek 		return 1;
348e985b929SDavid van Moolenbroek 	}
349e985b929SDavid van Moolenbroek 
350e985b929SDavid van Moolenbroek 	/* The /dump URI will dump all requests to stdout and say 200 ok. */
351e985b929SDavid van Moolenbroek 	evhttp_set_cb(http, "/dump", dump_request_cb, NULL);
352e985b929SDavid van Moolenbroek 
353e985b929SDavid van Moolenbroek 	/* We want to accept arbitrary requests, so we need to set a "generic"
354e985b929SDavid van Moolenbroek 	 * cb.  We can also add callbacks for specific paths. */
355e985b929SDavid van Moolenbroek 	evhttp_set_gencb(http, send_document_cb, argv[1]);
356e985b929SDavid van Moolenbroek 
357e985b929SDavid van Moolenbroek 	/* Now we tell the evhttp what port to listen on */
358e985b929SDavid van Moolenbroek 	handle = evhttp_bind_socket_with_handle(http, "0.0.0.0", port);
359e985b929SDavid van Moolenbroek 	if (!handle) {
360e985b929SDavid van Moolenbroek 		fprintf(stderr, "couldn't bind to port %d. Exiting.\n",
361e985b929SDavid van Moolenbroek 		    (int)port);
362e985b929SDavid van Moolenbroek 		return 1;
363e985b929SDavid van Moolenbroek 	}
364e985b929SDavid van Moolenbroek 
365e985b929SDavid van Moolenbroek 	{
366e985b929SDavid van Moolenbroek 		/* Extract and display the address we're listening on. */
367e985b929SDavid van Moolenbroek 		struct sockaddr_storage ss;
368e985b929SDavid van Moolenbroek 		evutil_socket_t fd;
369e985b929SDavid van Moolenbroek 		ev_socklen_t socklen = sizeof(ss);
370e985b929SDavid van Moolenbroek 		char addrbuf[128];
371e985b929SDavid van Moolenbroek 		void *inaddr;
372e985b929SDavid van Moolenbroek 		const char *addr;
373e985b929SDavid van Moolenbroek 		int got_port = -1;
374e985b929SDavid van Moolenbroek 		fd = evhttp_bound_socket_get_fd(handle);
375e985b929SDavid van Moolenbroek 		memset(&ss, 0, sizeof(ss));
376e985b929SDavid van Moolenbroek 		if (getsockname(fd, (struct sockaddr *)&ss, &socklen)) {
377e985b929SDavid van Moolenbroek 			perror("getsockname() failed");
378e985b929SDavid van Moolenbroek 			return 1;
379e985b929SDavid van Moolenbroek 		}
380e985b929SDavid van Moolenbroek 		if (ss.ss_family == AF_INET) {
381e985b929SDavid van Moolenbroek 			got_port = ntohs(((struct sockaddr_in*)&ss)->sin_port);
382e985b929SDavid van Moolenbroek 			inaddr = &((struct sockaddr_in*)&ss)->sin_addr;
383e985b929SDavid van Moolenbroek 		} else if (ss.ss_family == AF_INET6) {
384e985b929SDavid van Moolenbroek 			got_port = ntohs(((struct sockaddr_in6*)&ss)->sin6_port);
385e985b929SDavid van Moolenbroek 			inaddr = &((struct sockaddr_in6*)&ss)->sin6_addr;
386e985b929SDavid van Moolenbroek 		} else {
387e985b929SDavid van Moolenbroek 			fprintf(stderr, "Weird address family %d\n",
388e985b929SDavid van Moolenbroek 			    ss.ss_family);
389e985b929SDavid van Moolenbroek 			return 1;
390e985b929SDavid van Moolenbroek 		}
391e985b929SDavid van Moolenbroek 		addr = evutil_inet_ntop(ss.ss_family, inaddr, addrbuf,
392e985b929SDavid van Moolenbroek 		    sizeof(addrbuf));
393e985b929SDavid van Moolenbroek 		if (addr) {
394e985b929SDavid van Moolenbroek 			printf("Listening on %s:%d\n", addr, got_port);
395e985b929SDavid van Moolenbroek 			evutil_snprintf(uri_root, sizeof(uri_root),
396e985b929SDavid van Moolenbroek 			    "http://%s:%d",addr,got_port);
397e985b929SDavid van Moolenbroek 		} else {
398e985b929SDavid van Moolenbroek 			fprintf(stderr, "evutil_inet_ntop failed\n");
399e985b929SDavid van Moolenbroek 			return 1;
400e985b929SDavid van Moolenbroek 		}
401e985b929SDavid van Moolenbroek 	}
402e985b929SDavid van Moolenbroek 
403e985b929SDavid van Moolenbroek 	event_base_dispatch(base);
404e985b929SDavid van Moolenbroek 
405e985b929SDavid van Moolenbroek 	return 0;
406e985b929SDavid van Moolenbroek }
407