Commit Diff


commit - 0d047efcb40ec311da407e0b705a92f764c96338
commit + f48e3b85a97ab6dbf808559c2231d0ab6344ba66
blob - 4d7c6250a5962aa691682a24e88a796da0278bd1
blob + df68f5fe15728c02a7547eefaa8923a40092d37f
--- .gitignore
+++ .gitignore
@@ -25,3 +25,4 @@ regress/fill-file
 regress/iri_test
 regress/puny-test
 regress/*.o
+regress/gg
blob - 521c5b2b4b0603cebeffbf3e66f11a72e61a93ce
blob + 5f91bd7d1cc61800f8d3f469a0d004975abecb3e
--- Makefile
+++ Makefile
@@ -20,9 +20,6 @@ OBJS = ${SRCS:.c=.o} lex.yy.o y.tab.o ${COMPAT}
 gmid: ${OBJS}
 	${CC} ${OBJS} -o gmid ${LDFLAGS}
 
-gg: gg.o iri.o utf8.o ${COMPAT}
-	${CC} gg.o iri.o utf8.o ${COMPAT} -o $@ ${LDFLAGS}
-
 static: ${OBJS}
 	${CC} ${OBJS} -o gmid ${LDFLAGS} ${STATIC}
 
@@ -30,11 +27,11 @@ TAGS: ${SRCS}
 	@(etags ${SRCS} || true) 2>/dev/null
 
 clean:
-	rm -f *.o compat/*.o lex.yy.c y.tab.c y.tab.h y.output gmid gg
+	rm -f *.o compat/*.o lex.yy.c y.tab.c y.tab.h y.output gmid
 	rm -f compile_flags.txt
 	make -C regress clean
 
-regress: gmid gg
+regress: gmid
 	make -C regress all
 
 install: gmid
blob - ad47822a9b871beab8e34e4ad26466b12203fa71 (mode 644)
blob + /dev/null
--- gg.1
+++ /dev/null
@@ -1,70 +0,0 @@
-.\" Copyright (c) 2021 Omar Polo <op@omarpolo.com>
-.\"
-.\" Permission to use, copy, modify, and distribute this software for any
-.\" purpose with or without fee is hereby granted, provided that the above
-.\" copyright notice and this permission notice appear in all copies.
-.\"
-.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-.Dd $Mdocdate: January 23 2021$
-.Dt GG 1
-.Os
-.Sh NAME
-.Nm gg
-.Nd simple Gemini client
-.Sh SYNOPSIS
-.Nm
-.Bk -words
-.Op Fl 23bchNVv
-.Op Fl C Pa cert.pem Fl K Pa key.pem
-.Op Fl H Ar hostname
-.Ar IRI
-.Ek
-.Sh DESCRIPTION
-.Nm
-is a simple Gemini client.
-It fetches the Gemini page given and prints the server response to
-standard output.
-The option are as follows:
-.Bl -tag -width 6m
-.It Fl 2
-Use only TLSv1.2.
-.It Fl 3
-Use only TLSv1.3.
-.It Fl b
-Print only the body of the response.
-.It Fl C Pa cert.pem
-Load the client certificate, must be in PEM format.
-.It Fl c
-Print only the response code.
-.It Fl H Ar hostname
-Use the given
-.Ar hostname
-for SNI, instead of the one extracted from the IRI.
-The IRI hostname will still be used for the DNS resolution.
-.It Fl h
-Print only the response header.
-.It Fl K Pa key.pem
-Load the client certificate key, must be in PEM format.
-.It Fl N
-Don't check whether the peer certificate name matches the requested
-hostname.
-.It Fl V
-Only validate the IRI, don't do the Gemini transaction.
-.It Fl v
-Print also the request.
-.El
-.Pp
-Note that
-.Nm
-won't try to do TOFU (Trust On First Use) or any X.509 certificate
-validation: it will happily accept any certificate it is given.
-.Pp
-By default
-.Nm
-will accept both TLSv1.2 and TLSv1.3 and will always do SNI.
blob - 8a1e7eb445d39a1bc140c48d929f6d0415e3f0c2 (mode 644)
blob + /dev/null
--- gg.c
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Copyright (c) 2021 Omar Polo <op@omarpolo.com>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "gmid.h"
-
-#include <string.h>
-
-int flag2, flag3, bflag, cflag, hflag, Nflag, Vflag, vflag;
-const char *cert, *key;
-
-int
-main(int argc, char **argv)
-{
-	struct iri iri;
-	struct tls_config *conf;
-	struct tls *ctx;
-	char iribuf[GEMINI_URL_LEN], buf[GEMINI_URL_LEN];
-	const char *parse_err = "unknown error", *port = "1965";
-	const char *hostname;
-	char *t;
-	int ch;
-	int handshake;
-	ssize_t len;
-
-	hostname = NULL;
-	while ((ch = getopt(argc, argv, "23C:cbH:hK:NVv")) != -1) {
-		switch (ch) {
-		case '2':
-			flag2 = 1;
-			break;
-		case '3':
-			flag3 = 1;
-			break;
-		case 'b':
-			bflag = 1;
-			break;
-		case 'C':
-			cert = optarg;
-			break;
-		case 'c':
-			cflag = 1;
-			break;
-		case 'H':
-			hostname = optarg;
-			break;
-		case 'h':
-			hflag = 1;
-			break;
-		case 'K':
-			key = optarg;
-			break;
-		case 'N':
-			Nflag = 1;
-			break;
-		case 'V':
-			Vflag = 1;
-			break;
-		case 'v':
-			vflag = 1;
-			break;
-		default:
-			fprintf(stderr, "USAGE: %s [-23cbhNVv] [-H hostname]\n",
-			    *argv);
-			return 1;
-		}
-	}
-	argc -= optind;
-	argv += optind;
-
-	if ((bflag + cflag + hflag + Vflag) > 1)
-		errx(1, "only one of bchr flags can be used.");
-
-	if (flag2 + flag3 > 1)
-		errx(1, "only -2 or -3 can be specified at the same time.");
-
-	if ((cert != NULL && key == NULL) || (cert == NULL && key != NULL))
-		errx(1, "missing certificate or key");
-
-	if (argc != 1)
-		errx(1, "missing IRI");
-
-	if (strlcpy(iribuf, argv[0], sizeof(iribuf)) >= sizeof(iribuf))
-		errx(1, "request too long: %s", argv[0]);
-	if (strlcpy(buf, argv[0], sizeof(buf)) >= sizeof(iribuf))
-		errx(1, "request too long: %s", argv[0]);
-	if (strlcat(buf, "\r\n", sizeof(buf)) >= sizeof(buf))
-		errx(1, "request too long: %s", argv[0]);
-
-	if (!parse_iri(iribuf, &iri, &parse_err))
-		errx(1, "invalid IRI: %s", parse_err);
-
-	if (Vflag)
-		errx(0, "IRI: OK");
-
-	if ((conf = tls_config_new()) == NULL)
-		errx(1, "tls_config_new");
-
-	tls_config_insecure_noverifycert(conf);
-	if (Nflag)
-		tls_config_insecure_noverifyname(conf);
-
-	if (flag2 && tls_config_set_protocols(conf, TLS_PROTOCOL_TLSv1_2) == -1)
-		errx(1, "cannot set TLSv1.2");
-	if (flag3 && tls_config_set_protocols(conf, TLS_PROTOCOL_TLSv1_3) == -1)
-		errx(1, "cannot set TLSv1.3");
-
-	if (cert != NULL && tls_config_set_keypair_file(conf, cert, key))
-		errx(1, "couldn't load cert: %s", cert);
-
-	if ((ctx = tls_client()) == NULL)
-		errx(1, "tls_client creation failed");
-
-	if (tls_configure(ctx, conf) == -1)
-		errx(1, "tls_configure: %s", tls_error(ctx));
-
-	if (*iri.port != '\0')
-		port = iri.port;
-
-	if (hostname == NULL)
-		hostname = iri.host;
-
-	if (tls_connect_servername(ctx, iri.host, port, hostname) == -1)
-		errx(1, "tls_connect: %s", tls_error(ctx));
-
-	for (handshake = 0; !handshake;) {
-		switch (tls_handshake(ctx)) {
-		case 0:
-		case -1:
-			handshake = 1;
-			break;
-		}
-	}
-
-	if (vflag)
-		printf("%s", buf);
-	if (tls_write(ctx, buf, strlen(buf)) == -1)
-		errx(1, "tls_write: %s", tls_error(ctx));
-
-	for (;;) {
-		switch (len = tls_read(ctx, buf, sizeof(buf))) {
-		case 0:
-		case -1:
-			goto end;
-		case TLS_WANT_POLLIN:
-		case TLS_WANT_POLLOUT:
-			continue;
-		}
-
-		if (bflag) {
-			bflag = 0;
-			if ((t = strchr(buf, '\r')) != NULL)
-				t += 2;
-			else if ((t = strchr(buf, '\n')) != NULL)
-				t += 1;
-			else
-				continue;
-			len -= t - buf;
-			write(1, t, len);
-			continue;
-		}
-
-		if (cflag) {
-			write(1, buf, 2);
-			write(1, "\n", 1);
-			break;
-		}
-
-		if (hflag) {
-			t = strchr(buf, '\r');
-			if (t == NULL)
-				t = strchr(buf, '\n');
-			if (t == NULL)
-				t = &buf[len];
-                        write(1, buf, t - buf);
-			write(1, "\n", 1);
-			break;
-		}
-
-		write(1, buf, len);
-	}
-end:
-
-	tls_close(ctx);
-	tls_free(ctx);
-
-	return 0;
-}
blob - b485d6498603cf02baede84cf3178ae0c7b112af
blob + 4f416d36626c56cd952559923fe8d658465648ce
--- regress/Makefile
+++ regress/Makefile
@@ -2,11 +2,14 @@ include ../Makefile.local
 
 .PHONY: all clean runtime
 
-all: puny-test testdata iri_test cert.pem testca.pem valid.crt invalid.cert.pem
+all: gg puny-test testdata iri_test cert.pem testca.pem valid.crt invalid.cert.pem
 	./puny-test
 	./runtime
 	./iri_test
 
+gg: gg.o ../iri.o ../utf8.o ${COMPAT}
+	${CC} gg.o ../iri.o ../utf8.o ${COMPAT} -o $@ ${LDFLAGS}
+
 puny-test: puny-test.o ../puny.o ../utf8.o ../utils.o ../log.o ${COMPAT}
 	${CC} puny-test.o ../puny.o ../utf8.o ../utils.o ../log.o ${COMPAT} \
 		-o puny-test ${LDFLAGS}
@@ -59,7 +62,7 @@ invalid.cert.pem: cert.pem
 clean:
 	rm -f *.o iri_test cert.pem key.pem
 	rm -f testca.* valid.csr valid.key invalid.*pem
-	rm -rf testdata fill-file puny-test
+	rm -rf testdata fill-file puny-test gg
 
 testdata: fill-file
 	mkdir testdata
blob - /dev/null
blob + ad47822a9b871beab8e34e4ad26466b12203fa71 (mode 644)
--- /dev/null
+++ regress/gg.1
@@ -0,0 +1,70 @@
+.\" Copyright (c) 2021 Omar Polo <op@omarpolo.com>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.Dd $Mdocdate: January 23 2021$
+.Dt GG 1
+.Os
+.Sh NAME
+.Nm gg
+.Nd simple Gemini client
+.Sh SYNOPSIS
+.Nm
+.Bk -words
+.Op Fl 23bchNVv
+.Op Fl C Pa cert.pem Fl K Pa key.pem
+.Op Fl H Ar hostname
+.Ar IRI
+.Ek
+.Sh DESCRIPTION
+.Nm
+is a simple Gemini client.
+It fetches the Gemini page given and prints the server response to
+standard output.
+The option are as follows:
+.Bl -tag -width 6m
+.It Fl 2
+Use only TLSv1.2.
+.It Fl 3
+Use only TLSv1.3.
+.It Fl b
+Print only the body of the response.
+.It Fl C Pa cert.pem
+Load the client certificate, must be in PEM format.
+.It Fl c
+Print only the response code.
+.It Fl H Ar hostname
+Use the given
+.Ar hostname
+for SNI, instead of the one extracted from the IRI.
+The IRI hostname will still be used for the DNS resolution.
+.It Fl h
+Print only the response header.
+.It Fl K Pa key.pem
+Load the client certificate key, must be in PEM format.
+.It Fl N
+Don't check whether the peer certificate name matches the requested
+hostname.
+.It Fl V
+Only validate the IRI, don't do the Gemini transaction.
+.It Fl v
+Print also the request.
+.El
+.Pp
+Note that
+.Nm
+won't try to do TOFU (Trust On First Use) or any X.509 certificate
+validation: it will happily accept any certificate it is given.
+.Pp
+By default
+.Nm
+will accept both TLSv1.2 and TLSv1.3 and will always do SNI.
blob - /dev/null
blob + 7eb698f5700f3ad09a243917ce979f3da2e3dc82 (mode 644)
--- /dev/null
+++ regress/gg.c
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2021 Omar Polo <op@omarpolo.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "../gmid.h"
+
+#include <string.h>
+
+int flag2, flag3, bflag, cflag, hflag, Nflag, Vflag, vflag;
+const char *cert, *key;
+
+int
+main(int argc, char **argv)
+{
+	struct iri iri;
+	struct tls_config *conf;
+	struct tls *ctx;
+	char iribuf[GEMINI_URL_LEN], buf[GEMINI_URL_LEN];
+	const char *parse_err = "unknown error", *port = "1965";
+	const char *hostname;
+	char *t;
+	int ch;
+	int handshake;
+	ssize_t len;
+
+	hostname = NULL;
+	while ((ch = getopt(argc, argv, "23C:cbH:hK:NVv")) != -1) {
+		switch (ch) {
+		case '2':
+			flag2 = 1;
+			break;
+		case '3':
+			flag3 = 1;
+			break;
+		case 'b':
+			bflag = 1;
+			break;
+		case 'C':
+			cert = optarg;
+			break;
+		case 'c':
+			cflag = 1;
+			break;
+		case 'H':
+			hostname = optarg;
+			break;
+		case 'h':
+			hflag = 1;
+			break;
+		case 'K':
+			key = optarg;
+			break;
+		case 'N':
+			Nflag = 1;
+			break;
+		case 'V':
+			Vflag = 1;
+			break;
+		case 'v':
+			vflag = 1;
+			break;
+		default:
+			fprintf(stderr, "USAGE: %s [-23cbhNVv] [-H hostname]\n",
+			    *argv);
+			return 1;
+		}
+	}
+	argc -= optind;
+	argv += optind;
+
+	if ((bflag + cflag + hflag + Vflag) > 1)
+		errx(1, "only one of bchr flags can be used.");
+
+	if (flag2 + flag3 > 1)
+		errx(1, "only -2 or -3 can be specified at the same time.");
+
+	if ((cert != NULL && key == NULL) || (cert == NULL && key != NULL))
+		errx(1, "missing certificate or key");
+
+	if (argc != 1)
+		errx(1, "missing IRI");
+
+	if (strlcpy(iribuf, argv[0], sizeof(iribuf)) >= sizeof(iribuf))
+		errx(1, "request too long: %s", argv[0]);
+	if (strlcpy(buf, argv[0], sizeof(buf)) >= sizeof(iribuf))
+		errx(1, "request too long: %s", argv[0]);
+	if (strlcat(buf, "\r\n", sizeof(buf)) >= sizeof(buf))
+		errx(1, "request too long: %s", argv[0]);
+
+	if (!parse_iri(iribuf, &iri, &parse_err))
+		errx(1, "invalid IRI: %s", parse_err);
+
+	if (Vflag)
+		errx(0, "IRI: OK");
+
+	if ((conf = tls_config_new()) == NULL)
+		errx(1, "tls_config_new");
+
+	tls_config_insecure_noverifycert(conf);
+	if (Nflag)
+		tls_config_insecure_noverifyname(conf);
+
+	if (flag2 && tls_config_set_protocols(conf, TLS_PROTOCOL_TLSv1_2) == -1)
+		errx(1, "cannot set TLSv1.2");
+	if (flag3 && tls_config_set_protocols(conf, TLS_PROTOCOL_TLSv1_3) == -1)
+		errx(1, "cannot set TLSv1.3");
+
+	if (cert != NULL && tls_config_set_keypair_file(conf, cert, key))
+		errx(1, "couldn't load cert: %s", cert);
+
+	if ((ctx = tls_client()) == NULL)
+		errx(1, "tls_client creation failed");
+
+	if (tls_configure(ctx, conf) == -1)
+		errx(1, "tls_configure: %s", tls_error(ctx));
+
+	if (*iri.port != '\0')
+		port = iri.port;
+
+	if (hostname == NULL)
+		hostname = iri.host;
+
+	if (tls_connect_servername(ctx, iri.host, port, hostname) == -1)
+		errx(1, "tls_connect: %s", tls_error(ctx));
+
+	for (handshake = 0; !handshake;) {
+		switch (tls_handshake(ctx)) {
+		case 0:
+		case -1:
+			handshake = 1;
+			break;
+		}
+	}
+
+	if (vflag)
+		printf("%s", buf);
+	if (tls_write(ctx, buf, strlen(buf)) == -1)
+		errx(1, "tls_write: %s", tls_error(ctx));
+
+	for (;;) {
+		switch (len = tls_read(ctx, buf, sizeof(buf))) {
+		case 0:
+		case -1:
+			goto end;
+		case TLS_WANT_POLLIN:
+		case TLS_WANT_POLLOUT:
+			continue;
+		}
+
+		if (bflag) {
+			bflag = 0;
+			if ((t = strchr(buf, '\r')) != NULL)
+				t += 2;
+			else if ((t = strchr(buf, '\n')) != NULL)
+				t += 1;
+			else
+				continue;
+			len -= t - buf;
+			write(1, t, len);
+			continue;
+		}
+
+		if (cflag) {
+			write(1, buf, 2);
+			write(1, "\n", 1);
+			break;
+		}
+
+		if (hflag) {
+			t = strchr(buf, '\r');
+			if (t == NULL)
+				t = strchr(buf, '\n');
+			if (t == NULL)
+				t = &buf[len];
+                        write(1, buf, t - buf);
+			write(1, "\n", 1);
+			break;
+		}
+
+		write(1, buf, len);
+	}
+end:
+
+	tls_close(ctx);
+	tls_free(ctx);
+
+	return 0;
+}
blob - 02cd09b8190a6bee289f07716da2a20e7c8a1476
blob + 098db1a4668faecb1226eae970a097a09e7c26e7
--- regress/runtime
+++ regress/runtime
@@ -27,19 +27,19 @@ checkconf() {
 # usage: get <path>
 # return the body of the request on stdout
 get() {
-	./../gg -b $ggflags "gemini://localhost:10965/$1"
+	./gg -b $ggflags "gemini://localhost:10965/$1"
 }
 
 # usage: head <path>
 # return the meta response line on stdout
 head() {
-	./../gg -h $ggflags "gemini://localhost:10965/$1"
+	./gg -h $ggflags "gemini://localhost:10965/$1"
 }
 
 # usage: raw <path>
 # return both header and body
 raw() {
-	./../gg $ggflags "gemini://localhost:10965/$1"
+	./gg $ggflags "gemini://localhost:10965/$1"
 }
 
 run() {