NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: bin/58880: bozohttpd(8): set custom header field in responses



"Taylor R Campbell via gnats" <gnats-admin%NetBSD.org@localhost> writes:

> The following reply was made to PR bin/58880; it has been noted by GNATS.
>
> From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
> To: Sunil Nimmagadda <sunil%nimmagadda.net@localhost>
> Cc: gnats-admin%netbsd.org@localhost,
> 	netbsd-bugs%netbsd.org@localhost, gnats-bugs%netbsd.org@localhost
> Subject: Re: bin/58880: bozohttpd(8): set custom header field in responses
> Date: Fri, 13 Dec 2024 14:57:03 +0000
>
>  > Date: Fri, 13 Dec 2024 13:03:05 +0530
>  > From: Sunil Nimmagadda <sunil%nimmagadda.net@localhost>
>  >=20
>  > This diff allows custom headers to be specified in a .bzcustomheaders fil=
>  e at
>  > the root of the server. The lines from it are included verbatim as
>  > headers in all of the responses...
>  
>  Awesome!  Can I interest you in writing some automatic tests for this
>  too, including the edge cases martin@ mentioned?

Sure, updated diff with atf test case. For now, this diff only supports
static text and no variable substitutions...
From 7f8f1ab04076f7a276fd3fec892450880ac388e1 Mon Sep 17 00:00:00 2001
From: Sunil Nimmagadda <sunil%nimmagadda.net@localhost>
Date: Sat, 14 Dec 2024 09:00:05 +0530
Subject: [PATCH] Implement custom headers for httpd.

---
 libexec/httpd/bozohttpd.8               |  5 ++
 libexec/httpd/bozohttpd.c               | 36 ++++++++++++++
 libexec/httpd/bozohttpd.h               | 10 ++++
 tests/libexec/httpd/.bzcustomheaders    |  2 +
 tests/libexec/httpd/Makefile            |  6 +++
 tests/libexec/httpd/custom_headers.awk  | 51 ++++++++++++++++++++
 tests/libexec/httpd/index.html          |  4 ++
 tests/libexec/httpd/t_custom_headers.sh | 62 +++++++++++++++++++++++++
 8 files changed, 176 insertions(+)
 create mode 100644 tests/libexec/httpd/.bzcustomheaders
 create mode 100644 tests/libexec/httpd/Makefile
 create mode 100644 tests/libexec/httpd/custom_headers.awk
 create mode 100644 tests/libexec/httpd/index.html
 create mode 100644 tests/libexec/httpd/t_custom_headers.sh

diff --git a/libexec/httpd/bozohttpd.8 b/libexec/httpd/bozohttpd.8
index 196fcb52acc7..b37cfb50de6c 100644
--- a/libexec/httpd/bozohttpd.8
+++ b/libexec/httpd/bozohttpd.8
@@ -640,6 +640,11 @@ with a backslash
 .Pq Ql \e
 The right hand side of the colon is always used verbatim, no escape sequences
 are interpreted.
+.Ss CUSTOM RESPONSE HEADERS
+If a
+.Pa .bzcustomheaders
+file is found at the root of the server, it is expected to contain
+custom headers to be included verbatim in all of the responses.
 .Sh EXAMPLES
 To configure set of virtual hosts, one would use an
 .Xr inetd.conf 5
diff --git a/libexec/httpd/bozohttpd.c b/libexec/httpd/bozohttpd.c
index 656bdf073af3..a488f8b4fa5f 100644
--- a/libexec/httpd/bozohttpd.c
+++ b/libexec/httpd/bozohttpd.c
@@ -181,6 +181,7 @@ struct {
 	{ ABSREDIRECT_FILE,   "rejected absredirect request" },
 	{ REMAP_FILE,         "rejected remap request" },
 	{ AUTH_FILE,          "rejected authfile request" },
+	{ CUSTOMHEADERS_FILE, "rejected customheaders request" },
 	{ NULL,               NULL },
 };
 
@@ -1974,12 +1975,17 @@ bozo_print_header(bozo_httpreq_t *request,
 	off_t len;
 	char	date[40];
 	bozoheaders_t *hdr;
+	bozocustomheaders_t *chdr;
 
 	SIMPLEQ_FOREACH(hdr, &request->hr_replheaders, h_next) {
 		bozo_printf(httpd, "%s: %s\r\n", hdr->h_header,
 				hdr->h_value);
 	}
 
+        SIMPLEQ_FOREACH(chdr, &httpd->customheaders, h_next) {
+		bozo_printf(httpd, "%s\r\n", chdr->h_header);
+        }
+
 	bozo_printf(httpd, "Date: %s\r\n", bozo_http_date(date, sizeof(date)));
 	bozo_printf(httpd, "Server: %s\r\n", httpd->server_software);
 	bozo_printf(httpd, "Accept-Ranges: bytes\r\n");
@@ -2524,6 +2530,8 @@ bozo_init_httpd(bozohttpd_t *httpd)
 #ifndef NO_LUA_SUPPORT
 	SIMPLEQ_INIT(&httpd->lua_states);
 #endif
+
+        SIMPLEQ_INIT(&httpd->customheaders);
 	return 1;
 }
 
@@ -2562,6 +2570,33 @@ bozo_set_defaults(bozohttpd_t *httpd, bozoprefs_t *prefs)
 	return bozo_init_httpd(httpd) && bozo_init_prefs(httpd, prefs);
 }
 
+static void
+bozo_setup_customheaders(bozohttpd_t *httpd)
+{
+	struct bozocustomheaders *hdr;
+	FILE *fp;
+	char *fn, *line = NULL;
+	size_t linecap = 0;
+	ssize_t linelen;
+
+	bozoasprintf(httpd, &fn, "%s/%s", httpd->slashdir, CUSTOMHEADERS_FILE);
+	fp = fopen(fn, "r");
+	if (fp == NULL) {
+		free(fn);
+		return;
+	}
+
+	free(fn);
+	while ((linelen = getline(&line, &linecap, fp)) > 0) {
+		line[strcspn(line, "\n")] = '\0';
+		hdr = bozomalloc(httpd, sizeof *hdr);
+		hdr->h_header = bozostrdup(httpd, NULL, line);
+		SIMPLEQ_INSERT_TAIL(&httpd->customheaders, hdr, h_next);
+	}
+	free(line);
+	fclose(fp);
+}
+
 /* set the virtual host name, port and root */
 int
 bozo_setup(bozohttpd_t *httpd, bozoprefs_t *prefs, const char *vhost,
@@ -2674,6 +2709,7 @@ bozo_setup(bozohttpd_t *httpd, bozoprefs_t *prefs, const char *vhost,
 	 */
 	bozo_ssl_init(httpd);
 	bozo_daemon_init(httpd);
+	bozo_setup_customheaders(httpd);
 
 	username = bozo_get_pref(prefs, "username");
 	if (username != NULL) {
diff --git a/libexec/httpd/bozohttpd.h b/libexec/httpd/bozohttpd.h
index cdfec757793e..811b891215da 100644
--- a/libexec/httpd/bozohttpd.h
+++ b/libexec/httpd/bozohttpd.h
@@ -64,6 +64,12 @@ typedef struct bozoheaders {
 } bozoheaders_t;
 SIMPLEQ_HEAD(qheaders, bozoheaders);
 
+typedef struct bozocustomheaders {
+	const char *h_header;
+	SIMPLEQ_ENTRY(bozocustomheaders)	h_next;
+} bozocustomheaders_t;
+SIMPLEQ_HEAD(cheaders, bozocustomheaders);
+
 #ifndef NO_LUA_SUPPORT
 typedef struct lua_handler {
 	const char	*name;
@@ -144,6 +150,7 @@ typedef struct bozohttpd_t {
 	ssize_t		 getln_buflen;	/* length of allocated space */
 	char		*errorbuf;	/* no dynamic allocation allowed */
 	bozo_consts_t	 consts;	/* various constants */
+	struct cheaders	customheaders;	/* Headers read from .bzcustomheaders */
 } bozohttpd_t;
 
 /* bozo_httpreq_t */
@@ -280,6 +287,9 @@ void	debug__(bozohttpd_t *, int, const char *, ...) BOZO_PRINTFLIKE(3, 4);
 #ifndef AUTH_FILE
 #define AUTH_FILE		".htpasswd"
 #endif
+#ifndef CUSTOMHEADERS_FILE
+#define CUSTOMHEADERS_FILE	".bzcustomheaders"
+#endif
 
 /* be sure to always return this error up */
 int	bozo_http_error(bozohttpd_t *, int, bozo_httpreq_t *, const char *);
diff --git a/tests/libexec/httpd/.bzcustomheaders b/tests/libexec/httpd/.bzcustomheaders
new file mode 100644
index 000000000000..3e2ca829597f
--- /dev/null
+++ b/tests/libexec/httpd/.bzcustomheaders
@@ -0,0 +1,2 @@
+Strict-Transport-Security: max-age=31536000
+Content-Security-Policy: default-src https:
diff --git a/tests/libexec/httpd/Makefile b/tests/libexec/httpd/Makefile
new file mode 100644
index 000000000000..936f616997c2
--- /dev/null
+++ b/tests/libexec/httpd/Makefile
@@ -0,0 +1,6 @@
+.include <bsd.own.mk>
+
+TESTSDIR=	${TESTSBASE}/libexec/httpd
+TESTS_SH=	t_custom_headers
+
+.include <bsd.test.mk>
diff --git a/tests/libexec/httpd/custom_headers.awk b/tests/libexec/httpd/custom_headers.awk
new file mode 100644
index 000000000000..a7e00cb1847b
--- /dev/null
+++ b/tests/libexec/httpd/custom_headers.awk
@@ -0,0 +1,51 @@
+# Copyright (c) 2024 The NetBSD Foundation, Inc.
+# All rights reserved.
+#
+# This code is derived from software contributed to The NetBSD Foundation
+# by Sunil Nimmagadda.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+BEGIN {
+    in_headers = 1
+    while (getline <".bzcustomheaders" > 0) {
+	custom_headers[$0] = 0
+    }
+}
+
+/^$/ { in_headers = 0 }
+
+{
+    if (in_headers && $0 in custom_headers) {
+	custom_headers[$0] += 1
+    }
+}
+
+END {
+    for (h in custom_headers) {
+	if (custom_headers[h] == 0) {
+	    printf("\'%s\' header not found\n", h)
+	    exit 1
+	}
+    }
+}
diff --git a/tests/libexec/httpd/index.html b/tests/libexec/httpd/index.html
new file mode 100644
index 000000000000..b0941bbd5809
--- /dev/null
+++ b/tests/libexec/httpd/index.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<html lang="en">
+<head><title>hello world!</title></head>
+</html>
diff --git a/tests/libexec/httpd/t_custom_headers.sh b/tests/libexec/httpd/t_custom_headers.sh
new file mode 100644
index 000000000000..666af720accc
--- /dev/null
+++ b/tests/libexec/httpd/t_custom_headers.sh
@@ -0,0 +1,62 @@
+# Copyright (c) 2024 The NetBSD Foundation, Inc.
+# All rights reserved.
+#
+# This code is derived from software contributed to The NetBSD Foundation
+# by Sunil Nimmagadda.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+atf_test_case custom_headers cleanup
+custom_headers_head()
+{
+	atf_set "descr" "Check for custom HTTP headers"
+}
+
+HTTPD_PID=./.__httpd.pid
+custom_headers_body()
+{
+	# start httpd in daemon mode
+	atf_check -s exit:0 \
+	    /usr/libexec/httpd -P $HTTPD_PID -I 8080 -b .
+
+	atf_check -s exit:0 \
+	    printf "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n" | \
+	    nc 127.0.0.1 8080 | \
+	    tr -d '\r' | \
+	    awk -f $(atf_get_srcdir)/custom_headers.awk
+}
+
+custom_headers_cleanup()
+{
+	if [ -f "$HTTPD_PID" ]; then
+		echo kill -9 "$(cat $HTTPD_PID)"
+		kill -9 "$(cat $HTTPD_PID)"
+		echo '# wait for httpd to exit'
+		sleep 1
+	fi
+}
+
+atf_init_test_cases()
+{
+	atf_add_test_case custom_headers
+}
-- 
2.47.0



Home | Main Index | Thread Index | Old Index