git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
From: "Matthew John Cheetham via GitGitGadget" <gitgitgadget@gmail.com>
To: git@vger.kernel.org
Cc: Derrick Stolee <derrickstolee@github.com>,
	Lessley Dennington <lessleydennington@gmail.com>,
	Matthew John Cheetham <mjcheetham@outlook.com>,
	M Hickford <mirth.hickford@gmail.com>,
	Jeff Hostetler <git@jeffhostetler.com>,
	Glen Choo <chooglen@google.com>,
	Matthew John Cheetham <mjcheetham@github.com>,
	Matthew John Cheetham <mjcheetham@outlook.com>
Subject: [PATCH v4 3/8] test-http-server: add stub HTTP server test helper
Date: Mon, 12 Dec 2022 21:36:18 +0000	[thread overview]
Message-ID: <07a1845ea5693fc8d3716e7f97e65d467f34a40e.1670880984.git.gitgitgadget@gmail.com> (raw)
In-Reply-To: <pull.1352.v4.git.1670880984.gitgitgadget@gmail.com>

From: Matthew John Cheetham <mjcheetham@outlook.com>

Introduce a mini HTTP server helper that in the future will be enhanced
to provide a frontend for the git-http-backend, with support for
arbitrary authentication schemes.

Right now, test-http-server is a pared-down copy of the git-daemon that
always returns a 501 Not Implemented response to all callers.

Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
---
 Makefile                            |   2 +
 contrib/buildsystems/CMakeLists.txt |  13 +
 t/helper/.gitignore                 |   1 +
 t/helper/test-http-server.c         | 685 ++++++++++++++++++++++++++++
 4 files changed, 701 insertions(+)
 create mode 100644 t/helper/test-http-server.c

diff --git a/Makefile b/Makefile
index b258fdbed86..1eb795bbfd4 100644
--- a/Makefile
+++ b/Makefile
@@ -1611,6 +1611,8 @@ else
 	endif
 	BASIC_CFLAGS += $(CURL_CFLAGS)
 
+	TEST_PROGRAMS_NEED_X += test-http-server
+
 	REMOTE_CURL_PRIMARY = git-remote-http$X
 	REMOTE_CURL_ALIASES = git-remote-https$X git-remote-ftp$X git-remote-ftps$X
 	REMOTE_CURL_NAMES = $(REMOTE_CURL_PRIMARY) $(REMOTE_CURL_ALIASES)
diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt
index 2f6e0197ffa..e9b9bfbb437 100644
--- a/contrib/buildsystems/CMakeLists.txt
+++ b/contrib/buildsystems/CMakeLists.txt
@@ -989,6 +989,19 @@ set(wrapper_scripts
 set(wrapper_test_scripts
 	test-fake-ssh test-tool)
 
+if(CURL_FOUND)
+       list(APPEND wrapper_test_scripts test-http-server)
+
+       add_executable(test-http-server ${CMAKE_SOURCE_DIR}/t/helper/test-http-server.c)
+       target_link_libraries(test-http-server common-main)
+
+       if(MSVC)
+               set_target_properties(test-http-server
+                                       PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}/t/helper)
+               set_target_properties(test-http-server
+                                       PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}/t/helper)
+       endif()
+endif()
 
 foreach(script ${wrapper_scripts})
 	file(STRINGS ${CMAKE_SOURCE_DIR}/wrap-for-bin.sh content NEWLINE_CONSUME)
diff --git a/t/helper/.gitignore b/t/helper/.gitignore
index 8c2ddcce95f..9aa9c752997 100644
--- a/t/helper/.gitignore
+++ b/t/helper/.gitignore
@@ -1,2 +1,3 @@
 /test-tool
 /test-fake-ssh
+/test-http-server
diff --git a/t/helper/test-http-server.c b/t/helper/test-http-server.c
new file mode 100644
index 00000000000..18f1f741305
--- /dev/null
+++ b/t/helper/test-http-server.c
@@ -0,0 +1,685 @@
+#include "config.h"
+#include "run-command.h"
+#include "strbuf.h"
+#include "string-list.h"
+#include "trace2.h"
+#include "version.h"
+#include "dir.h"
+#include "date.h"
+
+#define TR2_CAT "test-http-server"
+
+static const char *pid_file;
+static int verbose;
+static int reuseaddr;
+
+static const char test_http_auth_usage[] =
+"http-server [--verbose]\n"
+"           [--timeout=<n>] [--init-timeout=<n>] [--max-connections=<n>]\n"
+"           [--reuseaddr] [--pid-file=<file>]\n"
+"           [--listen=<host_or_ipaddr>]* [--port=<n>]\n"
+;
+
+/* Timeout, and initial timeout */
+static unsigned int timeout;
+static unsigned int init_timeout;
+
+static void logreport(const char *label, const char *err, va_list params)
+{
+	struct strbuf msg = STRBUF_INIT;
+
+	strbuf_addf(&msg, "[%"PRIuMAX"] %s: ", (uintmax_t)getpid(), label);
+	strbuf_vaddf(&msg, err, params);
+	strbuf_addch(&msg, '\n');
+
+	fwrite(msg.buf, sizeof(char), msg.len, stderr);
+	fflush(stderr);
+
+	strbuf_release(&msg);
+}
+
+__attribute__((format (printf, 1, 2)))
+static void logerror(const char *err, ...)
+{
+	va_list params;
+	va_start(params, err);
+	logreport("error", err, params);
+	va_end(params);
+}
+
+__attribute__((format (printf, 1, 2)))
+static void loginfo(const char *err, ...)
+{
+	va_list params;
+	if (!verbose)
+		return;
+	va_start(params, err);
+	logreport("info", err, params);
+	va_end(params);
+}
+
+static void set_keep_alive(int sockfd)
+{
+	int ka = 1;
+
+	if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &ka, sizeof(ka)) < 0) {
+		if (errno != ENOTSOCK)
+			logerror("unable to set SO_KEEPALIVE on socket: %s",
+				strerror(errno));
+	}
+}
+
+/*
+ * The code in this section is used by "worker" instances to service
+ * a single connection from a client.  The worker talks to the client
+ * on 0 and 1.
+ */
+
+enum worker_result {
+	/*
+	 * Operation successful.
+	 * Caller *might* keep the socket open and allow keep-alive.
+	 */
+	WR_OK       = 0,
+
+	/*
+	 * Various errors while processing the request and/or the response.
+	 * Close the socket and clean up.
+	 * Exit child-process with non-zero status.
+	 */
+	WR_IO_ERROR = 1<<0,
+
+	/*
+	 * Close the socket and clean up.  Does not imply an error.
+	 */
+	WR_HANGUP   = 1<<1,
+
+	WR_STOP_THE_MUSIC = (WR_IO_ERROR | WR_HANGUP),
+};
+
+static enum worker_result worker(void)
+{
+	const char *response = "HTTP/1.1 501 Not Implemented\r\n";
+	char *client_addr = getenv("REMOTE_ADDR");
+	char *client_port = getenv("REMOTE_PORT");
+	enum worker_result wr = WR_OK;
+
+	if (client_addr)
+		loginfo("Connection from %s:%s", client_addr, client_port);
+
+	set_keep_alive(0);
+
+	while (1) {
+		if (write_in_full(1, response, strlen(response)) < 0) {
+			logerror("unable to write response");
+			wr = WR_IO_ERROR;
+		}
+
+		if (wr & WR_STOP_THE_MUSIC)
+			break;
+	}
+
+	close(0);
+	close(1);
+
+	return !!(wr & WR_IO_ERROR);
+}
+
+/*
+ * This section contains the listener and child-process management
+ * code used by the primary instance to accept incoming connections
+ * and dispatch them to async child process "worker" instances.
+ */
+
+static int addrcmp(const struct sockaddr_storage *s1,
+		   const struct sockaddr_storage *s2)
+{
+	const struct sockaddr *sa1 = (const struct sockaddr*) s1;
+	const struct sockaddr *sa2 = (const struct sockaddr*) s2;
+
+	if (sa1->sa_family != sa2->sa_family)
+		return sa1->sa_family - sa2->sa_family;
+	if (sa1->sa_family == AF_INET)
+		return memcmp(&((struct sockaddr_in *)s1)->sin_addr,
+		    &((struct sockaddr_in *)s2)->sin_addr,
+		    sizeof(struct in_addr));
+#ifndef NO_IPV6
+	if (sa1->sa_family == AF_INET6)
+		return memcmp(&((struct sockaddr_in6 *)s1)->sin6_addr,
+		    &((struct sockaddr_in6 *)s2)->sin6_addr,
+		    sizeof(struct in6_addr));
+#endif
+	return 0;
+}
+
+static int max_connections = 32;
+
+static unsigned int live_children;
+
+static struct child {
+	struct child *next;
+	struct child_process cld;
+	struct sockaddr_storage address;
+} *firstborn;
+
+static void add_child(struct child_process *cld, struct sockaddr *addr, socklen_t addrlen)
+{
+	struct child *newborn, **cradle;
+
+	newborn = xcalloc(1, sizeof(*newborn));
+	live_children++;
+	memcpy(&newborn->cld, cld, sizeof(*cld));
+	memcpy(&newborn->address, addr, addrlen);
+	for (cradle = &firstborn; *cradle; cradle = &(*cradle)->next)
+		if (!addrcmp(&(*cradle)->address, &newborn->address))
+			break;
+	newborn->next = *cradle;
+	*cradle = newborn;
+}
+
+/*
+ * This gets called if the number of connections grows
+ * past "max_connections".
+ *
+ * We kill the newest connection from a duplicate IP.
+ */
+static void kill_some_child(void)
+{
+	const struct child *blanket, *next;
+
+	if (!(blanket = firstborn))
+		return;
+
+	for (; (next = blanket->next); blanket = next)
+		if (!addrcmp(&blanket->address, &next->address)) {
+			kill(blanket->cld.pid, SIGTERM);
+			break;
+		}
+}
+
+static void check_dead_children(void)
+{
+	int status;
+	pid_t pid;
+
+	struct child **cradle, *blanket;
+	for (cradle = &firstborn; (blanket = *cradle);)
+		if ((pid = waitpid(blanket->cld.pid, &status, WNOHANG)) > 1) {
+			const char *dead = "";
+			if (status)
+				dead = " (with error)";
+			loginfo("[%"PRIuMAX"] Disconnected%s", (uintmax_t)pid, dead);
+
+			/* remove the child */
+			*cradle = blanket->next;
+			live_children--;
+			child_process_clear(&blanket->cld);
+			free(blanket);
+		} else
+			cradle = &blanket->next;
+}
+
+static struct strvec cld_argv = STRVEC_INIT;
+static void handle(int incoming, struct sockaddr *addr, socklen_t addrlen)
+{
+	struct child_process cld = CHILD_PROCESS_INIT;
+
+	if (max_connections && live_children >= max_connections) {
+		kill_some_child();
+		sleep(1);  /* give it some time to die */
+		check_dead_children();
+		if (live_children >= max_connections) {
+			close(incoming);
+			logerror("Too many children, dropping connection");
+			return;
+		}
+	}
+
+	if (addr->sa_family == AF_INET) {
+		char buf[128] = "";
+		struct sockaddr_in *sin_addr = (void *) addr;
+		inet_ntop(addr->sa_family, &sin_addr->sin_addr, buf, sizeof(buf));
+		strvec_pushf(&cld.env, "REMOTE_ADDR=%s", buf);
+		strvec_pushf(&cld.env, "REMOTE_PORT=%d",
+				 ntohs(sin_addr->sin_port));
+#ifndef NO_IPV6
+	} else if (addr->sa_family == AF_INET6) {
+		char buf[128] = "";
+		struct sockaddr_in6 *sin6_addr = (void *) addr;
+		inet_ntop(AF_INET6, &sin6_addr->sin6_addr, buf, sizeof(buf));
+		strvec_pushf(&cld.env, "REMOTE_ADDR=[%s]", buf);
+		strvec_pushf(&cld.env, "REMOTE_PORT=%d",
+				 ntohs(sin6_addr->sin6_port));
+#endif
+	}
+
+	strvec_pushv(&cld.args, cld_argv.v);
+	cld.in = incoming;
+	cld.out = dup(incoming);
+
+	if (cld.out < 0)
+		logerror("could not dup() `incoming`");
+	else if (start_command(&cld))
+		logerror("unable to fork");
+	else
+		add_child(&cld, addr, addrlen);
+}
+
+static void child_handler(int signo)
+{
+	/*
+	 * Otherwise empty handler because systemcalls will get interrupted
+	 * upon signal receipt
+	 * SysV needs the handler to be rearmed
+	 */
+	signal(SIGCHLD, child_handler);
+}
+
+static int set_reuse_addr(int sockfd)
+{
+	int on = 1;
+
+	if (!reuseaddr)
+		return 0;
+	return setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
+			  &on, sizeof(on));
+}
+
+struct socketlist {
+	int *list;
+	size_t nr;
+	size_t alloc;
+};
+
+static const char *ip2str(int family, struct sockaddr *sin, socklen_t len)
+{
+#ifdef NO_IPV6
+	static char ip[INET_ADDRSTRLEN];
+#else
+	static char ip[INET6_ADDRSTRLEN];
+#endif
+
+	switch (family) {
+#ifndef NO_IPV6
+	case AF_INET6:
+		inet_ntop(family, &((struct sockaddr_in6*)sin)->sin6_addr, ip, len);
+		break;
+#endif
+	case AF_INET:
+		inet_ntop(family, &((struct sockaddr_in*)sin)->sin_addr, ip, len);
+		break;
+	default:
+		xsnprintf(ip, sizeof(ip), "<unknown>");
+	}
+	return ip;
+}
+
+#ifndef NO_IPV6
+
+static int setup_named_sock(char *listen_addr, int listen_port, struct socketlist *socklist)
+{
+	int socknum = 0;
+	char pbuf[NI_MAXSERV];
+	struct addrinfo hints, *ai0, *ai;
+	int gai;
+	long flags;
+
+	xsnprintf(pbuf, sizeof(pbuf), "%d", listen_port);
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_family = AF_UNSPEC;
+	hints.ai_socktype = SOCK_STREAM;
+	hints.ai_protocol = IPPROTO_TCP;
+	hints.ai_flags = AI_PASSIVE;
+
+	gai = getaddrinfo(listen_addr, pbuf, &hints, &ai0);
+	if (gai) {
+		logerror("getaddrinfo() for %s failed: %s", listen_addr, gai_strerror(gai));
+		return 0;
+	}
+
+	for (ai = ai0; ai; ai = ai->ai_next) {
+		int sockfd;
+
+		sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+		if (sockfd < 0)
+			continue;
+		if (sockfd >= FD_SETSIZE) {
+			logerror("Socket descriptor too large");
+			close(sockfd);
+			continue;
+		}
+
+#ifdef IPV6_V6ONLY
+		if (ai->ai_family == AF_INET6) {
+			int on = 1;
+			setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY,
+				   &on, sizeof(on));
+			/* Note: error is not fatal */
+		}
+#endif
+
+		if (set_reuse_addr(sockfd)) {
+			logerror("Could not set SO_REUSEADDR: %s", strerror(errno));
+			close(sockfd);
+			continue;
+		}
+
+		set_keep_alive(sockfd);
+
+		if (bind(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) {
+			logerror("Could not bind to %s: %s",
+				 ip2str(ai->ai_family, ai->ai_addr, ai->ai_addrlen),
+				 strerror(errno));
+			close(sockfd);
+			continue;	/* not fatal */
+		}
+		if (listen(sockfd, 5) < 0) {
+			logerror("Could not listen to %s: %s",
+				 ip2str(ai->ai_family, ai->ai_addr, ai->ai_addrlen),
+				 strerror(errno));
+			close(sockfd);
+			continue;	/* not fatal */
+		}
+
+		flags = fcntl(sockfd, F_GETFD, 0);
+		if (flags >= 0)
+			fcntl(sockfd, F_SETFD, flags | FD_CLOEXEC);
+
+		ALLOC_GROW(socklist->list, socklist->nr + 1, socklist->alloc);
+		socklist->list[socklist->nr++] = sockfd;
+		socknum++;
+	}
+
+	freeaddrinfo(ai0);
+
+	return socknum;
+}
+
+#else /* NO_IPV6 */
+
+static int setup_named_sock(char *listen_addr, int listen_port, struct socketlist *socklist)
+{
+	struct sockaddr_in sin;
+	int sockfd;
+	long flags;
+
+	memset(&sin, 0, sizeof sin);
+	sin.sin_family = AF_INET;
+	sin.sin_port = htons(listen_port);
+
+	if (listen_addr) {
+		/* Well, host better be an IP address here. */
+		if (inet_pton(AF_INET, listen_addr, &sin.sin_addr.s_addr) <= 0)
+			return 0;
+	} else {
+		sin.sin_addr.s_addr = htonl(INADDR_ANY);
+	}
+
+	sockfd = socket(AF_INET, SOCK_STREAM, 0);
+	if (sockfd < 0)
+		return 0;
+
+	if (set_reuse_addr(sockfd)) {
+		logerror("Could not set SO_REUSEADDR: %s", strerror(errno));
+		close(sockfd);
+		return 0;
+	}
+
+	set_keep_alive(sockfd);
+
+	if (bind(sockfd, (struct sockaddr *)&sin, sizeof sin) < 0) {
+		logerror("Could not bind to %s: %s",
+			 ip2str(AF_INET, (struct sockaddr *)&sin, sizeof(sin)),
+			 strerror(errno));
+		close(sockfd);
+		return 0;
+	}
+
+	if (listen(sockfd, 5) < 0) {
+		logerror("Could not listen to %s: %s",
+			 ip2str(AF_INET, (struct sockaddr *)&sin, sizeof(sin)),
+			 strerror(errno));
+		close(sockfd);
+		return 0;
+	}
+
+	flags = fcntl(sockfd, F_GETFD, 0);
+	if (flags >= 0)
+		fcntl(sockfd, F_SETFD, flags | FD_CLOEXEC);
+
+	ALLOC_GROW(socklist->list, socklist->nr + 1, socklist->alloc);
+	socklist->list[socklist->nr++] = sockfd;
+	return 1;
+}
+
+#endif
+
+static void socksetup(struct string_list *listen_addr, int listen_port, struct socketlist *socklist)
+{
+	if (!listen_addr->nr)
+		setup_named_sock("127.0.0.1", listen_port, socklist);
+	else {
+		int i, socknum;
+		for (i = 0; i < listen_addr->nr; i++) {
+			socknum = setup_named_sock(listen_addr->items[i].string,
+						   listen_port, socklist);
+
+			if (socknum == 0)
+				logerror("unable to allocate any listen sockets for host %s on port %u",
+					 listen_addr->items[i].string, listen_port);
+		}
+	}
+}
+
+static int service_loop(struct socketlist *socklist)
+{
+	struct pollfd *pfd;
+	int i;
+
+	CALLOC_ARRAY(pfd, socklist->nr);
+
+	for (i = 0; i < socklist->nr; i++) {
+		pfd[i].fd = socklist->list[i];
+		pfd[i].events = POLLIN;
+	}
+
+	signal(SIGCHLD, child_handler);
+
+	for (;;) {
+		int i;
+		int nr_ready;
+		int timeout = (pid_file ? 100 : -1);
+
+		check_dead_children();
+
+		nr_ready = poll(pfd, socklist->nr, timeout);
+		if (nr_ready < 0) {
+			if (errno != EINTR) {
+				logerror("Poll failed, resuming: %s",
+				      strerror(errno));
+				sleep(1);
+			}
+			continue;
+		}
+		else if (nr_ready == 0) {
+			/*
+			 * If we have a pid_file, then we watch it.
+			 * If someone deletes it, we shutdown the service.
+			 * The shell scripts in the test suite will use this.
+			 */
+			if (!pid_file || file_exists(pid_file))
+				continue;
+			goto shutdown;
+		}
+
+		for (i = 0; i < socklist->nr; i++) {
+			if (pfd[i].revents & POLLIN) {
+				union {
+					struct sockaddr sa;
+					struct sockaddr_in sai;
+#ifndef NO_IPV6
+					struct sockaddr_in6 sai6;
+#endif
+				} ss;
+				socklen_t sslen = sizeof(ss);
+				int incoming = accept(pfd[i].fd, &ss.sa, &sslen);
+				if (incoming < 0) {
+					switch (errno) {
+					case EAGAIN:
+					case EINTR:
+					case ECONNABORTED:
+						continue;
+					default:
+						die_errno("accept returned");
+					}
+				}
+				handle(incoming, &ss.sa, sslen);
+			}
+		}
+	}
+
+shutdown:
+	loginfo("Starting graceful shutdown (pid-file gone)");
+	for (i = 0; i < socklist->nr; i++)
+		close(socklist->list[i]);
+
+	return 0;
+}
+
+static int serve(struct string_list *listen_addr, int listen_port)
+{
+	struct socketlist socklist = { NULL, 0, 0 };
+
+	socksetup(listen_addr, listen_port, &socklist);
+	if (socklist.nr == 0)
+		die("unable to allocate any listen sockets on port %u",
+		    listen_port);
+
+	loginfo("Ready to rumble");
+
+	/*
+	 * Wait to create the pid-file until we've setup the sockets
+	 * and are open for business.
+	 */
+	if (pid_file)
+		write_file(pid_file, "%"PRIuMAX, (uintmax_t) getpid());
+
+	return service_loop(&socklist);
+}
+
+/*
+ * This section is executed by both the primary instance and all
+ * worker instances.  So, yes, each child-process re-parses the
+ * command line argument and re-discovers how it should behave.
+ */
+
+int cmd_main(int argc, const char **argv)
+{
+	int listen_port = 0;
+	struct string_list listen_addr = STRING_LIST_INIT_NODUP;
+	int worker_mode = 0;
+	int i;
+
+	trace2_cmd_name("test-http-server");
+	setup_git_directory_gently(NULL);
+
+	for (i = 1; i < argc; i++) {
+		const char *arg = argv[i];
+		const char *v;
+
+		if (skip_prefix(arg, "--listen=", &v)) {
+			string_list_append(&listen_addr, xstrdup_tolower(v));
+			continue;
+		}
+		if (skip_prefix(arg, "--port=", &v)) {
+			char *end;
+			unsigned long n;
+			n = strtoul(v, &end, 0);
+			if (*v && !*end) {
+				listen_port = n;
+				continue;
+			}
+		}
+		if (!strcmp(arg, "--worker")) {
+			worker_mode = 1;
+			trace2_cmd_mode("worker");
+			continue;
+		}
+		if (!strcmp(arg, "--verbose")) {
+			verbose = 1;
+			continue;
+		}
+		if (skip_prefix(arg, "--timeout=", &v)) {
+			timeout = atoi(v);
+			continue;
+		}
+		if (skip_prefix(arg, "--init-timeout=", &v)) {
+			init_timeout = atoi(v);
+			continue;
+		}
+		if (skip_prefix(arg, "--max-connections=", &v)) {
+			max_connections = atoi(v);
+			if (max_connections < 0)
+				max_connections = 0; /* unlimited */
+			continue;
+		}
+		if (!strcmp(arg, "--reuseaddr")) {
+			reuseaddr = 1;
+			continue;
+		}
+		if (skip_prefix(arg, "--pid-file=", &v)) {
+			pid_file = v;
+			continue;
+		}
+
+		fprintf(stderr, "error: unknown argument '%s'\n", arg);
+		usage(test_http_auth_usage);
+	}
+
+	/* avoid splitting a message in the middle */
+	setvbuf(stderr, NULL, _IOFBF, 4096);
+
+	if (listen_port == 0)
+		listen_port = DEFAULT_GIT_PORT;
+
+	/*
+	 * If no --listen=<addr> args are given, the setup_named_sock()
+	 * code will use receive a NULL address and set INADDR_ANY.
+	 * This exposes both internal and external interfaces on the
+	 * port.
+	 *
+	 * Disallow that and default to the internal-use-only loopback
+	 * address.
+	 */
+	if (!listen_addr.nr)
+		string_list_append(&listen_addr, "127.0.0.1");
+
+	/*
+	 * worker_mode is set in our own child process instances
+	 * (that are bound to a connected socket from a client).
+	 */
+	if (worker_mode)
+		return worker();
+
+	/*
+	 * `cld_argv` is a bit of a clever hack. The top-level instance
+	 * of test-http-server does the normal bind/listen/accept stuff.
+	 * For each incoming socket, the top-level process spawns
+	 * a child instance of test-http-server *WITH* the additional
+	 * `--worker` argument. This causes the child to set `worker_mode`
+	 * and immediately call `worker()` using the connected socket (and
+	 * without the usual need for fork() or threads).
+	 *
+	 * The magic here is made possible because `cld_argv` is static
+	 * and handle() (called by service_loop()) knows about it.
+	 */
+	strvec_push(&cld_argv, argv[0]);
+	strvec_push(&cld_argv, "--worker");
+	for (i = 1; i < argc; ++i)
+		strvec_push(&cld_argv, argv[i]);
+
+	/*
+	 * Setup primary instance to listen for connections.
+	 */
+	return serve(&listen_addr, listen_port);
+}
-- 
gitgitgadget


  parent reply	other threads:[~2022-12-12 21:37 UTC|newest]

Thread overview: 223+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-09-13 19:25 [PATCH 0/8] [RFC] Enhance credential helper protocol to include auth headers Matthew John Cheetham via GitGitGadget
2022-09-13 19:25 ` [PATCH 1/8] wincred: ignore unknown lines (do not die) Matthew John Cheetham via GitGitGadget
2022-09-13 19:25 ` [PATCH 2/8] netrc: " Matthew John Cheetham via GitGitGadget
2022-09-13 19:25 ` [PATCH 3/8] osxkeychain: clarify that we ignore unknown lines Matthew John Cheetham via GitGitGadget
2022-09-19 16:12   ` Derrick Stolee
2022-09-21 22:48     ` Matthew John Cheetham
2022-09-13 19:25 ` [PATCH 4/8] http: read HTTP WWW-Authenticate response headers Matthew John Cheetham via GitGitGadget
2022-09-19 16:21   ` Derrick Stolee
2022-09-21 22:24     ` Matthew John Cheetham
2022-09-26 14:13       ` Derrick Stolee
2022-09-13 19:25 ` [PATCH 5/8] credential: add WWW-Authenticate header to cred requests Matthew John Cheetham via GitGitGadget
2022-09-19 16:33   ` Derrick Stolee
2022-09-21 22:20     ` Matthew John Cheetham
2022-09-13 19:25 ` [PATCH 6/8] http: store all request headers on active_request_slot Matthew John Cheetham via GitGitGadget
2022-09-13 19:25 ` [PATCH 7/8] http: move proactive auth to first slot creation Matthew John Cheetham via GitGitGadget
2022-09-13 19:25 ` [PATCH 8/8] http: set specific auth scheme depending on credential Matthew John Cheetham via GitGitGadget
2022-09-19 16:42   ` Derrick Stolee
2022-09-19 16:08 ` [PATCH 0/8] [RFC] Enhance credential helper protocol to include auth headers Derrick Stolee
2022-09-19 16:44   ` Derrick Stolee
2022-09-21 22:19   ` Matthew John Cheetham
2022-09-19 23:36 ` Lessley Dennington
2022-10-21 17:07 ` [PATCH v2 0/6] " Matthew John Cheetham via GitGitGadget
2022-10-21 17:07   ` [PATCH v2 1/6] http: read HTTP WWW-Authenticate response headers Matthew John Cheetham via GitGitGadget
2022-10-21 17:07   ` [PATCH v2 2/6] credential: add WWW-Authenticate header to cred requests Matthew John Cheetham via GitGitGadget
2022-10-28 18:22     ` Jeff Hostetler
2022-11-01 23:07       ` Matthew John Cheetham
2022-10-21 17:08   ` [PATCH v2 3/6] http: store all request headers on active_request_slot Matthew John Cheetham via GitGitGadget
2022-10-21 17:08   ` [PATCH v2 4/6] http: move proactive auth to first slot creation Matthew John Cheetham via GitGitGadget
2022-10-21 17:08   ` [PATCH v2 5/6] http: set specific auth scheme depending on credential Matthew John Cheetham via GitGitGadget
2022-10-21 17:08   ` [PATCH v2 6/6] t5556-http-auth: add test for HTTP auth hdr logic Matthew John Cheetham via GitGitGadget
2022-10-28 15:08     ` Derrick Stolee
2022-10-28 19:14       ` Jeff Hostetler
2022-11-01 23:14         ` Matthew John Cheetham
2022-11-02 14:38           ` Derrick Stolee
2022-11-01 23:59       ` Matthew John Cheetham
2022-10-25  2:26   ` git-credential.txt M Hickford
2022-10-25 20:49     ` git-credential.txt Matthew John Cheetham
2022-11-02 22:09   ` [PATCH v3 00/11] Enhance credential helper protocol to include auth headers Matthew John Cheetham via GitGitGadget
2022-11-02 22:09     ` [PATCH v3 01/11] http: read HTTP WWW-Authenticate response headers Matthew John Cheetham via GitGitGadget
2022-11-02 22:09     ` [PATCH v3 02/11] credential: add WWW-Authenticate header to cred requests Matthew John Cheetham via GitGitGadget
2022-11-02 22:09     ` [PATCH v3 03/11] http: store all request headers on active_request_slot Matthew John Cheetham via GitGitGadget
2022-11-09 23:18       ` Glen Choo
2022-11-02 22:09     ` [PATCH v3 04/11] http: move proactive auth to first slot creation Matthew John Cheetham via GitGitGadget
2022-11-02 22:09     ` [PATCH v3 05/11] http: set specific auth scheme depending on credential Matthew John Cheetham via GitGitGadget
2022-11-09 23:40       ` Glen Choo
2022-12-12 21:53         ` Matthew John Cheetham
2022-11-02 22:09     ` [PATCH v3 06/11] test-http-server: add stub HTTP server test helper Matthew John Cheetham via GitGitGadget
2022-11-07 19:19       ` Derrick Stolee
2022-11-02 22:09     ` [PATCH v3 07/11] test-http-server: add HTTP error response function Matthew John Cheetham via GitGitGadget
2022-11-02 22:09     ` [PATCH v3 08/11] test-http-server: add HTTP request parsing Matthew John Cheetham via GitGitGadget
2022-11-02 22:09     ` [PATCH v3 09/11] test-http-server: pass Git requests to http-backend Matthew John Cheetham via GitGitGadget
2022-11-02 22:09     ` [PATCH v3 10/11] test-http-server: add simple authentication Matthew John Cheetham via GitGitGadget
2022-11-02 22:09     ` [PATCH v3 11/11] t5556: add HTTP authentication tests Matthew John Cheetham via GitGitGadget
2022-11-03 19:00     ` [PATCH v3 00/11] Enhance credential helper protocol to include auth headers M Hickford
2022-12-12 22:07       ` Matthew John Cheetham
2022-11-07 19:23     ` Derrick Stolee
2022-11-09 23:06     ` Glen Choo
2022-12-12 22:03       ` Matthew John Cheetham
2022-11-28  9:40     ` Junio C Hamano
2022-12-12 21:36     ` [PATCH v4 0/8] " Matthew John Cheetham via GitGitGadget
2022-12-12 21:36       ` [PATCH v4 1/8] http: read HTTP WWW-Authenticate response headers Matthew John Cheetham via GitGitGadget
2022-12-14 23:15         ` Victoria Dye
2023-01-11 22:09           ` Matthew John Cheetham
2022-12-15  9:27         ` Ævar Arnfjörð Bjarmason
2023-01-11 22:11           ` Matthew John Cheetham
2022-12-12 21:36       ` [PATCH v4 2/8] credential: add WWW-Authenticate header to cred requests Matthew John Cheetham via GitGitGadget
2022-12-14 23:15         ` Victoria Dye
2023-01-11 20:37           ` Matthew John Cheetham
2022-12-12 21:36       ` Matthew John Cheetham via GitGitGadget [this message]
2022-12-14 23:16         ` [PATCH v4 3/8] test-http-server: add stub HTTP server test helper Victoria Dye
2023-01-11 20:46           ` Matthew John Cheetham
2022-12-12 21:36       ` [PATCH v4 4/8] test-http-server: add HTTP error response function Matthew John Cheetham via GitGitGadget
2022-12-14 23:17         ` Victoria Dye
2022-12-12 21:36       ` [PATCH v4 5/8] test-http-server: add HTTP request parsing Matthew John Cheetham via GitGitGadget
2022-12-14 23:18         ` Victoria Dye
2023-01-11 21:39           ` Matthew John Cheetham
2022-12-12 21:36       ` [PATCH v4 6/8] test-http-server: pass Git requests to http-backend Matthew John Cheetham via GitGitGadget
2022-12-14 23:20         ` Victoria Dye
2023-01-11 21:45           ` Matthew John Cheetham
2023-01-12 20:54             ` Victoria Dye
2022-12-12 21:36       ` [PATCH v4 7/8] test-http-server: add simple authentication Matthew John Cheetham via GitGitGadget
2022-12-14 23:23         ` Victoria Dye
2023-01-11 22:00           ` Matthew John Cheetham
2022-12-12 21:36       ` [PATCH v4 8/8] t5556: add HTTP authentication tests Matthew John Cheetham via GitGitGadget
2022-12-14 23:48         ` Victoria Dye
2022-12-15  0:21           ` Junio C Hamano
2023-01-11 22:05             ` Matthew John Cheetham
2023-01-11 22:04           ` Matthew John Cheetham
2023-01-11 22:13       ` [PATCH v5 00/10] Enhance credential helper protocol to include auth headers Matthew John Cheetham via GitGitGadget
2023-01-11 22:13         ` [PATCH v5 01/10] daemon: libify socket setup and option functions Matthew John Cheetham via GitGitGadget
2023-01-12 19:35           ` Victoria Dye
2023-01-12 20:22             ` Derrick Stolee
2023-01-11 22:13         ` [PATCH v5 02/10] daemon: libify child process handling functions Matthew John Cheetham via GitGitGadget
2023-01-12 19:35           ` Victoria Dye
2023-01-17 21:14             ` Matthew John Cheetham
2023-01-11 22:13         ` [PATCH v5 03/10] daemon: rename some esoteric/laboured terminology Matthew John Cheetham via GitGitGadget
2023-01-12 19:44           ` Victoria Dye
2023-01-17 21:16             ` Matthew John Cheetham
2023-01-11 22:13         ` [PATCH v5 04/10] test-http-server: add stub HTTP server test helper Matthew John Cheetham via GitGitGadget
2023-01-12 19:57           ` Victoria Dye
2023-01-11 22:13         ` [PATCH v5 05/10] test-http-server: add HTTP error response function Matthew John Cheetham via GitGitGadget
2023-01-12 20:35           ` Victoria Dye
2023-01-17 21:23             ` Matthew John Cheetham
2023-01-11 22:13         ` [PATCH v5 06/10] test-http-server: add simple authentication Matthew John Cheetham via GitGitGadget
2023-01-13 18:10           ` Victoria Dye
2023-01-13 21:06             ` Junio C Hamano
2023-01-17 21:21             ` Matthew John Cheetham
2023-01-11 22:13         ` [PATCH v5 07/10] http: replace unsafe size_t multiplication with st_mult Matthew John Cheetham via GitGitGadget
2023-01-11 22:13         ` [PATCH v5 08/10] strvec: expose strvec_push_nodup for external use Matthew John Cheetham via GitGitGadget
2023-01-11 22:13         ` [PATCH v5 09/10] http: read HTTP WWW-Authenticate response headers Matthew John Cheetham via GitGitGadget
2023-01-12  8:41           ` Ævar Arnfjörð Bjarmason
2023-01-17 21:51             ` Matthew John Cheetham
2023-01-11 22:13         ` [PATCH v5 10/10] credential: add WWW-Authenticate header to cred requests Matthew John Cheetham via GitGitGadget
2023-01-12  8:48           ` Ævar Arnfjörð Bjarmason
2023-01-17 21:35             ` Matthew John Cheetham
2023-01-12 20:41           ` Derrick Stolee
2023-01-17 21:18             ` Matthew John Cheetham
2023-01-18  3:30         ` [PATCH v6 00/12] Enhance credential helper protocol to include auth headers Matthew John Cheetham via GitGitGadget
2023-01-18  3:30           ` [PATCH v6 01/12] daemon: libify socket setup and option functions Matthew John Cheetham via GitGitGadget
2023-01-18  3:30           ` [PATCH v6 02/12] daemon: libify child process handling functions Matthew John Cheetham via GitGitGadget
2023-01-18  3:30           ` [PATCH v6 03/12] daemon: rename some esoteric/laboured terminology Matthew John Cheetham via GitGitGadget
2023-01-18  3:30           ` [PATCH v6 04/12] test-http-server: add stub HTTP server test helper Matthew John Cheetham via GitGitGadget
2023-01-18 11:04             ` Ævar Arnfjörð Bjarmason
2023-01-20 22:05               ` Matthew John Cheetham
2023-01-18  3:30           ` [PATCH v6 05/12] test-http-server: add HTTP error response function Matthew John Cheetham via GitGitGadget
2023-01-18 11:07             ` Ævar Arnfjörð Bjarmason
2023-01-20 22:05               ` Matthew John Cheetham
2023-01-18  3:30           ` [PATCH v6 06/12] test-http-server: add HTTP request parsing Matthew John Cheetham via GitGitGadget
2023-01-18 11:14             ` Ævar Arnfjörð Bjarmason
2023-01-20 22:05               ` Matthew John Cheetham
2023-01-18  3:30           ` [PATCH v6 07/12] test-http-server: pass Git requests to http-backend Matthew John Cheetham via GitGitGadget
2023-01-18  3:30           ` [PATCH v6 08/12] test-http-server: add simple authentication Matthew John Cheetham via GitGitGadget
2023-01-18 11:21             ` Ævar Arnfjörð Bjarmason
2023-01-20 22:05               ` Matthew John Cheetham
2023-01-18  3:30           ` [PATCH v6 09/12] test-http-server: add sending of arbitrary headers Matthew John Cheetham via GitGitGadget
2023-01-18  3:30           ` [PATCH v6 10/12] http: replace unsafe size_t multiplication with st_mult Matthew John Cheetham via GitGitGadget
2023-01-18 11:38             ` Ævar Arnfjörð Bjarmason
2023-01-18 17:28               ` Victoria Dye
2023-01-18 23:16                 ` Ævar Arnfjörð Bjarmason
2023-01-18  3:30           ` [PATCH v6 11/12] http: read HTTP WWW-Authenticate response headers Matthew John Cheetham via GitGitGadget
2023-01-18 11:42             ` Ævar Arnfjörð Bjarmason
2023-01-20 22:05               ` Matthew John Cheetham
2023-01-18  3:30           ` [PATCH v6 12/12] credential: add WWW-Authenticate header to cred requests Matthew John Cheetham via GitGitGadget
2023-01-20 22:08           ` [PATCH v7 00/12] Enhance credential helper protocol to include auth headers Matthew John Cheetham via GitGitGadget
2023-01-20 22:08             ` [PATCH v7 01/12] daemon: libify socket setup and option functions Matthew John Cheetham via GitGitGadget
2023-01-20 22:08             ` [PATCH v7 02/12] daemon: libify child process handling functions Matthew John Cheetham via GitGitGadget
2023-01-20 22:08             ` [PATCH v7 03/12] daemon: rename some esoteric/laboured terminology Matthew John Cheetham via GitGitGadget
2023-01-20 22:08             ` [PATCH v7 04/12] test-http-server: add stub HTTP server test helper Matthew John Cheetham via GitGitGadget
2023-01-26  8:58               ` Jeff King
2023-01-20 22:08             ` [PATCH v7 05/12] test-http-server: add HTTP error response function Matthew John Cheetham via GitGitGadget
2023-01-20 22:08             ` [PATCH v7 06/12] test-http-server: add HTTP request parsing Matthew John Cheetham via GitGitGadget
2023-01-26  9:30               ` Jeff King
2023-01-20 22:08             ` [PATCH v7 07/12] test-http-server: pass Git requests to http-backend Matthew John Cheetham via GitGitGadget
2023-01-26  9:37               ` Jeff King
2023-01-20 22:08             ` [PATCH v7 08/12] test-http-server: add simple authentication Matthew John Cheetham via GitGitGadget
2023-01-26 10:02               ` Jeff King
2023-01-26 21:22                 ` Jeff King
2023-01-26 22:27                   ` Junio C Hamano
2023-01-26 20:33               ` Jeff King
2023-01-20 22:08             ` [PATCH v7 09/12] test-http-server: add sending of arbitrary headers Matthew John Cheetham via GitGitGadget
2023-01-20 22:08             ` [PATCH v7 10/12] http: replace unsafe size_t multiplication with st_mult Matthew John Cheetham via GitGitGadget
2023-01-26 10:09               ` Jeff King
2023-01-20 22:08             ` [PATCH v7 11/12] http: read HTTP WWW-Authenticate response headers Matthew John Cheetham via GitGitGadget
2023-01-26 10:31               ` Jeff King
2023-02-06 19:25                 ` Matthew John Cheetham
2023-02-09 13:12                   ` Jeff King
2023-01-20 22:08             ` [PATCH v7 12/12] credential: add WWW-Authenticate header to cred requests Matthew John Cheetham via GitGitGadget
2023-01-26 11:25               ` Jeff King
2023-02-06 19:18                 ` Matthew John Cheetham
2023-02-09 13:08                   ` Jeff King
2023-01-24 17:30             ` [PATCH v7 00/12] Enhance credential helper protocol to include auth headers Victoria Dye
2023-01-24 18:03               ` Junio C Hamano
2023-01-26 11:29                 ` Jeff King
2023-01-26 16:05                   ` Junio C Hamano
2023-02-02 10:14                     ` Johannes Schindelin
2023-02-02 11:04                       ` Ævar Arnfjörð Bjarmason
2023-02-02 13:51                         ` Johannes Schindelin
2023-02-06 21:32                           ` Ævar Arnfjörð Bjarmason
2023-03-27  9:05                             ` Johannes Schindelin
2023-02-03 17:34                       ` Jeff King
2023-03-27  9:10                         ` Johannes Schindelin
2023-03-28 18:55                           ` Jeff King
2023-01-28 14:28             ` M Hickford
2023-02-01 20:15               ` Matthew John Cheetham
2023-02-02  0:16                 ` Jeff King
2023-02-06 19:29             ` [PATCH v8 0/3] " Matthew John Cheetham via GitGitGadget
2023-02-06 19:29               ` [PATCH v8 1/3] t5563: add tests for basic and anoymous HTTP access Matthew John Cheetham via GitGitGadget
2023-02-06 20:32                 ` Ævar Arnfjörð Bjarmason
2023-02-08 20:24                 ` Victoria Dye
2023-02-09 11:19                   ` Ævar Arnfjörð Bjarmason
2023-02-15 19:32                     ` Matthew John Cheetham
2023-02-06 19:29               ` [PATCH v8 2/3] http: read HTTP WWW-Authenticate response headers Matthew John Cheetham via GitGitGadget
2023-02-06 20:36                 ` Ævar Arnfjörð Bjarmason
2023-02-08 21:05                 ` Victoria Dye
2023-02-06 19:29               ` [PATCH v8 3/3] credential: add WWW-Authenticate header to cred requests Matthew John Cheetham via GitGitGadget
2023-02-06 20:45                 ` Ævar Arnfjörð Bjarmason
2023-02-15 19:19                   ` Matthew John Cheetham
2023-02-06 20:59               ` [PATCH v8 0/3] Enhance credential helper protocol to include auth headers Ævar Arnfjörð Bjarmason
2023-02-08 21:29               ` Victoria Dye
2023-02-08 21:54               ` Junio C Hamano
2023-02-15 21:34               ` [PATCH v9 " Matthew John Cheetham via GitGitGadget
2023-02-15 21:34                 ` [PATCH v9 1/3] t5563: add tests for basic and anoymous HTTP access Matthew John Cheetham via GitGitGadget
2023-02-15 22:15                   ` Junio C Hamano
2023-02-16 22:25                     ` Matthew John Cheetham
2023-02-15 21:34                 ` [PATCH v9 2/3] http: read HTTP WWW-Authenticate response headers Matthew John Cheetham via GitGitGadget
2023-02-15 23:26                   ` Junio C Hamano
2023-02-16 22:29                     ` Matthew John Cheetham
2023-02-15 21:34                 ` [PATCH v9 3/3] credential: add WWW-Authenticate header to cred requests Matthew John Cheetham via GitGitGadget
2023-02-16 22:34                 ` [PATCH v10 0/3] Enhance credential helper protocol to include auth headers Matthew John Cheetham via GitGitGadget
2023-02-16 22:34                   ` [PATCH v10 1/3] t5563: add tests for basic and anoymous HTTP access Matthew John Cheetham via GitGitGadget
2023-02-23  9:16                     ` Jeff King
2023-02-23  9:37                       ` Jeff King
2023-02-27 17:18                       ` Matthew John Cheetham
2023-02-16 22:34                   ` [PATCH v10 2/3] http: read HTTP WWW-Authenticate response headers Matthew John Cheetham via GitGitGadget
2023-02-23  9:46                     ` Jeff King
2023-02-23 19:49                       ` Junio C Hamano
2023-02-27 17:14                         ` Matthew John Cheetham
2023-02-16 22:34                   ` [PATCH v10 3/3] credential: add WWW-Authenticate header to cred requests Matthew John Cheetham via GitGitGadget
2023-02-27 17:20                   ` [PATCH v11 0/3] Enhance credential helper protocol to include auth headers Matthew John Cheetham via GitGitGadget
2023-02-27 17:20                     ` [PATCH v11 1/3] t5563: add tests for basic and anoymous HTTP access Matthew John Cheetham via GitGitGadget
2023-02-27 17:20                     ` [PATCH v11 2/3] http: read HTTP WWW-Authenticate response headers Matthew John Cheetham via GitGitGadget
2023-02-27 17:20                     ` [PATCH v11 3/3] credential: add WWW-Authenticate header to cred requests Matthew John Cheetham via GitGitGadget
2023-02-27 20:27                     ` [PATCH v11 0/3] Enhance credential helper protocol to include auth headers Jeff King

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: http://vger.kernel.org/majordomo-info.html

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=07a1845ea5693fc8d3716e7f97e65d467f34a40e.1670880984.git.gitgitgadget@gmail.com \
    --to=gitgitgadget@gmail.com \
    --cc=chooglen@google.com \
    --cc=derrickstolee@github.com \
    --cc=git@jeffhostetler.com \
    --cc=git@vger.kernel.org \
    --cc=lessleydennington@gmail.com \
    --cc=mirth.hickford@gmail.com \
    --cc=mjcheetham@github.com \
    --cc=mjcheetham@outlook.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).