You should have received a copy of the GNU General Public License
along with Wget; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+In addition, as a special exception, the Free Software Foundation
+gives permission to link the code of its release of Wget with the
+OpenSSL project's "OpenSSL" library (or with modified versions of it
+that use the same license as the "OpenSSL" library), and distribute
+the linked executables. You must obey the GNU General Public License
+in all respects for all of the code used other than "OpenSSL". If you
+modify this file, you may extend this exception to your version of the
+file, but you are not obligated to do so. If you do not wish to do
+so, delete this exception statement from your version. */
#include <config.h>
/* Is X ".."? */
#define DDOTP(x) ((*(x) == '.') && (*(x + 1) == '.') && (!*(x + 2)))
+static const int NS_INADDRSZ = 4;
+static const int NS_IN6ADDRSZ = 16;
+static const int NS_INT16SZ = 2;
+
+
struct scheme_data
{
char *leading_string;
"Invalid user name",
#define PE_UNTERMINATED_IPV6_ADDRESS 5
"Unterminated IPv6 numeric address",
-#define PE_INVALID_IPV6_ADDRESS 6
- "Invalid char in IPv6 numeric address"
+#define PE_IPV6_NOT_SUPPORTED 6
+ "IPv6 addresses not supported",
+#define PE_INVALID_IPV6_ADDRESS 7
+ "Invalid IPv6 numeric address"
};
#define SETERR(p, v) do { \
*(p) = (v); \
} while (0)
+#ifdef ENABLE_IPV6
+/* The following two functions were adapted from glibc. */
+
+static int
+is_valid_ipv4_address (const char *str, const char *end)
+{
+ int saw_digit, octets;
+ int val;
+
+ saw_digit = 0;
+ octets = 0;
+ val = 0;
+
+ while (str < end) {
+ int ch = *str++;
+
+ if (ch >= '0' && ch <= '9') {
+ val = val * 10 + (ch - '0');
+
+ if (val > 255)
+ return 0;
+ if (saw_digit == 0) {
+ if (++octets > 4)
+ return 0;
+ saw_digit = 1;
+ }
+ } else if (ch == '.' && saw_digit == 1) {
+ if (octets == 4)
+ return 0;
+ val = 0;
+ saw_digit = 0;
+ } else
+ return 0;
+ }
+ if (octets < 4)
+ return 0;
+
+ return 1;
+}
+
+static int
+is_valid_ipv6_address (const char *str, const char *end)
+{
+ static const char xdigits[] = "0123456789abcdef";
+ const char *curtok;
+ int tp;
+ const char *colonp;
+ int saw_xdigit;
+ unsigned int val;
+
+ tp = 0;
+ colonp = NULL;
+
+ if (str == end)
+ return 0;
+
+ /* Leading :: requires some special handling. */
+ if (*str == ':')
+ {
+ ++str;
+ if (str == end || *str != ':')
+ return 0;
+ }
+
+ curtok = str;
+ saw_xdigit = 0;
+ val = 0;
+
+ while (str < end) {
+ int ch = *str++;
+ const char *pch;
+
+ /* if ch is a number, add it to val. */
+ pch = strchr(xdigits, ch);
+ if (pch != NULL) {
+ val <<= 4;
+ val |= (pch - xdigits);
+ if (val > 0xffff)
+ return 0;
+ saw_xdigit = 1;
+ continue;
+ }
+
+ /* if ch is a colon ... */
+ if (ch == ':') {
+ curtok = str;
+ if (saw_xdigit == 0) {
+ if (colonp != NULL)
+ return 0;
+ colonp = str + tp;
+ continue;
+ } else if (str == end) {
+ return 0;
+ }
+ if (tp > NS_IN6ADDRSZ - NS_INT16SZ)
+ return 0;
+ tp += NS_INT16SZ;
+ saw_xdigit = 0;
+ val = 0;
+ continue;
+ }
+
+ /* if ch is a dot ... */
+ if (ch == '.' && (tp <= NS_IN6ADDRSZ - NS_INADDRSZ) &&
+ is_valid_ipv4_address(curtok, end) == 1) {
+ tp += NS_INADDRSZ;
+ saw_xdigit = 0;
+ break;
+ }
+
+ return 0;
+ }
+
+ if (saw_xdigit == 1) {
+ if (tp > NS_IN6ADDRSZ - NS_INT16SZ)
+ return 0;
+ tp += NS_INT16SZ;
+ }
+
+ if (colonp != NULL) {
+ if (tp == NS_IN6ADDRSZ)
+ return 0;
+ tp = NS_IN6ADDRSZ;
+ }
+
+ if (tp != NS_IN6ADDRSZ)
+ return 0;
+
+ return 1;
+}
+#endif
+
/* Parse a URL.
Return a new struct url if successful, NULL on error. In case of
if (*p == '[')
{
- /* Support http://[::1]/ used by IPv6. */
- int invalid = 0;
- ++p;
- while (1)
+ /* Handle IPv6 address inside square brackets. Ideally we'd
+ just look for the terminating ']', but rfc2732 mandates
+ rejecting invalid IPv6 addresses. */
+
+ /* The address begins after '['. */
+ host_b = p + 1;
+ host_e = strchr (host_b, ']');
+
+ if (!host_e)
{
- char c = *p++;
- switch (c)
- {
- case ']':
- goto out;
- case '\0':
- SETERR (error, PE_UNTERMINATED_IPV6_ADDRESS);
- return NULL;
- case ':': case '.':
- break;
- default:
- if (ISXDIGIT (c))
- break;
- invalid = 1;
- }
+ SETERR (error, PE_UNTERMINATED_IPV6_ADDRESS);
+ return NULL;
}
- out:
- if (invalid)
+
+#ifdef ENABLE_IPV6
+ /* Check if the IPv6 address is valid. */
+ if (!is_valid_ipv6_address(host_b, host_e))
{
SETERR (error, PE_INVALID_IPV6_ADDRESS);
return NULL;
}
- /* Don't include brackets in [host_b, host_p). */
- ++host_b;
- host_e = p - 1;
+
+ /* Continue parsing after the closing ']'. */
+ p = host_e + 1;
+#else
+ SETERR (error, PE_IPV6_NOT_SUPPORTED);
+ return NULL;
+#endif
}
else
{
SETERR (error, PE_BAD_PORT_NUMBER);
return NULL;
}
+
port = 10 * port + (*pp - '0');
}
}
downloaded_files_hash = NULL;
}
}
+
+/* Return non-zero if scheme a is similar to scheme b.
+
+ Schemes are similar if they are equal. If SSL is supported, schemes
+ are also similar if one is http (SCHEME_HTTP) and the other is https
+ (SCHEME_HTTPS). */
+int
+schemes_are_similar_p (enum url_scheme a, enum url_scheme b)
+{
+ if (a == b)
+ return 1;
+#ifdef HAVE_SSL
+ if ((a == SCHEME_HTTP && b == SCHEME_HTTPS)
+ || (a == SCHEME_HTTPS && b == SCHEME_HTTP))
+ return 1;
+#endif
+ return 0;
+}
\f
#if 0
/* Debugging and testing support for path_simplify. */