NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: bin/60346: ftp failure when handling redirect through HTTP proxy



The following reply was made to PR bin/60346; it has been noted by GNATS.

From: mlelstv%serpens.de@localhost (Michael van Elst)
To: gnats-bugs%netbsd.org@localhost
Cc: 
Subject: Re: bin/60346: ftp failure when handling redirect through HTTP proxy
Date: Thu, 25 Jun 2026 21:03:13 -0000 (UTC)

 gnats-admin%NetBSD.org@localhost ("mlelstv%serpens.de@localhost via gnats") writes:
 
 >>Fix:
 >Maybe this:
 
 Here is a more complete handling of relative URLs.
 
 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	25 Jun 2026 20:55:25 -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	25 Jun 2026 20:55:25 -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	25 Jun 2026 20:55:25 -0000
 @@ -0,0 +1,304 @@
 +/*	$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 {
 +	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(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;
 +
 +	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 > 1 && 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;
 +			} else {
 +				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, char *baseurl)
 +{
 +	uriparts_t base;
 +	uriparts_t ref;
 +	uriparts_t tmp;
 +	char *buf, *tmp2;
 +	
 +	split_uri(baseurl, &base);
 +	split_uri(refurl, &ref);
 +
 +	tmp.scheme = tmp.authority = tmp.path = tmp.query = tmp.fragment = 0;
 +
 +	if (ref.scheme) {
 +		tmp.buf = remove_dot_segments(PATH(&ref), ref.path);
 +		tmp.path = strlen(tmp.buf);
 +		buf = build_uri(&ref, &ref, &tmp, &ref, &ref);
 +		FREEPTR(tmp.buf);
 +	} else {
 +		if (ref.authority) {
 +			tmp.buf = remove_dot_segments(PATH(&ref), ref.path);
 +			tmp.path = strlen(tmp.buf);
 +			buf = build_uri(&base, &ref, &tmp, &ref, &ref);
 +			FREEPTR(tmp.buf);
 +		} 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] == '/') {
 +					tmp.buf = remove_dot_segments(PATH(&ref), ref.path);
 +					tmp.path = strlen(tmp.buf);
 +					buf = build_uri(&base, &base, &tmp, &ref, &ref);
 +					FREEPTR(tmp.buf);
 +				} else {
 +					tmp2 = merge_paths(&base, &ref);
 +					tmp.buf = remove_dot_segments(tmp2, strlen(tmp2));
 +					tmp.path = strlen(tmp.buf);
 +					FREEPTR(tmp2);
 +
 +					buf = build_uri(&base, &base, &tmp, &ref, &ref);
 +					FREEPTR(tmp.buf);
 +				}
 +			}
 +		}
 +	}
 +
 +	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	25 Jun 2026 20:55:25 -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 *, char *);
 



Home | Main Index | Thread Index | Old Index