commit cb05cce7a39f2f45a21248ada25ecdfd073f64f8 from: Omar Polo date: Fri Nov 11 19:06:04 2022 UTC fix url handling commit - c063deb1a1e9296c7ac51636144f503a07b39195 commit + cb05cce7a39f2f45a21248ada25ecdfd073f64f8 blob - 7865a348251da2df0b4422d88e0b766d9479316f blob + 80ad3b893d4b2501a6a15b5e7096bbe4477dc93d --- proxy.c +++ proxy.c @@ -62,6 +62,7 @@ void proxy_init(struct privsep *, struct privsep_proc int proxy_launch(struct galileo *); void proxy_inflight_dec(const char *); int proxy_dispatch_parent(int, struct privsep_proc *, struct imsg *); +int proxy_resurl(struct client *, const char *, char *, size_t); void proxy_translate_gemtext(struct client *); void proxy_resolved(struct asr_result *, void *); void proxy_connect(int, short, void *); @@ -160,8 +161,90 @@ proxy_dispatch_parent(int fd, struct privsep_proc *p, } static int +portok(const char **url, struct client *clt) +{ + const char *u = *url; + const char *port = clt->clt_pc->proxy_port; + size_t len; + + len = strlen(port); + + if (*u == '\0' || *u == '/' || *u == '?' || *u == '#') + return (1); + if (*u != ':') + return (0); + u++; + if (strncmp(u, port, len) != 0) + return (0); + u += len; + if (*u != '\0' && *u != '/' && *u != '?' && *u != '#') + return (0); + *url = u; + return (1); +} + +int +proxy_resurl(struct client *clt, const char *url, char *buf, size_t len) +{ + const char *tmp; + size_t l; + + l = strlen(clt->clt_server_name); + + if (len == 0) { + log_warn("%s: zero-sized buffer!", __func__); + return (-1); + } + + /* look if it's an absolute URI */ + if (strncmp(url, "//", 2) == 0) { + tmp = url + 2; + if (strncmp(tmp, clt->clt_server_name, l) != 0) + goto done; + + tmp += l; + if (!portok(&tmp, clt)) + goto done; + url = tmp; + } else if (strncmp(url, "gemini://", 9) == 0) { + tmp = url + 9; + if (strncmp(tmp, clt->clt_server_name, l) != 0) + goto done; + + tmp += l; + if (!portok(&tmp, clt)) + goto done; + url = tmp; + } else { + tmp = url; + while (isalpha((unsigned char)*tmp) || *tmp == '+') + tmp++; + if (strncmp(tmp, "://", 3) == 0) + goto done; + } + + /* maybe it's an absolute path? */ + if (*url == '\0' || *url == '/') { + if (strlcpy(buf, clt->clt_script_name, len) >= len) + return (-1); + if (strlcat(buf, url + 1, len) >= len) + return (-1); + return (0); + } + + /* otherwise, leave it as it is */ + done: + if (strlcpy(buf, url, len) >= len) + return (-1); + return (0); +} + +static int gemtext_translate_line(struct client *clt, char *line) { + char buf[1025]; + char *url; + /* preformatted line / closing */ if (clt->clt_translate & TR_PRE) { if (!strncmp(line, "```", 3)) { @@ -201,7 +284,7 @@ gemtext_translate_line(struct client *clt, char *line) clt->clt_translate &= ~TR_LIST; } - /* link -- TODO: relativify from SCRIPT_NAME */ + /* link */ if (!strncmp(line, "=>", 2)) { char *label; @@ -214,19 +297,24 @@ gemtext_translate_line(struct client *clt, char *line) else *label++ = '\0'; - if (fnmatch("*.jpg", line, 0) == 0 || - fnmatch("*.jpeg", line, 0) == 0 || - fnmatch("*.gif", line, 0) == 0 || - fnmatch("*.png", line, 0) == 0 || - fnmatch("*.svg", line, 0) == 0 || - fnmatch("*.webp", line, 0) == 0) { + if (proxy_resurl(clt, line, buf, sizeof(buf)) == 0) + url = buf; + else + url = line; /* leave the URL as it is */ + + if (fnmatch("*.jpg", url, 0) == 0 || + fnmatch("*.jpeg", url, 0) == 0 || + fnmatch("*.gif", url, 0) == 0 || + fnmatch("*.png", url, 0) == 0 || + fnmatch("*.svg", url, 0) == 0 || + fnmatch("*.webp", url, 0) == 0) { if (clt->clt_translate & TR_NAV) { if (clt_puts(clt, "") == -1) return (-1); clt->clt_translate &= ~TR_NAV; } - if (tp_figure(clt->clt_tp, line, label) == -1) + if (tp_figure(clt->clt_tp, url, label) == -1) return (-1); return (0); @@ -241,17 +329,7 @@ gemtext_translate_line(struct client *clt, char *line) if (clt_puts(clt, "
  • clt_tp, - clt->clt_script_name) == -1) - return (-1); - - /* skip the first / */ - line++; - } - - if (tp_urlescape(clt->clt_tp, line) == -1 || + if (tp_urlescape(clt->clt_tp, url) == -1 || clt_puts(clt, "'>") == -1 || tp_htmlescape(clt->clt_tp, label) == -1 || clt_puts(clt, "
  • ") == -1) @@ -668,6 +746,7 @@ proxy_read(struct bufferevent *bev, void *d) struct client *clt = d; struct evbuffer *src = EVBUFFER_INPUT(bev); const char *ctype; + char buf[1025]; char lang[16]; char *hdr, *mime; size_t len; @@ -711,19 +790,9 @@ proxy_read(struct bufferevent *bev, void *d) /* handled below */ break; case '3': - /* XXX: do proper parsing */ - if (hdr[3] == '/' || strstr(&hdr[3], "//") == NULL) { - char *url; - - if (asprintf(&url, "%s%s", clt->clt_script_name, - &hdr[3]) == -1) - goto err; - - if (proxy_start_reply(clt, 302, url)) { - free(url); + if (proxy_resurl(clt, &hdr[3], buf, sizeof(buf)) == 0) { + if (proxy_start_reply(clt, 302, buf) == -1) goto err; - } - free(url); fcgi_end_request(clt, 0); goto err; }