commit - 6acf1bb453dd5584d4567d939b3cc148c300f187
commit + 62c0f697ddc7396384280f2f8bac7a092700f1ba
blob - ef1c974197379078a2b295149504fc5bfa103738
blob + 9a44d9597949d1e4c46f5778bb4d34da0f552753
--- iri.c
+++ iri.c
/*
- * Copyright (c) 2022 Omar Polo <op@omarpolo.com>
+ * Copyright (c) 2022, 2024 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
err:
errno = ENOBUFS;
return (-1);
+}
+
+int
+iri_urlescape(const char *path, char *buf, size_t len)
+{
+ const char *hex = "0123456789abcdef";
+ const uint8_t *p = path;
+
+ while (*p) {
+ if (len == 0)
+ break;
+
+ if (unreserved(*p) || sub_delims(*p) ||
+ *p == ':' || *p == '@' ||
+ *p == '/') {
+ *buf++ = *p++;
+ len--;
+ continue;
+ }
+
+ if (len < 3)
+ break;
+ *buf++ = '%';
+ *buf++ = hex[*p >> 4];
+ *buf++ = hex[*p & 0xf];
+ len -= 3;
+ p++;
+ }
+
+ if (len == 0 || *p)
+ return (-1);
+
+ *buf = '\0';
+ return (0);
+}
+
+int
+iri_urlunescape(const char *str, char *buf, size_t len)
+{
+ char t[3];
+ unsigned long l;
+
+ t[2] = '\0';
+
+ while (*str) {
+ if (len == 0)
+ return (-1);
+
+ if (*str != '%') {
+ *buf++ = *str++;
+ len--;
+ continue;
+ }
+
+ if (!isxdigit((unsigned char)str[1]) ||
+ !isxdigit((unsigned char)str[2]))
+ return (-1);
+
+ t[0] = str[1];
+ t[1] = str[2];
+
+ /* we know it's a proper number and will fit a char */
+ l = strtol(t, NULL, 16);
+ *buf++ = (unsigned char)l;
+ len--;
+ str += 3;
+ }
+
+ if (len == 0)
+ return (-1);
+ *buf = '\0';
+ return (0);
}
blob - 03ea7a8b0a497bc4ec9b9924db76cda1c03af23c
blob + 164785cba484bbb4faf96b930929940ae8537fbb
--- iri.h
+++ iri.h
/*
- * Copyright (c) 2022 Omar Polo <op@omarpolo.com>
+ * Copyright (c) 2022, 2024 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
int iri_setport(struct iri *, const char *);
int iri_setquery(struct iri *, const char *);
+int iri_urlescape(const char *, char *, size_t);
+int iri_urlunescape(const char *, char *, size_t);
+
#endif /* IRI_H */
blob - efd08aea46d99986a0dcae05a99a738784ac5a27
blob + ba333328471a966bb716d45587b30befead9bf0d
--- parser_gophermap.c
+++ parser_gophermap.c
/*
- * Copyright (c) 2021 Omar Polo <op@omarpolo.com>
+ * Copyright (c) 2021, 2024 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
#include <string.h>
#include "parser.h"
+#include "iri.h"
#include "utils.h"
#ifndef LINE_MAX
gm_parse(struct parser *p, const char *buf, size_t size)
{
return parser_foreach_line(p, buf, size, gm_foreach_line);
+}
+
+static int
+selector2uri(struct gm_selector *s, char *buf, size_t len)
+{
+ int r;
+
+ r = snprintf(buf, len, "gopher://%s:%s/%c%s",
+ s->addr, s->port, s->type, *s->selector != '/' ? "/" : "");
+ if (r < 0 || (size_t)r >= len)
+ return (-1);
+
+ buf += r;
+ len -= r;
+ return (iri_urlescape(s->selector, buf, len));
}
static inline int
emit_line(struct parser *p, enum line_type type, struct gm_selector *s)
{
struct line *l;
- char buf[LINE_MAX], b[2] = {0};
+ char buf[LINE_MAX];
if ((l = calloc(1, sizeof(*l))) == NULL)
goto err;
case LINE_LINK:
if (s->type == 'h' && !strncmp(s->selector, "URL:", 4)) {
strlcpy(buf, s->selector+4, sizeof(buf));
- } else {
- strlcpy(buf, "gopher://", sizeof(buf));
- strlcat(buf, s->addr, sizeof(buf));
- strlcat(buf, ":", sizeof(buf));
- strlcat(buf, s->port, sizeof(buf));
- strlcat(buf, "/", sizeof(buf));
- b[0] = s->type;
- strlcat(buf, b, sizeof(buf));
- if (*s->selector != '/')
- strlcat(buf, "/", sizeof(buf));
- strlcat(buf, s->selector, sizeof(buf));
- }
+ } else if (selector2uri(s, buf, sizeof(buf)) == -1)
+ goto err;
if ((l->alt = strdup(buf)) == NULL)
goto err;
blob - 4e71ecbaff97f7964d344324aed229fd8d1cf793
blob + 80420dcfbd8080e2692413ee333b8a0fb9339839
--- telescope.c
+++ telescope.c
return;
}
- strlcpy(req.req, path, sizeof(req.req));
+ if (iri_urlunescape(path, req.req, sizeof(req.req)) == -1)
+ strlcpy(req.req, path, sizeof(req.req));
if (tab->iri.iri_flags & IH_QUERY) {
strlcat(req.req, "?", sizeof(req.req));
strlcat(req.req, tab->iri.iri_query, sizeof(req.req));