Re: bin/60346: ftp failure when handling redirect through HTTP proxy
"Michael van Elst via gnats" <[email protected]>
| Newsgroups | gmane.os.netbsd.bugs |
|---|---|
| Message-ID | <[email protected]> |
The following reply was made to PR bin/60346; it has been noted by GNATS. From: [email protected] (Michael van Elst) To: [email protected] Cc: Subject: Re: bin/60346: ftp failure when handling redirect through HTTP proxy Date: Sat, 27 Jun 2026 05:10:30 -0000 (UTC) [email protected] ("Michael van Elst via gnats") writes: > Here is a more complete handling of relative URLs. And with some bug fixes... Index: usr.bin/ftp/Makefile =================================================================== RCS file: /cvsroot/src/usr.bin/ftp/Makefile,v retrieving revision 1.45 diff -p -u -r1.45 Makefile --- usr.bin/ftp/Makefile 8 Feb 2026 09:00:54 -0000 1.45 +++ usr.bin/ftp/Makefile 27 Jun 2026 05:01:06 -0000 @@ -7,7 +7,7 @@ USE_FORT?= yes # network client PROG= ftp SRCS= cmds.c cmdtab.c complete.c domacro.c fetch.c ftp.c main.c \ - progressbar.c ruserpass.c util.c + progressbar.c ruserpass.c uri.c util.c SRCS+= ssl.c # Uncomment the following to provide defaults for gate-ftp operation Index: usr.bin/ftp/fetch.c =================================================================== RCS file: /cvsroot/src/usr.bin/ftp/fetch.c,v retrieving revision 1.246 diff -p -u -r1.246 fetch.c --- usr.bin/ftp/fetch.c 8 Feb 2026 09:00:54 -0000 1.246 +++ usr.bin/ftp/fetch.c 27 Jun 2026 05:01:07 -0000 @@ -68,6 +68,7 @@ __RCSID("$NetBSD: fetch.c,v 1.246 2026/0 #include "ssl.h" #include "ftp_var.h" +#include "uri.h" #include "version.h" typedef enum { @@ -1246,6 +1247,7 @@ negotiate_connection(FETCH *fin, const c if (verbose) fprintf(ttyout, "Redirected to %s\n", location); + location = make_absurl(location, url); *rval = go_fetch(location, ui); } goto cleanup_fetch_url; Index: usr.bin/ftp/uri.c =================================================================== RCS file: usr.bin/ftp/uri.c diff -N usr.bin/ftp/uri.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ usr.bin/ftp/uri.c 27 Jun 2026 05:01:07 -0000 @@ -0,0 +1,313 @@ +/* $NetBSD: $ */ + +/*- + * Copyright (c) 2026 The NetBSD Foundation, Inc. + * All rights reserved. + * + * 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. + */ + +#include <stdlib.h> +#include <string.h> + +#include "ssl.h" +#include "ftp_var.h" +#include "uri.h" + +typedef struct { + const char *buf; + size_t scheme; + size_t authority; + size_t path; + size_t query; + size_t fragment; +} uriparts_t; + +#define SCHEME(p) ((p)->buf) +#define AUTHORITY(p) (SCHEME(p) + (p)->scheme) +#define PATH(p) (AUTHORITY(p) + (p)->authority) +#define QUERY(p) (PATH(p) + (p)->path) +#define FRAGMENT(p) (QUERY(p) + (p)->query) + +static void +split_uri(const char *uri, uriparts_t *parts) +{ + char *colon, *slash, *query, *sharp; + + parts->buf = uri; + parts->scheme = 0; + parts->authority = 0; + parts->path = 0; + parts->query = 0; + parts->fragment = 0; + + colon = strchr(uri, ':'); + slash = strchr(uri, '/'); + if (colon && (slash == NULL || (colon - uri) < (slash - uri))) { + parts->scheme = colon + 1 - uri; + uri = colon + 1; + } + + if (uri[0] == '/' && uri[1] == '/') { + slash = strchr(uri + 2, '/'); + if (slash == NULL) { + parts->authority = strlen(uri); + return; + } + parts->authority = slash - uri; + uri = slash; + } + + query = strchr(uri, '?'); + sharp = strchr(uri, '#'); + if (query && (sharp == NULL || (query - uri) < (sharp - uri))) { + parts->path = query - uri; + uri = query; + if (sharp != NULL) { + parts->query = sharp - query; + parts->fragment = strlen(sharp); + return; + } + parts->query = strlen(query); + return; + } + + if (sharp != NULL) { + parts->path = sharp - uri; + parts->fragment = strlen(sharp); + return; + } + + parts->path = strlen(uri); +} + +static char * +build_uri(uriparts_t *s, uriparts_t *a, uriparts_t *p, + uriparts_t *q, uriparts_t *f) +{ + size_t len; + char *buf, *out; + + len = s->scheme + a->authority + p->path + q->query + f->fragment; + buf = ftp_malloc(len + 1); + + out = buf; + memcpy(out, SCHEME(s), s->scheme); + out += s->scheme; + memcpy(out, AUTHORITY(a), a->authority); + out += a->authority; + memcpy(out, PATH(p), p->path); + out += p->path; + memcpy(out, QUERY(q), q->query); + out += q->query; + memcpy(out, FRAGMENT(f), f->fragment); + out += f->fragment; + *out = '\0'; + + return buf; +} + +static char * +remove_dot_segments(const char *path, size_t len) +{ + char *p; + char *buf, *out, *seg; + size_t n; + + p = ftp_malloc(len + 1); + strcpy(p, path); + + buf = ftp_malloc(len + 1); + out = buf; + *out = '\0'; + + while (len > 0) { + /* A */ + if (p[0] == '.') { + if (len > 1 && p[1] == '/') { + p += 2; + len -= 2; + continue; + } else if (len > 2 && p[1] == '.' && p[2] == '/') { + p += 3; + len -= 3; + continue; + } + } + + /* B */ + if (p[0] == '/') { + if (len > 2 && p[1] == '.' && p[2] == '/') { + p += 2; + len -= 2; + continue; + } else if (len == 2 && p[1] == '.') { + p += 1; + len -= 1; + p[0] = '/'; + continue; + } + } + + /* C */ + if (len > 2 && p[0] == '/' && p[1] == '.' && p[2] == '.') { + if (len > 3 && p[3] == '/') { + p += 3; + len -= 3; + seg = strrchr(buf, '/'); + if (seg != NULL) + *seg = '\0'; + continue; + } else if (len == 3) { + p += 2; + len -= 2; + p[0] = '/'; + seg = strrchr(buf, '/'); + if (seg != NULL) + *seg = '\0'; + continue; + } + } + + /* D */ + if (p[0] == '.') { + if (len == 1) { + p += 1; + len -= 1; + continue; + } else if (len == 2 && p[1] == '.') { + p += 2; + len -= 2; + continue; + } + } + + /* E */ + if (p[0] == '/') { + seg = strchr(p+1, '/'); + } else { + seg = strchr(p, '/'); + } + if (seg != NULL) + n = seg - p; + else + n = len; + + memcpy(out, p, n); + out += n; + *out = '\0'; + p += n; + len -= n; + }; + + FREEPTR(p); + + return buf; +} + +static char * +merge_paths(uriparts_t *base, uriparts_t *ref) +{ + char *buf; + const char *path, *last; + size_t len; + + if (base->authority && base->path == 0) { + len = 1 + ref->path; + buf = ftp_malloc(len + 1); + buf[0] = '/'; + memcpy(buf + 1, PATH(ref), ref->path); + } else { + path = PATH(base); + last = strrchr(path, '/'); + if (last == NULL || (size_t)(last - path) > base->path) + len = 0; + else + len = (size_t)(last - path) + 1; + buf = ftp_malloc(len + ref->path + 1); + memcpy(buf, path, len); + memcpy(buf + len, PATH(ref), ref->path); + len += ref->path; + } + buf[len] = '\0'; + + return buf; +} + +char * +make_absurl(char *refurl, const char *baseurl) +{ + uriparts_t base; + uriparts_t ref; + uriparts_t p; + char *buf, *tmp1, *tmp2; + + split_uri(baseurl, &base); + split_uri(refurl, &ref); + + p.scheme = p.authority = p.path = p.query = p.fragment = 0; + + if (ref.scheme) { + tmp1 = remove_dot_segments(PATH(&ref), ref.path); + p.buf = tmp1; + p.path = strlen(tmp1); + buf = build_uri(&ref, &ref, &p, &ref, &ref); + FREEPTR(tmp1); + } else { + if (ref.authority) { + tmp1 = remove_dot_segments(PATH(&ref), ref.path); + p.buf = tmp1; + p.path = strlen(tmp1); + buf = build_uri(&base, &ref, &p, &ref, &ref); + FREEPTR(tmp1); + } else { + if (ref.path == 0) { + if (ref.query) { + buf = build_uri(&base, &base, &base, &ref, &ref); + } else { + buf = build_uri(&base, &base, &base, &base, &ref); + } + } else { + if (PATH(&ref)[0] == '/') { + tmp1 = remove_dot_segments(PATH(&ref), ref.path); + p.buf = tmp1; + p.path = strlen(tmp1); + buf = build_uri(&base, &base, &p, &ref, &ref); + FREEPTR(tmp1); + } else { + tmp2 = merge_paths(&base, &ref); + tmp1 = remove_dot_segments(tmp2, strlen(tmp2)); + p.buf = tmp1; + p.path = strlen(tmp1); + FREEPTR(tmp2); + + buf = build_uri(&base, &base, &p, &ref, &ref); + FREEPTR(tmp1); + } + } + } + } + + FREEPTR(refurl); + + return buf; +} Index: usr.bin/ftp/uri.h =================================================================== RCS file: usr.bin/ftp/uri.h diff -N usr.bin/ftp/uri.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ usr.bin/ftp/uri.h 27 Jun 2026 05:01:07 -0000 @@ -0,0 +1,29 @@ +/* $NetBSD: $ */ + +/*- + * Copyright (c) 2026 The NetBSD Foundation, Inc. + * All rights reserved. + * + * 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. + */ + +char *make_absurl(char *, const char *);