From owner-freebsd-current@FreeBSD.ORG Mon Apr 9 20:50:55 2012 Return-Path: Delivered-To: freebsd-current@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 6CE53106566B for ; Mon, 9 Apr 2012 20:50:55 +0000 (UTC) (envelope-from emaste@freebsd.org) Received: from mail1.sandvine.com (Mail1.sandvine.com [64.7.137.134]) by mx1.freebsd.org (Postfix) with ESMTP id 16EB78FC14 for ; Mon, 9 Apr 2012 20:50:55 +0000 (UTC) Received: from labgw2.phaedrus.sandvine.com (192.168.222.22) by WTL-EXCH-1.sandvine.com (192.168.196.31) with Microsoft SMTP Server id 14.1.339.1; Mon, 9 Apr 2012 16:50:54 -0400 Received: by labgw2.phaedrus.sandvine.com (Postfix, from userid 10332) id E088D33C02; Mon, 9 Apr 2012 16:50:51 -0400 (EDT) Date: Mon, 9 Apr 2012 16:50:51 -0400 From: Ed Maste To: Message-ID: <20120409205051.GA27392@sandvine.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="NDin8bjvE/0mNLFQ" Content-Disposition: inline User-Agent: Mutt/1.4.2.1i Subject: [PATCH] percent-encoding for libfetch X-BeenThere: freebsd-current@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Discussions about the use of FreeBSD-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 09 Apr 2012 20:50:55 -0000 --NDin8bjvE/0mNLFQ Content-Type: text/plain; charset="us-ascii" Content-Disposition: inline Libfetch supports a username and password in a FTP or HTTP URL, but lacks a method to specify '@' or ':' there, as they're used as URL component separators. I discovered this issue because I have an FTP server that uses an email address as the username, and I can't use fetch(1) or libfetch against it. The attached patch adds decoding of percent-encoded usernames and passwords, in order to use a URL like ftp://foo%40example.com:password@host:port/file.bar . Please review. I plan to commit in the next few days. -Ed --NDin8bjvE/0mNLFQ Content-Type: text/plain; charset="us-ascii" Content-Disposition: attachment; filename="fetch.diff" Index: fetch.c =================================================================== --- fetch.c (revision 233584) +++ fetch.c (working copy) @@ -289,6 +289,49 @@ } /* + * Return value of the given hex digit. + */ +static int +fetch_hexval(char ch) +{ + + if (ch >= '0' && ch <= '9') + return (ch - '0'); + else if (ch >= 'a' && ch <= 'f') + return (ch - 'a' + 10); + else if (ch >= 'A' && ch <= 'F') + return (ch - 'A' + 10); + return (-1); +} + +/* + * Decode percent-encoded URL component from src into dst, stopping at end + * of string, or at @ or : separators. Returns a pointer to the unhandled + * part of the input string (null terminator, @, or :). No terminator is + * written to dst (it is the caller's responsibility). + */ +static const char * +fetch_pctdecode(char *dst, const char *src, size_t dlen) +{ + int d1, d2; + char c; + const char *s; + + for (s = src; *s != '\0' && *s != '@' && *s != ':'; s++) { + if (s[0] == '%' && (d1 = fetch_hexval(s[1])) >= 0 && + (d2 = fetch_hexval(s[2])) >= 0) { + c = d1 << 4 | d2; + s += 2; + } else { + c = *s; + } + if (dlen-- > 0) + *dst++ = c; + } + return (s); +} + +/* * Split an URL into components. URL syntax is: * [method:/][/[user[:pwd]@]host[:port]/][document] * This almost, but not quite, RFC1738 URL syntax. @@ -329,15 +372,11 @@ p = strpbrk(URL, "/@"); if (p && *p == '@') { /* username */ - for (q = URL, i = 0; (*q != ':') && (*q != '@'); q++) - if (i < URL_USERLEN) - u->user[i++] = *q; + q = fetch_pctdecode(u->user, URL, URL_USERLEN); /* password */ if (*q == ':') - for (q++, i = 0; (*q != ':') && (*q != '@'); q++) - if (i < URL_PWDLEN) - u->pwd[i++] = *q; + q = fetch_pctdecode(u->pwd, ++q, URL_PWDLEN); p++; } else { --NDin8bjvE/0mNLFQ--