summaryrefslogtreecommitdiff
path: root/source/xap
diff options
context:
space:
mode:
Diffstat (limited to 'source/xap')
-rwxr-xr-xsource/xap/seamonkey/gold/gold2
l---------source/xap/seamonkey/gold/ld1
-rwxr-xr-xsource/xap/seamonkey/seamonkey.SlackBuild61
-rw-r--r--source/xap/seamonkey/seamonkey.gettid.patch40
-rw-r--r--source/xap/seamonkey/seamonkey.i686.triplet.fix.diff11
-rw-r--r--source/xap/seamonkey/seamonkey.nsstring.patch24
-rw-r--r--source/xap/seamonkey/seamonkey.rust.encoding_rs.diff17
-rw-r--r--source/xap/seamonkey/seamonkey.rust14x.diff4279
-rw-r--r--source/xap/seamonkey/slack-desc2
9 files changed, 4391 insertions, 46 deletions
diff --git a/source/xap/seamonkey/gold/gold b/source/xap/seamonkey/gold/gold
deleted file mode 100755
index 8c86d3b0..00000000
--- a/source/xap/seamonkey/gold/gold
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/bash
-/usr/bin/ld.gold "$@"
diff --git a/source/xap/seamonkey/gold/ld b/source/xap/seamonkey/gold/ld
deleted file mode 120000
index 78a06a2a..00000000
--- a/source/xap/seamonkey/gold/ld
+++ /dev/null
@@ -1 +0,0 @@
-gold \ No newline at end of file
diff --git a/source/xap/seamonkey/seamonkey.SlackBuild b/source/xap/seamonkey/seamonkey.SlackBuild
index cfa82188..6f3dc56e 100755
--- a/source/xap/seamonkey/seamonkey.SlackBuild
+++ b/source/xap/seamonkey/seamonkey.SlackBuild
@@ -1,6 +1,6 @@
#!/bin/bash
-# Copyright 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 Patrick J. Volkerding, Sebeka, MN, USA
+# Copyright 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2020 Patrick J. Volkerding, Sebeka, MN, USA
# All rights reserved.
#
# Redistribution and use of this script, with or without modification, is
@@ -26,7 +26,7 @@ PKGNAM=seamonkey
TARBALLVER=${VERSION:-$(basename $(ls seamonkey-*.tar.* | cut -d - -f 2 | rev | cut -f 3- -d . | rev) .source)}
# Strip the end from beta versions:
VERSION=$(echo $TARBALLVER | cut -f 1 -d b)
-BUILD=${BUILD:-2}
+BUILD=${BUILD:-1}
# Automatically determine the architecture we're building on:
if [ -z "$ARCH" ]; then
@@ -57,19 +57,32 @@ else
OPTIMIZE_FLAG=${OPTIMIZE_FLAG:-"-O1"}
fi
-# Link using gold. This avoids running out of memory on 32-bit systems, and
-# avoids a recurring build failure with GNU ld on other systems.
-PATH="$(pwd)/gold:$PATH"
-export CC=${CC:-"gcc -B$(pwd)/gold"}
-export CXX=${CXX:-"g++ -B$(pwd)/gold"}
+# Seamonkey has been requiring more and more memory, especially while linking
+# libxul. If it fails to build natively on x86 32-bit, it can be useful to
+# attempt the build using an x86_64 kernel and a 32-bit userspace. Detect this
+# situation and set the ARCH to i686. Later in the script we'll add some
+# options to the .mozconfig so that the compile will do the right thing.
+if [ "$(uname -m)" = "x86_64" -a "$(file -L /usr/bin/gcc | grep 80386 | grep 32-bit)" != "" ]; then
+ COMPILE_X86_UNDER_X86_64=true
+ ARCH=i686
+fi
+
+# Choose a compiler (gcc/g++ or clang/clang++):
+export CC=${CC:-clang}
+export CXX=${CXX:-clang++}
# -Wformat is needed for -Werror=format-security
-# -Wno-format-overflow bypasses gcc9 build failure
# -fno-delete-null-pointer-checks disables gcc6 optimization that leads to instability
-# -fno-schedule-insns2 don't do an additional pass of instruction scheduling
-# -fno-lifetime-dse allow object storage to persist beyond the lifetime of the object
-export CFLAGS="-Wformat -Wno-format-overflow -fno-delete-null-pointer-checks -fno-schedule-insns2"
-export CXXFLAGS="-Wformat -Wno-format-overflow -fno-delete-null-pointer-checks -fno-schedule-insns2 -fno-lifetime-dse -fpermissive"
+export CFLAGS="-Wformat -fno-delete-null-pointer-checks"
+export CXXFLAGS="-Wformat -fno-delete-null-pointer-checks -fpermissive"
+
+# Keep memory usage as low as possible when linking:
+SLKLDFLAGS=" -Wl,--as-needed -Wl,--no-keep-memory -Wl,--stats"
+export LDFLAGS="$SLKLDFLAGS"
+export MOZ_LINK_FLAGS="$SLKLDFLAGS"
+
+# Don't use icecream:
+PATH=$(echo $PATH | sed "s|/usr/libexec/icecc/bin||g" | tr -s : | sed "s/^://g" | sed "s/:$//g")
NUMJOBS=${NUMJOBS:-" -j$(expr $(nproc) + 1) "}
@@ -84,7 +97,7 @@ PKG=$TMP/package-seamonkey
# following these instructions:
# https://bugzilla.mozilla.org/show_bug.cgi?id=1377987#c0
if [ -r /root/google-api-key ]; then
- GOOGLE_API_KEY="--with-google-api-keyfile=/root/google-api-key"
+ GOOGLE_API_KEY="--with-google-safebrowsing-api-keyfile=/root/google-api-key"
fi
rm -rf $PKG
@@ -110,10 +123,14 @@ cd seamonkey-${TARBALLVER} || exit 1
zcat $CWD/sm.ui.scrollToClick.diff.gz | patch -p1 --verbose || exit 1
# Fix for glibc-2.30's included gettid():
-zcat $CWD/seamonkey.gettid.patch.gz | patch -p2 --verbose || exit 1
+zcat $CWD/seamonkey.gettid.patch.gz | patch -p1 --verbose || exit 1
+
+# Don't fail on a Rust warning due to deprecated syntax:
+zcat $CWD/seamonkey.nsstring.patch.gz | patch -p0 --verbose || exit 1
-# Don't complain if Rust is i686:
-zcat $CWD/seamonkey.i686.triplet.fix.diff.gz | patch -p1 --verbose || exit 1
+# More Rust syntax changes:
+zcat $CWD/seamonkey.rust14x.diff.gz | patch -p1 --verbose || exit 1
+zcat $CWD/seamonkey.rust.encoding_rs.diff.gz | patch -p1 --verbose || exit 1
# Make sure the perms/ownerships are sane:
chown -R root:root .
@@ -123,8 +140,6 @@ find . \
\( -perm 666 -o -perm 664 -o -perm 600 -o -perm 444 -o -perm 440 -o -perm 400 \) \
-exec chmod 644 {} \+
-chown -R root:root .
-
# Our building options, in a configure-like display ;)
OPTIONS="\
--prefix=/usr \
@@ -134,18 +149,16 @@ OPTIONS="\
--enable-startup-notification \
--enable-alsa \
--disable-debug \
- --with-default-mozilla-five-home=/usr/lib${LIBDIRSUFFIX}/seamonkey-${VERSION} \
+ --enable-gold \
--enable-strip \
--disable-tests \
--disable-crashreporter \
--enable-accessibility \
$GOOGLE_API_KEY \
- --enable-safe-browsing \
--disable-updater \
--enable-chrome-format=omni \
--disable-necko-wifi \
--enable-extensions=default \
- --enable-rust \
--enable-js-shell \
--enable-elf-hack \
--enable-release \
@@ -182,6 +195,12 @@ mkdir -p mozilla/obj
# Set options for $OPTIMIZE_FLAG:
echo "ac_add_options --enable-optimize=\"${OPTIMIZE_FLAG}\"" >> .mozconfig
+if [ "$COMPILE_X86_UNDER_X86_64" = "true" ]; then
+ # Compile for i686 under an x86_64 kernel:
+ echo "ac_add_options --host=i686-pc-linux-gnu" >> .mozconfig
+ echo "ac_add_options --target=i686-pc-linux-gnu" >> .mozconfig
+fi
+
# Add the $OPTIONS above to .mozconfig:
for option in $OPTIONS; do echo "ac_add_options $option" >> .mozconfig; done
diff --git a/source/xap/seamonkey/seamonkey.gettid.patch b/source/xap/seamonkey/seamonkey.gettid.patch
index 81d5eabf..42a39247 100644
--- a/source/xap/seamonkey/seamonkey.gettid.patch
+++ b/source/xap/seamonkey/seamonkey.gettid.patch
@@ -1,15 +1,35 @@
-diff -Nrbu seamonkey-2.49.4/seamonkey-2.49.4/mozilla/tools/profiler/core/platform.h seamonkey-2.49.4-OK/seamonkey-2.49.4/mozilla/tools/profiler/core/platform.h
---- seamonkey-2.49.4/seamonkey-2.49.4/mozilla/tools/profiler/core/platform.h 2018-07-12 05:19:15.000000000 +0300
-+++ seamonkey-2.49.4-OK/seamonkey-2.49.4/mozilla/tools/profiler/core/platform.h 2019-07-27 20:31:47.675086876 +0300
-@@ -65,10 +65,7 @@
- #include <unistd.h>
- #if !defined(__BIONIC__)
- #include <sys/syscall.h>
+--- ./mozilla/tools/profiler/core/platform.h.orig 2020-02-17 17:39:44.000000000 -0600
++++ ./mozilla/tools/profiler/core/platform.h 2020-02-29 22:43:51.381996340 -0600
+@@ -43,32 +43,6 @@
+ #include <vector>
+ #include "StackTop.h"
+
+-// We need a definition of gettid(), but glibc doesn't provide a
+-// wrapper for it.
+-#if defined(__GLIBC__)
+-#include <unistd.h>
+-#include <sys/syscall.h>
-static inline pid_t gettid()
-{
- return (pid_t) syscall(SYS_gettid);
-}
-+
- #endif
- #endif
+-#elif defined(GP_OS_darwin)
+-#include <unistd.h>
+-#include <sys/syscall.h>
+-static inline pid_t gettid()
+-{
+- return (pid_t) syscall(SYS_thread_selfid);
+-}
+-#elif defined(GP_OS_android)
+-#include <unistd.h>
+-#elif defined(GP_OS_windows)
+-#include <windows.h>
+-#include <process.h>
+-#ifndef getpid
+-#define getpid _getpid
+-#endif
+-#endif
+-
+ extern mozilla::LazyLogModule gProfilerLog;
+ // These are for MOZ_LOG="prof:3" or higher. It's the default logging level for
diff --git a/source/xap/seamonkey/seamonkey.i686.triplet.fix.diff b/source/xap/seamonkey/seamonkey.i686.triplet.fix.diff
deleted file mode 100644
index 86a805ec..00000000
--- a/source/xap/seamonkey/seamonkey.i686.triplet.fix.diff
+++ /dev/null
@@ -1,11 +0,0 @@
---- ./mozilla/build/moz.configure/rust.configure.orig 2019-05-26 08:32:14.000000000 -0500
-+++ ./mozilla/build/moz.configure/rust.configure 2019-09-08 22:44:00.615109300 -0500
-@@ -105,7 +105,7 @@
- # OpenBSD
- ('x86_64', 'OpenBSD'): 'x86_64-unknown-openbsd',
- # Linux
-- ('x86', 'Linux'): 'i586-unknown-linux-gnu',
-+ ('x86', 'Linux'): 'i686-unknown-linux-gnu',
- # Linux
- ('x86_64', 'Linux'): 'x86_64-unknown-linux-gnu',
- # OS X and iOS
diff --git a/source/xap/seamonkey/seamonkey.nsstring.patch b/source/xap/seamonkey/seamonkey.nsstring.patch
new file mode 100644
index 00000000..83f5dd87
--- /dev/null
+++ b/source/xap/seamonkey/seamonkey.nsstring.patch
@@ -0,0 +1,24 @@
+# rust-1.39 deprecated the "try!" call in favor of "?" which then breaks
+# nsstring because it treats warnings as errors.
+
+diff -Nrup -U 8 mozilla/xpcom/rust/nsstring/src/lib.rs mozilla-OK/xpcom/rust/nsstring/src/lib.rs
+--- mozilla/xpcom/rust/nsstring/src/lib.rs 2020-02-25 03:10:53.802918476 +0300
++++ mozilla-OK/xpcom/rust/nsstring/src/lib.rs 2020-02-25 00:30:21.593463335 +0300
+@@ -108,17 +108,16 @@
+ //! similar to an `ns[C]String<'static>`, however, it does not have a `Drop`
+ //! implementation.
+ //!
+ //! If this type is dropped in rust, it will not free its backing storage. This
+ //! can be useful when implementing FFI types which contain `ns[C]String` members
+ //! which invoke their member's destructors through C++ code.
+
+ #![allow(non_camel_case_types)]
+-#![deny(warnings)]
+
+ #[macro_use]
+ extern crate bitflags;
+
+ use std::ops::{Deref, DerefMut};
+ use std::marker::PhantomData;
+ use std::borrow;
+ use std::slice;
diff --git a/source/xap/seamonkey/seamonkey.rust.encoding_rs.diff b/source/xap/seamonkey/seamonkey.rust.encoding_rs.diff
new file mode 100644
index 00000000..cf96490d
--- /dev/null
+++ b/source/xap/seamonkey/seamonkey.rust.encoding_rs.diff
@@ -0,0 +1,17 @@
+--- ./mozilla/third_party/rust/encoding_rs/src/utf_16.rs.orig 2020-02-17 17:39:16.000000000 -0600
++++ ./mozilla/third_party/rust/encoding_rs/src/utf_16.rs 2020-02-29 18:36:54.760363683 -0600
+@@ -30,7 +30,7 @@
+ )
+ }
+
+- pub fn additional_from_state(&self) -> usize() {
++ pub fn additional_from_state(&self) -> usize {
+ 1 + if self.lead_byte.is_some() { 1 } else { 0 } +
+ if self.lead_surrogate == 0 { 0 } else { 2 }
+ }
+--- ./mozilla/third_party/rust/encoding_rs/.cargo-checksum.json.orig 2020-02-17 17:39:16.000000000 -0600
++++ ./mozilla/third_party/rust/encoding_rs/.cargo-checksum.json 2020-02-29 20:36:51.768670989 -0600
+@@ -1 +1 @@
+-{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".travis.yml":"4d1af7257c9619f7ae66fc271ba2c1be5f063640ae8ceaa235c8c8aaf32f44ea","CONTRIBUTING.md":"e4ffa92c979c7e6ca7b676842a708ea05b84181327fcde43dfcd8038b678a057","COPYRIGHT":"20d4fff11cca11529df3f02096fbe8ffe350219cdb07cdedea34e6a762866da5","Cargo.toml":"b74676e1affb0a2b528507be488bd9588db646b3b05807dada63cbe7b0747fc6","Ideas.md":"c1be4cc91621f52f38ea7febda7a4bb68086189cacc834c7edac4ba1a9da02fe","LICENSE-APACHE":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","LICENSE-MIT":"74aa8b6d04c36bb640ee81187a3f24a2fa94e36d4c1d4f2ca164c3784ae87a83","README.md":"276d801faf4d6347c3ea32ae252cab95df653c846beaac535c5d70cf32094f5e","generate-encoding-data.py":"0b62de6d3b6368166b78a9259f06dc8d0f558504a0ed866dbe75dc2efb4bf464","rustfmt.toml":"c01c06dfbdfcf30730535aab911d69068febb921e2faef9571ceeb6a5c2a3eab","src/ascii.rs":"240c607d3bad850c57d1e96871d5c0371278ed3923c38354bbb4c8a876c9a515","src/big5.rs":"614d479aabc63007f778d1f776a37b885e13d20b7c6c7a2818a729bde342f8a6","src/data.rs":"412c842c698c3ce1cec4a27ab19ca275372ac28940ac49cdf3e0dad71a2c2812","src/euc_jp.rs":"feda0ade5e1c3e4abd7637c59373b977662007990fd164ea7db1acc502ba3534","src/euc_kr.rs":"23e08359ccbe7602f3a90fce78dc76fd4065c236820ac0d11c9d9325045da0e6","src/gb18030.rs":"aa9de27a41715dfb02a3b9161d86e3775f635f625f70d3abaadcd583ee7022c0","src/handles.rs":"8b0691ab21d638bd20078e33247f13afbc8012ff4b843a2fd03e3314353e8520","src/iso_2022_jp.rs":"285e7cea6df41d182a345a0f394a2348b1c313f0d55ed48c349824f2a6aff526","src/lib.rs":"dad6465f541ccdb171312879999d842dcbf11bc09119d81963df3a20f7d4e474","src/macros.rs":"9ab30e7194f61f268cd7d899cabb06ff9ca7717663926fd583b20334f49ac8d3","src/replacement.rs":"782f03f04d110e9a0656262bf4296aa0ab8199e196cb63239c30d9649996caa4","src/shift_jis.rs":"84df4ff58b60e0827d6c0c7049f2cf19033f2b9e25a9186bcfb0bbb05e87b380","src/simd_funcs.rs":"ff30e10bfb58fb8f56f0cc0b4dbcc4af6b343487562ee279ace8b31afd7bcccc","src/single_byte.rs":"0342a921427ed160f5cbe4532490aff5db00886a36b70273f54d8f6a9dcf6974","src/test_data/big5_in.txt":"4c5a8691f8dc717311889c63894026d2fb62725a86c4208ca274a9cc8d42a503","src/test_data/big5_in_ref.txt":"99d399e17750cf9c7cf30bb253dbfe35b81c4fcbdead93cfa48b1429213473c7","src/test_data/big5_out.txt":"6193ca97c297aa20e09396038d18e938bb7ea331c26f0f2454097296723a0b13","src/test_data/big5_out_ref.txt":"36567691f557df144f6cc520015a87038dfa156f296fcf103b56ae9a718be1fc","src/test_data/euc_kr_in.txt":"c86a7224f3215fa0d04e685622a752fdc72763e8ae076230c7fd62de57ec4074","src/test_data/euc_kr_in_ref.txt":"1f419f4ca47d708b54c73c461545a022ae2e20498fdbf8005a483d752a204883","src/test_data/euc_kr_out.txt":"e7f32e026f70be1e1b58e0047baf7d3d2c520269c4f9b9992e158b4decb0a1a3","src/test_data/euc_kr_out_ref.txt":"c9907857980b20b8e9e3b584482ed6567a2be6185d72237b6322f0404944924e","src/test_data/gb18030_in.txt":"ab7231b2d3e9afacdbd7d7f3b9e5361a7ff9f7e1cfdb4f3bd905b9362b309e53","src/test_data/gb18030_in_ref.txt":"dc5069421adca2043c55f5012b55a76fdff651d22e6e699fd0978f8d5706815c","src/test_data/gb18030_out.txt":"f0208d527f5ca63de7d9a0323be8d5cf12d8a104b2943d92c2701f0c3364dac1","src/test_data/gb18030_out_ref.txt":"6819fe47627e4ea01027003fc514b9f21a1322e732d7f1fb92cc6c5455bc6c07","src/test_data/iso_2022_jp_in.txt":"cd24bbdcb1834e25db54646fbf4c41560a13dc7540f6be3dba4f5d97d44513af","src/test_data/iso_2022_jp_in_ref.txt":"3dc4e6a5e06471942d086b16c9440945e78415f6f3f47e43717e4bc2eac2cdf5","src/test_data/iso_2022_jp_out.txt":"9b6f015329dda6c3f9ee5ce6dbd6fa9c89acc21283e886836c78b8d833480c21","src/test_data/iso_2022_jp_out_ref.txt":"78cb260093a20116ad9a42f43b05d1848c5ab100b6b9a850749809e943884b35","src/test_data/jis0208_in.txt":"6df3030553ffb0a6615bb33dc8ea9dca6d9623a9028e2ffec754ce3c3da824cc","src/test_data/jis0208_in_ref.txt":"3dc4e6a5e06471942d086b16c9440945e78415f6f3f47e43717e4bc2eac2cdf5","src/test_data/jis0208_out.txt":"4ec24477e1675ce750733bdc3c5add1cd27b6bd4ce1f09289564646e9654e857","src/test_data/jis0208_out_ref.txt":"c3e1cef5032b2b1d93a406f31ff940c4e2dfe8859b8b17ca2761fee7a75a0e48","src/test_data/jis0212_in.txt":"c011f0dd72bd7c8cd922df9374ef8d2769a77190514c77f6c62b415852eeb9fe","src/test_data/jis0212_in_ref.txt":"7d9458b3d2f73e7092a7f505c08ce1d233dde18aa679fbcf9889256239cc9e06","src/test_data/shift_jis_in.txt":"02e389ccef0dd2122e63f503899402cb7f797912c2444cc80ab93131116c5524","src/test_data/shift_jis_in_ref.txt":"512f985950ca902e643c88682dba9708b7c38d3c5ec2925168ab00ac94ab19f9","src/test_data/shift_jis_out.txt":"5fbc44da7bf639bf6cfe0fa1fd3eba7102b88f81919c9ea991302712f69426fb","src/test_data/shift_jis_out_ref.txt":"466322c6fed8286c64582731755290c2296508efdd258826e6279686649b481f","src/test_labels_names.rs":"0bcf7eeb8bb33cbc88bd3bd8462437501a43055db02c40a12a15fae8e68dd1cb","src/testing.rs":"60f85c6fb63fd4ab62e90dfa005920e79e0e1885795dc13a7a3c1980507925b1","src/utf_16.rs":"8155c1c0acaab2826ee9f99ba911fbd3125707d797327e630977bc2f3f9b1064","src/utf_8.rs":"14cd64de87d8fc5f814f52f76390bda0b4c705da98e73e376fb424ca02119ba5","src/utf_8_core.rs":"0229de223eef17ad16751a646bcd3839c24f24069d660a4dc61b8a5fad19d16f","src/variant.rs":"93dfec2dcfc9fd9711bb55d48177f4a0e9479c7fbd055f08db3853338569da83","src/x_user_defined.rs":"420fae797ea94e7a51eb005b97621ab32d68a8532c565afc60ecce6bdd84b6bd"},"package":"e00a1b1e95eb46988805ceee6f34cd95c46a6753e290cb3ff0486931989d4a4c"}
+\ No newline at end of file
++{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".travis.yml":"4d1af7257c9619f7ae66fc271ba2c1be5f063640ae8ceaa235c8c8aaf32f44ea","CONTRIBUTING.md":"e4ffa92c979c7e6ca7b676842a708ea05b84181327fcde43dfcd8038b678a057","COPYRIGHT":"20d4fff11cca11529df3f02096fbe8ffe350219cdb07cdedea34e6a762866da5","Cargo.toml":"b74676e1affb0a2b528507be488bd9588db646b3b05807dada63cbe7b0747fc6","Ideas.md":"c1be4cc91621f52f38ea7febda7a4bb68086189cacc834c7edac4ba1a9da02fe","LICENSE-APACHE":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","LICENSE-MIT":"74aa8b6d04c36bb640ee81187a3f24a2fa94e36d4c1d4f2ca164c3784ae87a83","README.md":"276d801faf4d6347c3ea32ae252cab95df653c846beaac535c5d70cf32094f5e","generate-encoding-data.py":"0b62de6d3b6368166b78a9259f06dc8d0f558504a0ed866dbe75dc2efb4bf464","rustfmt.toml":"c01c06dfbdfcf30730535aab911d69068febb921e2faef9571ceeb6a5c2a3eab","src/ascii.rs":"240c607d3bad850c57d1e96871d5c0371278ed3923c38354bbb4c8a876c9a515","src/big5.rs":"614d479aabc63007f778d1f776a37b885e13d20b7c6c7a2818a729bde342f8a6","src/data.rs":"412c842c698c3ce1cec4a27ab19ca275372ac28940ac49cdf3e0dad71a2c2812","src/euc_jp.rs":"feda0ade5e1c3e4abd7637c59373b977662007990fd164ea7db1acc502ba3534","src/euc_kr.rs":"23e08359ccbe7602f3a90fce78dc76fd4065c236820ac0d11c9d9325045da0e6","src/gb18030.rs":"aa9de27a41715dfb02a3b9161d86e3775f635f625f70d3abaadcd583ee7022c0","src/handles.rs":"8b0691ab21d638bd20078e33247f13afbc8012ff4b843a2fd03e3314353e8520","src/iso_2022_jp.rs":"285e7cea6df41d182a345a0f394a2348b1c313f0d55ed48c349824f2a6aff526","src/lib.rs":"dad6465f541ccdb171312879999d842dcbf11bc09119d81963df3a20f7d4e474","src/macros.rs":"9ab30e7194f61f268cd7d899cabb06ff9ca7717663926fd583b20334f49ac8d3","src/replacement.rs":"782f03f04d110e9a0656262bf4296aa0ab8199e196cb63239c30d9649996caa4","src/shift_jis.rs":"84df4ff58b60e0827d6c0c7049f2cf19033f2b9e25a9186bcfb0bbb05e87b380","src/simd_funcs.rs":"ff30e10bfb58fb8f56f0cc0b4dbcc4af6b343487562ee279ace8b31afd7bcccc","src/single_byte.rs":"0342a921427ed160f5cbe4532490aff5db00886a36b70273f54d8f6a9dcf6974","src/test_data/big5_in.txt":"4c5a8691f8dc717311889c63894026d2fb62725a86c4208ca274a9cc8d42a503","src/test_data/big5_in_ref.txt":"99d399e17750cf9c7cf30bb253dbfe35b81c4fcbdead93cfa48b1429213473c7","src/test_data/big5_out.txt":"6193ca97c297aa20e09396038d18e938bb7ea331c26f0f2454097296723a0b13","src/test_data/big5_out_ref.txt":"36567691f557df144f6cc520015a87038dfa156f296fcf103b56ae9a718be1fc","src/test_data/euc_kr_in.txt":"c86a7224f3215fa0d04e685622a752fdc72763e8ae076230c7fd62de57ec4074","src/test_data/euc_kr_in_ref.txt":"1f419f4ca47d708b54c73c461545a022ae2e20498fdbf8005a483d752a204883","src/test_data/euc_kr_out.txt":"e7f32e026f70be1e1b58e0047baf7d3d2c520269c4f9b9992e158b4decb0a1a3","src/test_data/euc_kr_out_ref.txt":"c9907857980b20b8e9e3b584482ed6567a2be6185d72237b6322f0404944924e","src/test_data/gb18030_in.txt":"ab7231b2d3e9afacdbd7d7f3b9e5361a7ff9f7e1cfdb4f3bd905b9362b309e53","src/test_data/gb18030_in_ref.txt":"dc5069421adca2043c55f5012b55a76fdff651d22e6e699fd0978f8d5706815c","src/test_data/gb18030_out.txt":"f0208d527f5ca63de7d9a0323be8d5cf12d8a104b2943d92c2701f0c3364dac1","src/test_data/gb18030_out_ref.txt":"6819fe47627e4ea01027003fc514b9f21a1322e732d7f1fb92cc6c5455bc6c07","src/test_data/iso_2022_jp_in.txt":"cd24bbdcb1834e25db54646fbf4c41560a13dc7540f6be3dba4f5d97d44513af","src/test_data/iso_2022_jp_in_ref.txt":"3dc4e6a5e06471942d086b16c9440945e78415f6f3f47e43717e4bc2eac2cdf5","src/test_data/iso_2022_jp_out.txt":"9b6f015329dda6c3f9ee5ce6dbd6fa9c89acc21283e886836c78b8d833480c21","src/test_data/iso_2022_jp_out_ref.txt":"78cb260093a20116ad9a42f43b05d1848c5ab100b6b9a850749809e943884b35","src/test_data/jis0208_in.txt":"6df3030553ffb0a6615bb33dc8ea9dca6d9623a9028e2ffec754ce3c3da824cc","src/test_data/jis0208_in_ref.txt":"3dc4e6a5e06471942d086b16c9440945e78415f6f3f47e43717e4bc2eac2cdf5","src/test_data/jis0208_out.txt":"4ec24477e1675ce750733bdc3c5add1cd27b6bd4ce1f09289564646e9654e857","src/test_data/jis0208_out_ref.txt":"c3e1cef5032b2b1d93a406f31ff940c4e2dfe8859b8b17ca2761fee7a75a0e48","src/test_data/jis0212_in.txt":"c011f0dd72bd7c8cd922df9374ef8d2769a77190514c77f6c62b415852eeb9fe","src/test_data/jis0212_in_ref.txt":"7d9458b3d2f73e7092a7f505c08ce1d233dde18aa679fbcf9889256239cc9e06","src/test_data/shift_jis_in.txt":"02e389ccef0dd2122e63f503899402cb7f797912c2444cc80ab93131116c5524","src/test_data/shift_jis_in_ref.txt":"512f985950ca902e643c88682dba9708b7c38d3c5ec2925168ab00ac94ab19f9","src/test_data/shift_jis_out.txt":"5fbc44da7bf639bf6cfe0fa1fd3eba7102b88f81919c9ea991302712f69426fb","src/test_data/shift_jis_out_ref.txt":"466322c6fed8286c64582731755290c2296508efdd258826e6279686649b481f","src/test_labels_names.rs":"0bcf7eeb8bb33cbc88bd3bd8462437501a43055db02c40a12a15fae8e68dd1cb","src/testing.rs":"60f85c6fb63fd4ab62e90dfa005920e79e0e1885795dc13a7a3c1980507925b1","src/utf_16.rs":"1d2c40857c946f6eecf724efc60a196865b4d84a59b08b42fbe4576fa8308fd0","src/utf_8.rs":"14cd64de87d8fc5f814f52f76390bda0b4c705da98e73e376fb424ca02119ba5","src/utf_8_core.rs":"0229de223eef17ad16751a646bcd3839c24f24069d660a4dc61b8a5fad19d16f","src/variant.rs":"93dfec2dcfc9fd9711bb55d48177f4a0e9479c7fbd055f08db3853338569da83","src/x_user_defined.rs":"420fae797ea94e7a51eb005b97621ab32d68a8532c565afc60ecce6bdd84b6bd"},"package":"e00a1b1e95eb46988805ceee6f34cd95c46a6753e290cb3ff0486931989d4a4c"}
diff --git a/source/xap/seamonkey/seamonkey.rust14x.diff b/source/xap/seamonkey/seamonkey.rust14x.diff
new file mode 100644
index 00000000..3287eed0
--- /dev/null
+++ b/source/xap/seamonkey/seamonkey.rust14x.diff
@@ -0,0 +1,4279 @@
+diff -u -r --new-file seamonkey-2.53.1.orig/mozilla/netwerk/base/rust-url-capi/Cargo.toml seamonkey-2.53.1/mozilla/netwerk/base/rust-url-capi/Cargo.toml
+--- seamonkey-2.53.1.orig/mozilla/netwerk/base/rust-url-capi/Cargo.toml 2020-02-17 17:37:59.000000000 -0600
++++ seamonkey-2.53.1/mozilla/netwerk/base/rust-url-capi/Cargo.toml 2020-02-29 21:16:23.109772243 -0600
+@@ -8,6 +8,6 @@
+
+ [dependencies]
+ libc = "0.2.0"
+-url = "1.5.1"
++url = "1.7.2"
+ nsstring = { path = "../../../xpcom/rust/nsstring" }
+ nserror = { path = "../../../xpcom/rust/nserror" }
+diff -u -r --new-file seamonkey-2.53.1.orig/mozilla/third_party/rust/url/.cargo-checksum.json seamonkey-2.53.1/mozilla/third_party/rust/url/.cargo-checksum.json
+--- seamonkey-2.53.1.orig/mozilla/third_party/rust/url/.cargo-checksum.json 2020-02-17 17:39:21.000000000 -0600
++++ seamonkey-2.53.1/mozilla/third_party/rust/url/.cargo-checksum.json 2020-02-29 21:15:43.797770564 -0600
+@@ -1 +1 @@
+-{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".travis.yml":"890af214187ffcba4732acb2d1af30d7adb9aade0679e9fdb06baae363240b8e","Cargo.toml":"ec586106c4d0625919a3591fe3ae915043e82c8bfdd1c9e747171ba5e21047e1","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"20c7855c364d57ea4c97889a5e8d98470a9952dade37bd9248b9a54431670e5e","Makefile":"bffd75d34654b2955d4f005f1a5e85c821c90becf1a8a52cbe10121972f43148","README.md":"eb3f4694003f408cbe3c7f3e9fbbc71241defb940cc55a816981f0f0f144c8eb","UPGRADING.md":"fbcc2d39bdf17db0745793db6626fcd5c909dddd4ce13b27566cfabece22c368","appveyor.yml":"c78486dbfbe6ebbf3d808afb9a19f7ec18c4704ce451c6305f0716999b70a1a6","docs/.nojekyll":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","docs/404.html":"f61e6271c1ea1aa113b64b356e994595fa548f0433f89948d747503ad22195cd","docs/index.html":"f61e6271c1ea1aa113b64b356e994595fa548f0433f89948d747503ad22195cd","github.png":"b432fd855efe7c430fe6a57ccf83935c1996f03a7cdc8d6e1b34154b8c43f6ec","rust-url-todo":"1192cee7b6cedf2133d97dc6074b593a1d19b0ee13fff6f28d6329855044e575","src/encoding.rs":"f3e109ca8ec5a9130da50cdfb3003530aedb6dd5a440f0790d76b71f6981119c","src/form_urlencoded.rs":"7ccaef7148e4bc2577154c50f8705db3a055b641269e24c22770f06222321e1e","src/host.rs":"281165d732ea87b6f01a98f7c68ffcb284c41f84b3ab6ed674fb8e57022d1019","src/lib.rs":"bd156e8bcfbd44f0cd52c8b394e03ec63fea012c0bf5ca554521352714838605","src/origin.rs":"7071dcc1070ccfae84cdcd43586b84a9706e35a9a099ff4dde128da0909bd0bc","src/parser.rs":"9d30868f0900586fec6f122a0322598a08116ab0b4c4d8caf5c35a720381a73a","src/path_segments.rs":"7bd3142eaa568863ef44e2255c181239141f9eeee337f889b9ffaaeab4ca669d","src/quirks.rs":"1231f965e22bb3632c22993e2a8d4c7470bcb4a8de25d049f31784303f0def03","src/slicing.rs":"4e539886b23945a92094625f3e531a4bff40daa44240b5d19ee8577478c4f7fe","tests/data.rs":"c333766897f6492fb6583ab5c8a511973b7a55f58ca550799432343da64d5ca7","tests/setters_tests.json":"ebcbdb52e9a4b5a565f8806d52ebc610d46a34df883e10b0be080d026468ff73","tests/unit.rs":"c2f206f433be619414d761d358a2a4a5a46cfe8a4fea5339adec5e9937d78de2","tests/urltestdata.json":"430c74aa3a31afaa57a92805544e00825f4dffe2def98c1e3c212c3db80268af"},"package":"eeb819346883532a271eb626deb43c4a1bb4c4dd47c519bd78137c3e72a4fe27"}
+\ No newline at end of file
++{"files":{"Cargo.toml":"80d575ae6adad93cb0910b385b871e2d92d558078f58a3c8eafe95940d459f6b","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"20c7855c364d57ea4c97889a5e8d98470a9952dade37bd9248b9a54431670e5e","README.md":"eb3f4694003f408cbe3c7f3e9fbbc71241defb940cc55a816981f0f0f144c8eb","UPGRADING.md":"fbcc2d39bdf17db0745793db6626fcd5c909dddd4ce13b27566cfabece22c368","appveyor.yml":"c78486dbfbe6ebbf3d808afb9a19f7ec18c4704ce451c6305f0716999b70a1a6","benches/parse_url.rs":"821ecb051c3c6c40eb3b268ba7337b2988333627d0af0c8e1afc84734ffbbf2b","docs/404.html":"f61e6271c1ea1aa113b64b356e994595fa548f0433f89948d747503ad22195cd","docs/index.html":"f61e6271c1ea1aa113b64b356e994595fa548f0433f89948d747503ad22195cd","src/encoding.rs":"f3e109ca8ec5a9130da50cdfb3003530aedb6dd5a440f0790d76b71f6981119c","src/form_urlencoded.rs":"d8c35e92375cafcd7e12c4f0d5374bab62aa1f333629d55b007a9c3d5c3cb615","src/host.rs":"66a2c0c77a8add2da16bc690fbc82b130cf1367ac655fc36990a214e193a4d6c","src/lib.rs":"e09dcba401018169ee26764e1c2bccf0855a5d935707c2100fd8d8e77a1bbc91","src/origin.rs":"6e4821eb9600a32ef54d05c8e1a7937f6d9b4dd1e3bda7f36c7988f6a2bef78b","src/parser.rs":"76368cbe93308123c014a3502024cf97d97ca61dcfc7b6ecd710073867d6deca","src/path_segments.rs":"7bd3142eaa568863ef44e2255c181239141f9eeee337f889b9ffaaeab4ca669d","src/quirks.rs":"6cf1697bad363532cbcc60917a9b126560ac3ab3e1a77da0abcf4f2a40c8233a","src/slicing.rs":"4e539886b23945a92094625f3e531a4bff40daa44240b5d19ee8577478c4f7fe","tests/data.rs":"f2c1c6d1823e8d21aeeae31c786d7f4ef0d97352a896f8c5aeb03a41fedb9a48","tests/setters_tests.json":"08ddaa632ad19c81e83b904bfaa94bc971f26e2bdfcef27d2f93fd033ad57340","tests/unit.rs":"ead7185710ce06c8d68ea18700618477867ee355656eabcad26cfcfaaad361a0","tests/urltestdata.json":"1b0c7c727d8d7e79dfb0d0aa347ff05675ddb68bc4ead38f83fd8e89bc59cc32"},"package":"dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a"}
+\ No newline at end of file
+diff -u -r --new-file seamonkey-2.53.1.orig/mozilla/third_party/rust/url/.travis.yml seamonkey-2.53.1/mozilla/third_party/rust/url/.travis.yml
+--- seamonkey-2.53.1.orig/mozilla/third_party/rust/url/.travis.yml 2020-02-17 17:39:21.000000000 -0600
++++ seamonkey-2.53.1/mozilla/third_party/rust/url/.travis.yml 1969-12-31 18:00:00.000000000 -0600
+@@ -1,9 +0,0 @@
+-language: rust
+-rust:
+- - nightly
+- - beta
+- - stable
+- - 1.17.0
+-script: make test
+-notifications:
+- webhooks: http://build.servo.org:54856/travis
+diff -u -r --new-file seamonkey-2.53.1.orig/mozilla/third_party/rust/url/Cargo.toml seamonkey-2.53.1/mozilla/third_party/rust/url/Cargo.toml
+--- seamonkey-2.53.1.orig/mozilla/third_party/rust/url/Cargo.toml 2020-02-17 17:39:21.000000000 -0600
++++ seamonkey-2.53.1/mozilla/third_party/rust/url/Cargo.toml 2020-02-29 21:15:43.799770565 -0600
+@@ -1,24 +1,31 @@
+-[package]
++# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
++#
++# When uploading crates to the registry Cargo will automatically
++# "normalize" Cargo.toml files for maximal compatibility
++# with all versions of Cargo and also rewrite `path` dependencies
++# to registry (e.g. crates.io) dependencies
++#
++# If you believe there's an error in this file please file an
++# issue against the rust-lang/cargo repository. If you're
++# editing this file be aware that the upstream Cargo.toml
++# will likely look very different (and much more reasonable)
+
++[package]
+ name = "url"
+-# When updating version, also modify html_root_url in the lib.rs
+-version = "1.5.1"
++version = "1.7.2"
+ authors = ["The rust-url developers"]
+-
+ description = "URL library for Rust, based on the WHATWG URL Standard"
+ documentation = "https://docs.rs/url"
+-repository = "https://github.com/servo/rust-url"
+ readme = "README.md"
+ keywords = ["url", "parser"]
+ categories = ["parser-implementations", "web-programming", "encoding"]
+ license = "MIT/Apache-2.0"
++repository = "https://github.com/servo/rust-url"
++[package.metadata.docs.rs]
++features = ["query_encoding"]
+
+-[badges]
+-travis-ci = { repository = "servo/rust-url" }
+-appveyor = { repository = "servo/rust-url" }
+-
+-[workspace]
+-members = [".", "idna", "percent_encoding", "url_serde"]
++[lib]
++test = false
+
+ [[test]]
+ name = "unit"
+@@ -27,23 +34,50 @@
+ name = "data"
+ harness = false
+
+-[lib]
+-test = false
++[[bench]]
++name = "parse_url"
++harness = false
++[dependencies.encoding]
++version = "0.2"
++optional = true
+
+-[dev-dependencies]
+-rustc-test = "0.1"
+-rustc-serialize = "0.3"
+-serde_json = ">=0.6.1, <0.9"
++[dependencies.heapsize]
++version = ">=0.4.1, <0.5"
++optional = true
++
++[dependencies.idna]
++version = "0.1.0"
++
++[dependencies.matches]
++version = "0.1"
++
++[dependencies.percent-encoding]
++version = "1.0.0"
++
++[dependencies.rustc-serialize]
++version = "0.3"
++optional = true
++
++[dependencies.serde]
++version = ">=0.6.1, <0.9"
++optional = true
++[dev-dependencies.bencher]
++version = "0.1"
++
++[dev-dependencies.rustc-serialize]
++version = "0.3"
++
++[dev-dependencies.rustc-test]
++version = "0.3"
++
++[dev-dependencies.serde_json]
++version = ">=0.6.1, <0.9"
+
+ [features]
+-query_encoding = ["encoding"]
+ heap_size = ["heapsize"]
++query_encoding = ["encoding"]
++[badges.appveyor]
++repository = "Manishearth/rust-url"
+
+-[dependencies]
+-encoding = {version = "0.2", optional = true}
+-heapsize = {version = ">=0.1.1, <0.5", optional = true}
+-idna = { version = "0.1.0", path = "./idna" }
+-matches = "0.1"
+-percent-encoding = { version = "1.0.0", path = "./percent_encoding" }
+-rustc-serialize = {version = "0.3", optional = true}
+-serde = {version = ">=0.6.1, <0.9", optional = true}
++[badges.travis-ci]
++repository = "servo/rust-url"
+diff -u -r --new-file seamonkey-2.53.1.orig/mozilla/third_party/rust/url/Makefile seamonkey-2.53.1/mozilla/third_party/rust/url/Makefile
+--- seamonkey-2.53.1.orig/mozilla/third_party/rust/url/Makefile 2020-02-17 17:39:21.000000000 -0600
++++ seamonkey-2.53.1/mozilla/third_party/rust/url/Makefile 1969-12-31 18:00:00.000000000 -0600
+@@ -1,6 +0,0 @@
+-test:
+- cargo test --features "query_encoding serde rustc-serialize heapsize"
+- (cd idna && cargo test)
+- (cd url_serde && cargo test)
+-
+-.PHONY: test
+diff -u -r --new-file seamonkey-2.53.1.orig/mozilla/third_party/rust/url/benches/parse_url.rs seamonkey-2.53.1/mozilla/third_party/rust/url/benches/parse_url.rs
+--- seamonkey-2.53.1.orig/mozilla/third_party/rust/url/benches/parse_url.rs 1969-12-31 18:00:00.000000000 -0600
++++ seamonkey-2.53.1/mozilla/third_party/rust/url/benches/parse_url.rs 2020-02-29 21:15:43.801770565 -0600
+@@ -0,0 +1,18 @@
++#[macro_use]
++extern crate bencher;
++
++extern crate url;
++
++use bencher::{black_box, Bencher};
++
++use url::Url;
++
++fn short(bench: &mut Bencher) {
++ let url = "https://example.com/bench";
++
++ bench.bytes = url.len() as u64;
++ bench.iter(|| black_box(url).parse::<Url>().unwrap());
++}
++
++benchmark_group!(benches, short);
++benchmark_main!(benches);
+diff -u -r --new-file seamonkey-2.53.1.orig/mozilla/third_party/rust/url/rust-url-todo seamonkey-2.53.1/mozilla/third_party/rust/url/rust-url-todo
+--- seamonkey-2.53.1.orig/mozilla/third_party/rust/url/rust-url-todo 2020-02-17 17:39:21.000000000 -0600
++++ seamonkey-2.53.1/mozilla/third_party/rust/url/rust-url-todo 1969-12-31 18:00:00.000000000 -0600
+@@ -1,14 +0,0 @@
+-* standalone path parsing?
+-* Test setters
+- * Test trim C0/space
+- * Test remove tab & newline
+-
+-
+-
+-#[test]
+-fn test_path_segments() {
+- let mut url = Url::parse("http://example.net").unwrap();
+- url.push_path_segment("foo").unwrap();
+- url.extend_path_segments(&["bar", "b/az"]).unwrap();
+- assert_eq!(url.as_str(), "http://example.net/foo");
+-}
+diff -u -r --new-file seamonkey-2.53.1.orig/mozilla/third_party/rust/url/src/form_urlencoded.rs seamonkey-2.53.1/mozilla/third_party/rust/url/src/form_urlencoded.rs
+--- seamonkey-2.53.1.orig/mozilla/third_party/rust/url/src/form_urlencoded.rs 2020-02-17 17:39:21.000000000 -0600
++++ seamonkey-2.53.1/mozilla/third_party/rust/url/src/form_urlencoded.rs 2020-02-29 21:15:43.802770565 -0600
+@@ -16,6 +16,7 @@
+ use encoding::EncodingOverride;
+ use percent_encoding::{percent_encode_byte, percent_decode};
+ use std::borrow::{Borrow, Cow};
++use std::fmt;
+ use std::str;
+
+
+@@ -216,6 +217,15 @@
+ target: Option<T>,
+ start_position: usize,
+ encoding: EncodingOverride,
++ custom_encoding: Option<SilentDebug<Box<FnMut(&str) -> Cow<[u8]>>>>,
++}
++
++struct SilentDebug<T>(T);
++
++impl<T> fmt::Debug for SilentDebug<T> {
++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++ f.write_str("…")
++ }
+ }
+
+ pub trait Target {
+@@ -247,8 +257,16 @@
+ // * `Serializer` keeps its target in a private field
+ // * Unlike in other `Target` impls, `UrlQuery::finished` does not return `Self`.
+ impl<'a> Target for ::UrlQuery<'a> {
+- fn as_mut_string(&mut self) -> &mut String { &mut self.url.serialization }
+- fn finish(self) -> &'a mut ::Url { self.url }
++ fn as_mut_string(&mut self) -> &mut String {
++ &mut self.url.as_mut().unwrap().serialization
++ }
++
++ fn finish(mut self) -> &'a mut ::Url {
++ let url = self.url.take().unwrap();
++ url.restore_already_parsed_fragment(self.fragment.take());
++ url
++ }
++
+ type Finished = &'a mut ::Url;
+ }
+
+@@ -272,6 +290,7 @@
+ target: Some(target),
+ start_position: start_position,
+ encoding: EncodingOverride::utf8(),
++ custom_encoding: None,
+ }
+ }
+
+@@ -290,11 +309,20 @@
+ self
+ }
+
++ /// Set the character encoding to be used for names and values before percent-encoding.
++ pub fn custom_encoding_override<F>(&mut self, encode: F) -> &mut Self
++ where F: FnMut(&str) -> Cow<[u8]> + 'static
++ {
++ self.custom_encoding = Some(SilentDebug(Box::new(encode)));
++ self
++ }
++
+ /// Serialize and append a name/value pair.
+ ///
+ /// Panics if called after `.finish()`.
+ pub fn append_pair(&mut self, name: &str, value: &str) -> &mut Self {
+- append_pair(string(&mut self.target), self.start_position, self.encoding, name, value);
++ append_pair(string(&mut self.target), self.start_position, self.encoding,
++ &mut self.custom_encoding, name, value);
+ self
+ }
+
+@@ -311,7 +339,8 @@
+ let string = string(&mut self.target);
+ for pair in iter {
+ let &(ref k, ref v) = pair.borrow();
+- append_pair(string, self.start_position, self.encoding, k.as_ref(), v.as_ref());
++ append_pair(string, self.start_position, self.encoding,
++ &mut self.custom_encoding, k.as_ref(), v.as_ref());
+ }
+ }
+ self
+@@ -324,6 +353,8 @@
+ /// Panics if called after `.finish()`.
+ #[cfg(feature = "query_encoding")]
+ pub fn append_charset(&mut self) -> &mut Self {
++ assert!(self.custom_encoding.is_none(),
++ "Cannot use both custom_encoding_override() and append_charset()");
+ {
+ let string = string(&mut self.target);
+ append_separator_if_needed(string, self.start_position);
+@@ -361,9 +392,20 @@
+ }
+
+ fn append_pair(string: &mut String, start_position: usize, encoding: EncodingOverride,
++ custom_encoding: &mut Option<SilentDebug<Box<FnMut(&str) -> Cow<[u8]>>>>,
+ name: &str, value: &str) {
+ append_separator_if_needed(string, start_position);
+- string.extend(byte_serialize(&encoding.encode(name.into())));
++ append_encoded(name, string, encoding, custom_encoding);
+ string.push('=');
+- string.extend(byte_serialize(&encoding.encode(value.into())));
++ append_encoded(value, string, encoding, custom_encoding);
++}
++
++fn append_encoded(s: &str, string: &mut String, encoding: EncodingOverride,
++ custom_encoding: &mut Option<SilentDebug<Box<FnMut(&str) -> Cow<[u8]>>>>) {
++ let bytes = if let Some(SilentDebug(ref mut custom)) = *custom_encoding {
++ custom(s)
++ } else {
++ encoding.encode(s.into())
++ };
++ string.extend(byte_serialize(&bytes));
+ }
+diff -u -r --new-file seamonkey-2.53.1.orig/mozilla/third_party/rust/url/src/host.rs seamonkey-2.53.1/mozilla/third_party/rust/url/src/host.rs
+--- seamonkey-2.53.1.orig/mozilla/third_party/rust/url/src/host.rs 2020-02-17 17:39:21.000000000 -0600
++++ seamonkey-2.53.1/mozilla/third_party/rust/url/src/host.rs 2020-02-29 21:15:07.663769022 -0600
+@@ -13,7 +13,7 @@
+ use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs};
+ use std::vec;
+ use parser::{ParseResult, ParseError};
+-use percent_encoding::percent_decode;
++use percent_encoding::{percent_decode, utf8_percent_encode, SIMPLE_ENCODE_SET};
+ use idna;
+
+ #[derive(Copy, Clone, Debug, Eq, PartialEq)]
+@@ -73,7 +73,9 @@
+ #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
+ pub enum Host<S=String> {
+ /// A DNS domain name, as '.' dot-separated labels.
+- /// Non-ASCII labels are encoded in punycode per IDNA.
++ /// Non-ASCII labels are encoded in punycode per IDNA if this is the host of
++ /// a special URL, or percent encoded for non-special URLs. Hosts for
++ /// non-special URLs are also called opaque hosts.
+ Domain(S),
+
+ /// An IPv4 address.
+@@ -137,7 +139,7 @@
+ impl Host<String> {
+ /// Parse a host: either an IPv6 address in [] square brackets, or a domain.
+ ///
+- /// https://url.spec.whatwg.org/#host-parsing
++ /// <https://url.spec.whatwg.org/#host-parsing>
+ pub fn parse(input: &str) -> Result<Self, ParseError> {
+ if input.starts_with('[') {
+ if !input.ends_with(']') {
+@@ -158,6 +160,23 @@
+ Ok(Host::Domain(domain.into()))
+ }
+ }
++
++ // <https://url.spec.whatwg.org/#concept-opaque-host-parser>
++ pub fn parse_opaque(input: &str) -> Result<Self, ParseError> {
++ if input.starts_with('[') {
++ if !input.ends_with(']') {
++ return Err(ParseError::InvalidIpv6Address)
++ }
++ return parse_ipv6addr(&input[1..input.len() - 1]).map(Host::Ipv6)
++ }
++ if input.find(|c| matches!(c,
++ '\0' | '\t' | '\n' | '\r' | ' ' | '#' | '/' | ':' | '?' | '@' | '[' | '\\' | ']'
++ )).is_some() {
++ return Err(ParseError::InvalidDomainCharacter)
++ }
++ let s = utf8_percent_encode(input, SIMPLE_ENCODE_SET).to_string();
++ Ok(Host::Domain(s))
++ }
+ }
+
+ impl<S: AsRef<str>> fmt::Display for Host<S> {
+@@ -309,8 +328,8 @@
+ }
+ }
+
+-/// https://url.spec.whatwg.org/#ipv4-number-parser
+-fn parse_ipv4number(mut input: &str) -> Result<u32, ()> {
++/// <https://url.spec.whatwg.org/#ipv4-number-parser>
++fn parse_ipv4number(mut input: &str) -> Result<Option<u32>, ()> {
+ let mut r = 10;
+ if input.starts_with("0x") || input.starts_with("0X") {
+ input = &input[2..];
+@@ -319,19 +338,35 @@
+ input = &input[1..];
+ r = 8;
+ }
++
++ // At the moment we can't know the reason why from_str_radix fails
++ // https://github.com/rust-lang/rust/issues/22639
++ // So instead we check if the input looks like a real number and only return
++ // an error when it's an overflow.
++ let valid_number = match r {
++ 8 => input.chars().all(|c| c >= '0' && c <='7'),
++ 10 => input.chars().all(|c| c >= '0' && c <='9'),
++ 16 => input.chars().all(|c| (c >= '0' && c <='9') || (c >='a' && c <= 'f') || (c >= 'A' && c <= 'F')),
++ _ => false
++ };
++
++ if !valid_number {
++ return Ok(None);
++ }
++
+ if input.is_empty() {
+- return Ok(0);
++ return Ok(Some(0));
+ }
+ if input.starts_with('+') {
+- return Err(())
++ return Ok(None);
+ }
+ match u32::from_str_radix(input, r) {
+- Ok(number) => Ok(number),
++ Ok(number) => Ok(Some(number)),
+ Err(_) => Err(()),
+ }
+ }
+
+-/// https://url.spec.whatwg.org/#concept-ipv4-parser
++/// <https://url.spec.whatwg.org/#concept-ipv4-parser>
+ fn parse_ipv4addr(input: &str) -> ParseResult<Option<Ipv4Addr>> {
+ if input.is_empty() {
+ return Ok(None)
+@@ -344,15 +379,19 @@
+ return Ok(None);
+ }
+ let mut numbers: Vec<u32> = Vec::new();
++ let mut overflow = false;
+ for part in parts {
+ if part == "" {
+ return Ok(None);
+ }
+- if let Ok(n) = parse_ipv4number(part) {
+- numbers.push(n);
+- } else {
+- return Ok(None);
+- }
++ match parse_ipv4number(part) {
++ Ok(Some(n)) => numbers.push(n),
++ Ok(None) => return Ok(None),
++ Err(()) => overflow = true
++ };
++ }
++ if overflow {
++ return Err(ParseError::InvalidIpv4Address);
+ }
+ let mut ipv4 = numbers.pop().expect("a non-empty list of numbers");
+ // Equivalent to: ipv4 >= 256 ** (4 − numbers.len())
+@@ -368,7 +407,7 @@
+ Ok(Some(Ipv4Addr::from(ipv4)))
+ }
+
+-/// https://url.spec.whatwg.org/#concept-ipv6-parser
++/// <https://url.spec.whatwg.org/#concept-ipv6-parser>
+ fn parse_ipv6addr(input: &str) -> ParseResult<Ipv6Addr> {
+ let input = input.as_bytes();
+ let len = input.len();
+@@ -423,6 +462,9 @@
+ return Err(ParseError::InvalidIpv6Address)
+ }
+ i = start;
++ if piece_pointer > 6 {
++ return Err(ParseError::InvalidIpv6Address)
++ }
+ is_ip_v4 = true;
+ },
+ b':' => {
+@@ -445,16 +487,24 @@
+ if piece_pointer > 6 {
+ return Err(ParseError::InvalidIpv6Address)
+ }
+- let mut dots_seen = 0;
++ let mut numbers_seen = 0;
+ while i < len {
+- let mut value = None;
++ if numbers_seen > 0 {
++ if numbers_seen < 4 && (i < len && input[i] == b'.') {
++ i += 1
++ } else {
++ return Err(ParseError::InvalidIpv6Address)
++ }
++ }
++
++ let mut ipv4_piece = None;
+ while i < len {
+ let digit = match input[i] {
+ c @ b'0' ... b'9' => c - b'0',
+ _ => break
+ };
+- match value {
+- None => value = Some(digit as u16),
++ match ipv4_piece {
++ None => ipv4_piece = Some(digit as u16),
+ Some(0) => return Err(ParseError::InvalidIpv6Address), // No leading zero
+ Some(ref mut v) => {
+ *v = *v * 10 + digit as u16;
+@@ -465,24 +515,28 @@
+ }
+ i += 1;
+ }
+- if dots_seen < 3 && !(i < len && input[i] == b'.') {
+- return Err(ParseError::InvalidIpv6Address)
+- }
+- pieces[piece_pointer] = if let Some(v) = value {
++
++ pieces[piece_pointer] = if let Some(v) = ipv4_piece {
+ pieces[piece_pointer] * 0x100 + v
+ } else {
+ return Err(ParseError::InvalidIpv6Address)
+ };
+- if dots_seen == 1 || dots_seen == 3 {
++ numbers_seen += 1;
++
++ if numbers_seen == 2 || numbers_seen == 4 {
+ piece_pointer += 1;
+ }
+- i += 1;
+- if dots_seen == 3 && i < len {
+- return Err(ParseError::InvalidIpv6Address)
+- }
+- dots_seen += 1;
++ }
++
++ if numbers_seen != 4 {
++ return Err(ParseError::InvalidIpv6Address)
+ }
+ }
++
++ if i < len {
++ return Err(ParseError::InvalidIpv6Address)
++ }
++
+ match compress_pointer {
+ Some(compress_pointer) => {
+ let mut swaps = piece_pointer - compress_pointer;
+diff -u -r --new-file seamonkey-2.53.1.orig/mozilla/third_party/rust/url/src/lib.rs seamonkey-2.53.1/mozilla/third_party/rust/url/src/lib.rs
+--- seamonkey-2.53.1.orig/mozilla/third_party/rust/url/src/lib.rs 2020-02-17 17:39:21.000000000 -0600
++++ seamonkey-2.53.1/mozilla/third_party/rust/url/src/lib.rs 2020-02-29 21:15:43.804770565 -0600
+@@ -104,7 +104,7 @@
+ # run().unwrap();
+ */
+
+-#![doc(html_root_url = "https://docs.rs/url/1.5.1")]
++#![doc(html_root_url = "https://docs.rs/url/1.7.0")]
+
+ #[cfg(feature="rustc-serialize")] extern crate rustc_serialize;
+ #[macro_use] extern crate matches;
+@@ -112,12 +112,13 @@
+ #[cfg(feature="heapsize")] #[macro_use] extern crate heapsize;
+
+ pub extern crate idna;
++#[macro_use]
+ pub extern crate percent_encoding;
+
+ use encoding::EncodingOverride;
+ #[cfg(feature = "heapsize")] use heapsize::HeapSizeOf;
+ use host::HostInternal;
+-use parser::{Parser, Context, SchemeType, to_u32};
++use parser::{Parser, Context, SchemeType, to_u32, ViolationFn};
+ use percent_encoding::{PATH_SEGMENT_ENCODE_SET, USERINFO_ENCODE_SET,
+ percent_encode, percent_decode, utf8_percent_encode};
+ use std::borrow::Borrow;
+@@ -135,7 +136,7 @@
+ pub use origin::{Origin, OpaqueOrigin};
+ pub use host::{Host, HostAndPort, SocketAddrs};
+ pub use path_segments::PathSegmentsMut;
+-pub use parser::ParseError;
++pub use parser::{ParseError, SyntaxViolation};
+ pub use slicing::Position;
+
+ mod encoding;
+@@ -186,7 +187,7 @@
+ pub struct ParseOptions<'a> {
+ base_url: Option<&'a Url>,
+ encoding_override: encoding::EncodingOverride,
+- log_syntax_violation: Option<&'a Fn(&'static str)>,
++ violation_fn: ViolationFn<'a>,
+ }
+
+ impl<'a> ParseOptions<'a> {
+@@ -209,9 +210,47 @@
+ self
+ }
+
+- /// Call the provided function or closure on non-fatal parse errors.
++ /// Call the provided function or closure on non-fatal parse errors, passing
++ /// a static string description. This method is deprecated in favor of
++ /// `syntax_violation_callback` and is implemented as an adaptor for the
++ /// latter, passing the `SyntaxViolation` description. Only the last value
++ /// passed to either method will be used by a parser.
++ #[deprecated]
+ pub fn log_syntax_violation(mut self, new: Option<&'a Fn(&'static str)>) -> Self {
+- self.log_syntax_violation = new;
++ self.violation_fn = match new {
++ Some(f) => ViolationFn::OldFn(f),
++ None => ViolationFn::NoOp
++ };
++ self
++ }
++
++ /// Call the provided function or closure for a non-fatal `SyntaxViolation`
++ /// when it occurs during parsing. Note that since the provided function is
++ /// `Fn`, the caller might need to utilize _interior mutability_, such as with
++ /// a `RefCell`, to collect the violations.
++ ///
++ /// ## Example
++ /// ```
++ /// use std::cell::RefCell;
++ /// use url::{Url, SyntaxViolation};
++ /// # use url::ParseError;
++ /// # fn run() -> Result<(), url::ParseError> {
++ /// let violations = RefCell::new(Vec::new());
++ /// let url = Url::options()
++ /// .syntax_violation_callback(Some(&|v| violations.borrow_mut().push(v)))
++ /// .parse("https:////example.com")?;
++ /// assert_eq!(url.as_str(), "https://example.com/");
++ /// assert_eq!(violations.into_inner(),
++ /// vec!(SyntaxViolation::ExpectedDoubleSlash));
++ /// # Ok(())
++ /// # }
++ /// # run().unwrap();
++ /// ```
++ pub fn syntax_violation_callback(mut self, new: Option<&'a Fn(SyntaxViolation)>) -> Self {
++ self.violation_fn = match new {
++ Some(f) => ViolationFn::NewFn(f),
++ None => ViolationFn::NoOp
++ };
+ self
+ }
+
+@@ -221,7 +260,7 @@
+ serialization: String::with_capacity(input.len()),
+ base_url: self.base_url,
+ query_encoding_override: self.encoding_override,
+- log_syntax_violation: self.log_syntax_violation,
++ violation_fn: self.violation_fn,
+ context: Context::UrlParser,
+ }.parse_url(input)
+ }
+@@ -229,11 +268,12 @@
+
+ impl<'a> Debug for ParseOptions<'a> {
+ fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+- write!(f, "ParseOptions {{ base_url: {:?}, encoding_override: {:?}, log_syntax_violation: ", self.base_url, self.encoding_override)?;
+- match self.log_syntax_violation {
+- Some(_) => write!(f, "Some(Fn(&'static str)) }}"),
+- None => write!(f, "None }}")
+- }
++ write!(f,
++ "ParseOptions {{ base_url: {:?}, encoding_override: {:?}, \
++ violation_fn: {:?} }}",
++ self.base_url,
++ self.encoding_override,
++ self.violation_fn)
+ }
+ }
+
+@@ -252,6 +292,13 @@
+ /// # }
+ /// # run().unwrap();
+ /// ```
++ ///
++ /// # Errors
++ ///
++ /// If the function can not parse an absolute URL from the given string,
++ /// a [`ParseError`] variant will be returned.
++ ///
++ /// [`ParseError`]: enum.ParseError.html
+ #[inline]
+ pub fn parse(input: &str) -> Result<Url, ::ParseError> {
+ Url::options().parse(input)
+@@ -274,6 +321,13 @@
+ /// # }
+ /// # run().unwrap();
+ /// ```
++ ///
++ /// # Errors
++ ///
++ /// If the function can not parse an absolute URL from the given string,
++ /// a [`ParseError`] variant will be returned.
++ ///
++ /// [`ParseError`]: enum.ParseError.html
+ #[inline]
+ pub fn parse_with_params<I, K, V>(input: &str, iter: I) -> Result<Url, ::ParseError>
+ where I: IntoIterator,
+@@ -301,7 +355,7 @@
+ /// ```rust
+ /// use url::Url;
+ /// # use url::ParseError;
+- ///
++ ///
+ /// # fn run() -> Result<(), ParseError> {
+ /// let base = Url::parse("https://example.net/a/b.html")?;
+ /// let url = base.join("c.png")?;
+@@ -314,6 +368,13 @@
+ /// # }
+ /// # run().unwrap();
+ /// ```
++ ///
++ /// # Errors
++ ///
++ /// If the function can not parse an URL from the given string
++ /// with this URL as the base URL, a [`ParseError`] variant will be returned.
++ ///
++ /// [`ParseError`]: enum.ParseError.html
+ #[inline]
+ pub fn join(&self, input: &str) -> Result<Url, ::ParseError> {
+ Url::options().base_url(Some(self)).parse(input)
+@@ -342,7 +403,7 @@
+ ParseOptions {
+ base_url: None,
+ encoding_override: EncodingOverride::utf8(),
+- log_syntax_violation: None,
++ violation_fn: ViolationFn::NoOp,
+ }
+ }
+
+@@ -500,7 +561,7 @@
+ Ok(())
+ }
+
+- /// Return the origin of this URL (https://url.spec.whatwg.org/#origin)
++ /// Return the origin of this URL (<https://url.spec.whatwg.org/#origin>)
+ ///
+ /// Note: this returns an opaque origin for `file:` URLs, which causes
+ /// `url.origin() != url.origin()`.
+@@ -1156,11 +1217,11 @@
+ /// assert_eq!(url.as_str(), "https://example.com/data.csv");
+
+ /// url.set_fragment(Some("cell=4,1-6,2"));
+- /// assert_eq!(url.as_str(), "https://example.com/data.csv#cell=4,1-6,2");
++ /// assert_eq!(url.as_str(), "https://example.com/data.csv#cell=4,1-6,2");
+ /// assert_eq!(url.fragment(), Some("cell=4,1-6,2"));
+ ///
+ /// url.set_fragment(None);
+- /// assert_eq!(url.as_str(), "https://example.com/data.csv");
++ /// assert_eq!(url.as_str(), "https://example.com/data.csv");
+ /// assert!(url.fragment().is_none());
+ /// # Ok(())
+ /// # }
+@@ -1213,7 +1274,7 @@
+ /// assert_eq!(url.as_str(), "https://example.com/products");
+ ///
+ /// url.set_query(Some("page=2"));
+- /// assert_eq!(url.as_str(), "https://example.com/products?page=2");
++ /// assert_eq!(url.as_str(), "https://example.com/products?page=2");
+ /// assert_eq!(url.query(), Some("page=2"));
+ /// # Ok(())
+ /// # }
+@@ -1283,7 +1344,7 @@
+ self.serialization.push('?');
+ }
+
+- let query = UrlQuery { url: self, fragment: fragment };
++ let query = UrlQuery { url: Some(self), fragment: fragment };
+ form_urlencoded::Serializer::for_suffix(query, query_start + "?".len())
+ }
+
+@@ -1309,12 +1370,12 @@
+ /// # fn run() -> Result<(), ParseError> {
+ /// let mut url = Url::parse("https://example.com")?;
+ /// url.set_path("api/comments");
+- /// assert_eq!(url.as_str(), "https://example.com/api/comments");
++ /// assert_eq!(url.as_str(), "https://example.com/api/comments");
+ /// assert_eq!(url.path(), "/api/comments");
+ ///
+ /// let mut url = Url::parse("https://example.com/api")?;
+ /// url.set_path("data/report.csv");
+- /// assert_eq!(url.as_str(), "https://example.com/data/report.csv");
++ /// assert_eq!(url.as_str(), "https://example.com/data/report.csv");
+ /// assert_eq!(url.path(), "/data/report.csv");
+ /// # Ok(())
+ /// # }
+@@ -1406,7 +1467,8 @@
+ /// # run().unwrap();
+ /// ```
+ pub fn set_port(&mut self, mut port: Option<u16>) -> Result<(), ()> {
+- if !self.has_host() || self.scheme() == "file" {
++ // has_host implies !cannot_be_a_base
++ if !self.has_host() || self.host() == Some(Host::Domain("")) || self.scheme() == "file" {
+ return Err(())
+ }
+ if port.is_some() && port == parser::default_port(self.scheme()) {
+@@ -1448,9 +1510,6 @@
+
+ /// Change this URL’s host.
+ ///
+- /// If this URL is cannot-be-a-base or there is an error parsing the given `host`,
+- /// do nothing and return `Err`.
+- ///
+ /// Removing the host (calling this with `None`)
+ /// will also remove any username, password, and port number.
+ ///
+@@ -1477,7 +1536,7 @@
+ /// ```
+ /// use url::Url;
+ /// # use url::ParseError;
+- ///
++ ///
+ /// # fn run() -> Result<(), ParseError> {
+ /// let mut url = Url::parse("foo://example.net")?;
+ /// let result = url.set_host(None);
+@@ -1493,7 +1552,7 @@
+ /// ```
+ /// use url::Url;
+ /// # use url::ParseError;
+- ///
++ ///
+ /// # fn run() -> Result<(), ParseError> {
+ /// let mut url = Url::parse("https://example.net")?;
+ /// let result = url.set_host(None);
+@@ -1509,7 +1568,7 @@
+ /// ```
+ /// use url::Url;
+ /// # use url::ParseError;
+- ///
++ ///
+ /// # fn run() -> Result<(), ParseError> {
+ /// let mut url = Url::parse("mailto:rms@example.net")?;
+ ///
+@@ -1524,6 +1583,13 @@
+ /// # }
+ /// # run().unwrap();
+ /// ```
++ ///
++ /// # Errors
++ ///
++ /// If this URL is cannot-be-a-base or there is an error parsing the given `host`,
++ /// a [`ParseError`] variant will be returned.
++ ///
++ /// [`ParseError`]: enum.ParseError.html
+ pub fn set_host(&mut self, host: Option<&str>) -> Result<(), ParseError> {
+ if self.cannot_be_a_base() {
+ return Err(ParseError::SetHostOnCannotBeABaseUrl)
+@@ -1533,7 +1599,11 @@
+ if host == "" && SchemeType::from(self.scheme()).is_special() {
+ return Err(ParseError::EmptyHost);
+ }
+- self.set_host_internal(Host::parse(host)?, None)
++ if SchemeType::from(self.scheme()).is_special() {
++ self.set_host_internal(Host::parse(host)?, None)
++ } else {
++ self.set_host_internal(Host::parse_opaque(host)?, None)
++ }
+ } else if self.has_host() {
+ if SchemeType::from(self.scheme()).is_special() {
+ return Err(ParseError::EmptyHost)
+@@ -1666,7 +1736,8 @@
+ /// # run().unwrap();
+ /// ```
+ pub fn set_password(&mut self, password: Option<&str>) -> Result<(), ()> {
+- if !self.has_host() {
++ // has_host implies !cannot_be_a_base
++ if !self.has_host() || self.host() == Some(Host::Domain("")) || self.scheme() == "file" {
+ return Err(())
+ }
+ if let Some(password) = password {
+@@ -1732,21 +1803,23 @@
+ /// ```
+ ///
+ /// Setup username to user1
++ ///
+ /// ```rust
+ /// use url::{Url, ParseError};
+ ///
+ /// # fn run() -> Result<(), ParseError> {
+- /// let mut url = Url::parse("ftp://:secre1@example.com")?;
++ /// let mut url = Url::parse("ftp://:secre1@example.com/")?;
+ /// let result = url.set_username("user1");
+ /// assert!(result.is_ok());
+ /// assert_eq!(url.username(), "user1");
+- /// assert_eq!(url.as_str(), "ftp://user1:secre1@example.com");
++ /// assert_eq!(url.as_str(), "ftp://user1:secre1@example.com/");
+ /// # Ok(())
+ /// # }
+ /// # run().unwrap();
+ /// ```
+ pub fn set_username(&mut self, username: &str) -> Result<(), ()> {
+- if !self.has_host() {
++ // has_host implies !cannot_be_a_base
++ if !self.has_host() || self.host() == Some(Host::Domain("")) || self.scheme() == "file" {
+ return Err(())
+ }
+ let username_start = self.scheme_end + 3;
+@@ -1805,7 +1878,7 @@
+ /// ```
+ /// use url::Url;
+ /// # use url::ParseError;
+- ///
++ ///
+ /// # fn run() -> Result<(), ParseError> {
+ /// let mut url = Url::parse("https://example.net")?;
+ /// let result = url.set_scheme("foo");
+@@ -1822,7 +1895,7 @@
+ /// ```
+ /// use url::Url;
+ /// # use url::ParseError;
+- ///
++ ///
+ /// # fn run() -> Result<(), ParseError> {
+ /// let mut url = Url::parse("https://example.net")?;
+ /// let result = url.set_scheme("foõ");
+@@ -1838,7 +1911,7 @@
+ /// ```
+ /// use url::Url;
+ /// # use url::ParseError;
+- ///
++ ///
+ /// # fn run() -> Result<(), ParseError> {
+ /// let mut url = Url::parse("mailto:rms@example.net")?;
+ /// let result = url.set_scheme("https");
+@@ -1887,7 +1960,7 @@
+ /// ```
+ /// # if cfg!(unix) {
+ /// use url::Url;
+- ///
++ ///
+ /// # fn run() -> Result<(), ()> {
+ /// let url = Url::from_file_path("/tmp/foo.txt")?;
+ /// assert_eq!(url.as_str(), "file:///tmp/foo.txt");
+@@ -1902,6 +1975,7 @@
+ /// # run().unwrap();
+ /// # }
+ /// ```
++ #[cfg(any(unix, windows, target_os="redox"))]
+ pub fn from_file_path<P: AsRef<Path>>(path: P) -> Result<Url, ()> {
+ let mut serialization = "file://".to_owned();
+ let host_start = serialization.len() as u32;
+@@ -1937,6 +2011,7 @@
+ ///
+ /// Note that `std::path` does not consider trailing slashes significant
+ /// and usually does not include them (e.g. in `Path::parent()`).
++ #[cfg(any(unix, windows, target_os="redox"))]
+ pub fn from_directory_path<P: AsRef<Path>>(path: P) -> Result<Url, ()> {
+ let mut url = Url::from_file_path(path)?;
+ if !url.serialization.ends_with('/') {
+@@ -2018,6 +2093,7 @@
+ /// (That is, if the percent-decoded path contains a NUL byte or,
+ /// for a Windows path, is not UTF-8.)
+ #[inline]
++ #[cfg(any(unix, windows, target_os="redox"))]
+ pub fn to_file_path(&self) -> Result<PathBuf, ()> {
+ if let Some(segments) = self.path_segments() {
+ let host = match self.host() {
+@@ -2264,6 +2340,7 @@
+ Ok((host_end, host_internal))
+ }
+
++
+ #[cfg(any(unix, target_os = "redox"))]
+ fn file_url_segments_to_pathbuf(host: Option<&str>, segments: str::Split<char>) -> Result<PathBuf, ()> {
+ use std::ffi::OsStr;
+@@ -2347,13 +2424,15 @@
+ /// Implementation detail of `Url::query_pairs_mut`. Typically not used directly.
+ #[derive(Debug)]
+ pub struct UrlQuery<'a> {
+- url: &'a mut Url,
++ url: Option<&'a mut Url>,
+ fragment: Option<String>,
+ }
+
+ impl<'a> Drop for UrlQuery<'a> {
+ fn drop(&mut self) {
+- self.url.restore_already_parsed_fragment(self.fragment.take())
++ if let Some(url) = self.url.take() {
++ url.restore_already_parsed_fragment(self.fragment.take())
++ }
+ }
+ }
+
+diff -u -r --new-file seamonkey-2.53.1.orig/mozilla/third_party/rust/url/src/origin.rs seamonkey-2.53.1/mozilla/third_party/rust/url/src/origin.rs
+--- seamonkey-2.53.1.orig/mozilla/third_party/rust/url/src/origin.rs 2020-02-17 17:39:21.000000000 -0600
++++ seamonkey-2.53.1/mozilla/third_party/rust/url/src/origin.rs 2020-02-29 21:14:51.284768322 -0600
+@@ -49,7 +49,7 @@
+ /// - If the scheme is anything else, the origin is opaque, meaning
+ /// the URL does not have the same origin as any other URL.
+ ///
+-/// For more information see https://url.spec.whatwg.org/#origin
++/// For more information see <https://url.spec.whatwg.org/#origin>
+ #[derive(PartialEq, Eq, Hash, Clone, Debug)]
+ pub enum Origin {
+ /// A globally unique identifier
+@@ -86,7 +86,7 @@
+ matches!(*self, Origin::Tuple(..))
+ }
+
+- /// https://html.spec.whatwg.org/multipage/#ascii-serialisation-of-an-origin
++ /// <https://html.spec.whatwg.org/multipage/#ascii-serialisation-of-an-origin>
+ pub fn ascii_serialization(&self) -> String {
+ match *self {
+ Origin::Opaque(_) => "null".to_owned(),
+@@ -100,7 +100,7 @@
+ }
+ }
+
+- /// https://html.spec.whatwg.org/multipage/#unicode-serialisation-of-an-origin
++ /// <https://html.spec.whatwg.org/multipage/#unicode-serialisation-of-an-origin>
+ pub fn unicode_serialization(&self) -> String {
+ match *self {
+ Origin::Opaque(_) => "null".to_owned(),
+diff -u -r --new-file seamonkey-2.53.1.orig/mozilla/third_party/rust/url/src/parser.rs seamonkey-2.53.1/mozilla/third_party/rust/url/src/parser.rs
+--- seamonkey-2.53.1.orig/mozilla/third_party/rust/url/src/parser.rs 2020-02-17 17:39:21.000000000 -0600
++++ seamonkey-2.53.1/mozilla/third_party/rust/url/src/parser.rs 2020-02-29 21:15:43.806770565 -0600
+@@ -6,7 +6,9 @@
+ // option. This file may not be copied, modified, or distributed
+ // except according to those terms.
+
++#[allow(unused_imports, deprecated)]
+ use std::ascii::AsciiExt;
++
+ use std::error::Error;
+ use std::fmt::{self, Formatter, Write};
+ use std::str;
+@@ -20,6 +22,12 @@
+ PATH_SEGMENT_ENCODE_SET
+ };
+
++define_encode_set! {
++ // The backslash (\) character is treated as a path separator in special URLs
++ // so it needs to be additionally escaped in that case.
++ pub SPECIAL_PATH_SEGMENT_ENCODE_SET = [PATH_SEGMENT_ENCODE_SET] | {'\\'}
++}
++
+ pub type ParseResult<T> = Result<T, ParseError>;
+
+ macro_rules! simple_enum_error {
+@@ -70,6 +78,54 @@
+ fn from(_: ::idna::uts46::Errors) -> ParseError { ParseError::IdnaError }
+ }
+
++macro_rules! syntax_violation_enum {
++ ($($name: ident => $description: expr,)+) => {
++ /// Non-fatal syntax violations that can occur during parsing.
++ #[derive(PartialEq, Eq, Clone, Copy, Debug)]
++ pub enum SyntaxViolation {
++ $(
++ $name,
++ )+
++ }
++
++ impl SyntaxViolation {
++ pub fn description(&self) -> &'static str {
++ match *self {
++ $(
++ SyntaxViolation::$name => $description,
++ )+
++ }
++ }
++ }
++ }
++}
++
++syntax_violation_enum! {
++ Backslash => "backslash",
++ C0SpaceIgnored =>
++ "leading or trailing control or space character are ignored in URLs",
++ EmbeddedCredentials =>
++ "embedding authentication information (username or password) \
++ in an URL is not recommended",
++ ExpectedDoubleSlash => "expected //",
++ ExpectedFileDoubleSlash => "expected // after file:",
++ FileWithHostAndWindowsDrive => "file: with host and Windows drive letter",
++ NonUrlCodePoint => "non-URL code point",
++ NullInFragment => "NULL characters are ignored in URL fragment identifiers",
++ PercentDecode => "expected 2 hex digits after %",
++ TabOrNewlineIgnored => "tabs or newlines are ignored in URLs",
++ UnencodedAtSign => "unencoded @ sign in username or password",
++}
++
++#[cfg(feature = "heapsize")]
++known_heap_size!(0, SyntaxViolation);
++
++impl fmt::Display for SyntaxViolation {
++ fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
++ self.description().fmt(fmt)
++ }
++}
++
+ #[derive(Copy, Clone)]
+ pub enum SchemeType {
+ File,
+@@ -112,18 +168,17 @@
+
+ impl<'i> Input<'i> {
+ pub fn new(input: &'i str) -> Self {
+- Input::with_log(input, None)
++ Input::with_log(input, ViolationFn::NoOp)
+ }
+
+- pub fn with_log(original_input: &'i str, log_syntax_violation: Option<&Fn(&'static str)>)
+- -> Self {
++ pub fn with_log(original_input: &'i str, vfn: ViolationFn) -> Self {
+ let input = original_input.trim_matches(c0_control_or_space);
+- if let Some(log) = log_syntax_violation {
++ if vfn.is_set() {
+ if input.len() < original_input.len() {
+- log("leading or trailing control or space character are ignored in URLs")
++ vfn.call(SyntaxViolation::C0SpaceIgnored)
+ }
+ if input.chars().any(|c| matches!(c, '\t' | '\n' | '\r')) {
+- log("tabs or newlines are ignored in URLs")
++ vfn.call(SyntaxViolation::TabOrNewlineIgnored)
+ }
+ }
+ Input { chars: input.chars() }
+@@ -216,11 +271,60 @@
+ }
+ }
+
++/// Wrapper for syntax violation callback functions.
++#[derive(Copy, Clone)]
++pub enum ViolationFn<'a> {
++ NewFn(&'a (Fn(SyntaxViolation) + 'a)),
++ OldFn(&'a (Fn(&'static str) + 'a)),
++ NoOp
++}
++
++impl<'a> ViolationFn<'a> {
++ /// Call with a violation.
++ pub fn call(self, v: SyntaxViolation) {
++ match self {
++ ViolationFn::NewFn(f) => f(v),
++ ViolationFn::OldFn(f) => f(v.description()),
++ ViolationFn::NoOp => {}
++ }
++ }
++
++ /// Call with a violation, if provided test returns true. Avoids
++ /// the test entirely if `NoOp`.
++ pub fn call_if<F>(self, v: SyntaxViolation, test: F)
++ where F: Fn() -> bool
++ {
++ match self {
++ ViolationFn::NewFn(f) => if test() { f(v) },
++ ViolationFn::OldFn(f) => if test() { f(v.description()) },
++ ViolationFn::NoOp => {} // avoid test
++ }
++ }
++
++ /// True if not `NoOp`
++ pub fn is_set(self) -> bool {
++ match self {
++ ViolationFn::NoOp => false,
++ _ => true
++ }
++ }
++}
++
++impl<'a> fmt::Debug for ViolationFn<'a> {
++ fn fmt(&self, f: &mut Formatter) -> fmt::Result {
++ match *self {
++ ViolationFn::NewFn(_) => write!(f, "NewFn(Fn(SyntaxViolation))"),
++ ViolationFn::OldFn(_) => write!(f, "OldFn(Fn(&'static str))"),
++ ViolationFn::NoOp => write!(f, "NoOp")
++ }
++ }
++}
++
+ pub struct Parser<'a> {
+ pub serialization: String,
+ pub base_url: Option<&'a Url>,
+ pub query_encoding_override: EncodingOverride,
+- pub log_syntax_violation: Option<&'a Fn(&'static str)>,
++ pub violation_fn: ViolationFn<'a>,
+ pub context: Context,
+ }
+
+@@ -237,29 +341,14 @@
+ serialization: serialization,
+ base_url: None,
+ query_encoding_override: EncodingOverride::utf8(),
+- log_syntax_violation: None,
++ violation_fn: ViolationFn::NoOp,
+ context: Context::Setter,
+ }
+ }
+
+- fn syntax_violation(&self, reason: &'static str) {
+- if let Some(log) = self.log_syntax_violation {
+- log(reason)
+- }
+- }
+-
+- fn syntax_violation_if<F: Fn() -> bool>(&self, reason: &'static str, test: F) {
+- // Skip test if not logging.
+- if let Some(log) = self.log_syntax_violation {
+- if test() {
+- log(reason)
+- }
+- }
+- }
+-
+ /// https://url.spec.whatwg.org/#concept-basic-url-parser
+ pub fn parse_url(mut self, input: &str) -> ParseResult<Url> {
+- let input = Input::with_log(input, self.log_syntax_violation);
++ let input = Input::with_log(input, self.violation_fn);
+ if let Ok(remaining) = self.parse_scheme(input.clone()) {
+ return self.parse_with_scheme(remaining)
+ }
+@@ -310,12 +399,13 @@
+ }
+
+ fn parse_with_scheme(mut self, input: Input) -> ParseResult<Url> {
++ use SyntaxViolation::{ExpectedFileDoubleSlash, ExpectedDoubleSlash};
+ let scheme_end = to_u32(self.serialization.len())?;
+ let scheme_type = SchemeType::from(&self.serialization);
+ self.serialization.push(':');
+ match scheme_type {
+ SchemeType::File => {
+- self.syntax_violation_if("expected // after file:", || !input.starts_with("//"));
++ self.violation_fn.call_if(ExpectedFileDoubleSlash, || !input.starts_with("//"));
+ let base_file_url = self.base_url.and_then(|base| {
+ if base.scheme() == "file" { Some(base) } else { None }
+ });
+@@ -335,7 +425,7 @@
+ }
+ }
+ // special authority slashes state
+- self.syntax_violation_if("expected //", || {
++ self.violation_fn.call_if(ExpectedDoubleSlash, || {
+ input.clone().take_while(|&c| matches!(c, '/' | '\\'))
+ .collect::<String>() != "//"
+ });
+@@ -371,6 +461,7 @@
+ }
+
+ fn parse_file(mut self, input: Input, mut base_file_url: Option<&Url>) -> ParseResult<Url> {
++ use SyntaxViolation::Backslash;
+ // file state
+ debug_assert!(self.serialization.is_empty());
+ let (first_char, input_after_first_char) = input.split_first();
+@@ -451,6 +542,7 @@
+ let scheme_end = "file".len() as u32;
+ let path_start = "file://".len() as u32;
+ let fragment_start = "file:///".len() as u32;
++ self.serialization.push('#');
+ self.parse_fragment(input_after_first_char);
+ Ok(Url {
+ serialization: self.serialization,
+@@ -467,18 +559,18 @@
+ }
+ }
+ Some('/') | Some('\\') => {
+- self.syntax_violation_if("backslash", || first_char == Some('\\'));
++ self.violation_fn.call_if(Backslash, || first_char == Some('\\'));
+ // file slash state
+ let (next_char, input_after_next_char) = input_after_first_char.split_first();
+- self.syntax_violation_if("backslash", || next_char == Some('\\'));
++ self.violation_fn.call_if(Backslash, || next_char == Some('\\'));
+ if matches!(next_char, Some('/') | Some('\\')) {
+ // file host state
+ self.serialization.push_str("file://");
+ let scheme_end = "file".len() as u32;
+ let host_start = "file://".len() as u32;
+- let (path_start, host, remaining) =
++ let (path_start, mut host, remaining) =
+ self.parse_file_host(input_after_next_char)?;
+- let host_end = to_u32(self.serialization.len())?;
++ let mut host_end = to_u32(self.serialization.len())?;
+ let mut has_host = !matches!(host, HostInternal::None);
+ let remaining = if path_start {
+ self.parse_path_start(SchemeType::File, &mut has_host, remaining)
+@@ -487,7 +579,13 @@
+ self.serialization.push('/');
+ self.parse_path(SchemeType::File, &mut has_host, path_start, remaining)
+ };
+- // FIXME: deal with has_host
++ // For file URLs that have a host and whose path starts
++ // with the windows drive letter we just remove the host.
++ if !has_host {
++ self.serialization.drain(host_start as usize..host_end as usize);
++ host_end = host_start;
++ host = HostInternal::None;
++ }
+ let (query_start, fragment_start) =
+ self.parse_query_and_fragment(scheme_end, remaining)?;
+ Ok(Url {
+@@ -616,7 +714,7 @@
+ Some('/') | Some('\\') => {
+ let (slashes_count, remaining) = input.count_matching(|c| matches!(c, '/' | '\\'));
+ if slashes_count >= 2 {
+- self.syntax_violation_if("expected //", || {
++ self.violation_fn.call_if(SyntaxViolation::ExpectedDoubleSlash, || {
+ input.clone().take_while(|&c| matches!(c, '/' | '\\'))
+ .collect::<String>() != "//"
+ });
+@@ -680,11 +778,9 @@
+ match c {
+ '@' => {
+ if last_at.is_some() {
+- self.syntax_violation("unencoded @ sign in username or password")
++ self.violation_fn.call(SyntaxViolation::UnencodedAtSign)
+ } else {
+- self.syntax_violation(
+- "embedding authentification information (username or password) \
+- in an URL is not recommended")
++ self.violation_fn.call(SyntaxViolation::EmbeddedCredentials)
+ }
+ last_at = Some((char_count, remaining.clone()))
+ },
+@@ -701,14 +797,23 @@
+ };
+
+ let mut username_end = None;
++ let mut has_password = false;
++ let mut has_username = false;
+ while userinfo_char_count > 0 {
+ let (c, utf8_c) = input.next_utf8().unwrap();
+ userinfo_char_count -= 1;
+ if c == ':' && username_end.is_none() {
+ // Start parsing password
+ username_end = Some(to_u32(self.serialization.len())?);
+- self.serialization.push(':');
++ // We don't add a colon if the password is empty
++ if userinfo_char_count > 0 {
++ self.serialization.push(':');
++ has_password = true;
++ }
+ } else {
++ if !has_password {
++ has_username = true;
++ }
+ self.check_url_code_point(c, &input);
+ self.serialization.extend(utf8_percent_encode(utf8_c, USERINFO_ENCODE_SET));
+ }
+@@ -717,7 +822,9 @@
+ Some(i) => i,
+ None => to_u32(self.serialization.len())?,
+ };
+- self.serialization.push('@');
++ if has_username || has_password {
++ self.serialization.push('@');
++ }
+ Ok((username_end, remaining))
+ }
+
+@@ -783,6 +890,10 @@
+ if scheme_type.is_special() && host_str.is_empty() {
+ return Err(ParseError::EmptyHost)
+ }
++ if !scheme_type.is_special() {
++ let host = Host::parse_opaque(host_str)?;
++ return Ok((host, input));
++ }
+ let host = Host::parse(host_str)?;
+ Ok((host, input))
+ }
+@@ -867,7 +978,7 @@
+ match input.split_first() {
+ (Some('/'), remaining) => input = remaining,
+ (Some('\\'), remaining) => if scheme_type.is_special() {
+- self.syntax_violation("backslash");
++ self.violation_fn.call(SyntaxViolation::Backslash);
+ input = remaining
+ },
+ _ => {}
+@@ -895,7 +1006,7 @@
+ },
+ '\\' if self.context != Context::PathSegmentSetter &&
+ scheme_type.is_special() => {
+- self.syntax_violation("backslash");
++ self.violation_fn.call(SyntaxViolation::Backslash);
+ ends_with_slash = true;
+ break
+ },
+@@ -905,18 +1016,14 @@
+ },
+ _ => {
+ self.check_url_code_point(c, &input);
+- if c == '%' {
+- let after_percent_sign = input.clone();
+- if matches!(input.next(), Some('2')) &&
+- matches!(input.next(), Some('E') | Some('e')) {
+- self.serialization.push('.');
+- continue
+- }
+- input = after_percent_sign
+- }
+ if self.context == Context::PathSegmentSetter {
+- self.serialization.extend(utf8_percent_encode(
+- utf8_c, PATH_SEGMENT_ENCODE_SET));
++ if scheme_type.is_special() {
++ self.serialization.extend(utf8_percent_encode(
++ utf8_c, SPECIAL_PATH_SEGMENT_ENCODE_SET));
++ } else {
++ self.serialization.extend(utf8_percent_encode(
++ utf8_c, PATH_SEGMENT_ENCODE_SET));
++ }
+ } else {
+ self.serialization.extend(utf8_percent_encode(
+ utf8_c, DEFAULT_ENCODE_SET));
+@@ -925,7 +1032,7 @@
+ }
+ }
+ match &self.serialization[segment_start..] {
+- ".." => {
++ ".." | "%2e%2e" | "%2e%2E" | "%2E%2e" | "%2E%2E" | "%2e." | "%2E." | ".%2e" | ".%2E" => {
+ debug_assert!(self.serialization.as_bytes()[segment_start - 1] == b'/');
+ self.serialization.truncate(segment_start - 1); // Truncate "/.."
+ self.pop_path(scheme_type, path_start);
+@@ -933,7 +1040,7 @@
+ self.serialization.push('/')
+ }
+ },
+- "." => {
++ "." | "%2e" | "%2E" => {
+ self.serialization.truncate(segment_start);
+ },
+ _ => {
+@@ -945,7 +1052,7 @@
+ self.serialization.push(':');
+ }
+ if *has_host {
+- self.syntax_violation("file: with host and Windows drive letter");
++ self.violation_fn.call(SyntaxViolation::FileWithHostAndWindowsDrive);
+ *has_host = false; // FIXME account for this in callers
+ }
+ }
+@@ -1087,7 +1194,7 @@
+ pub fn parse_fragment(&mut self, mut input: Input) {
+ while let Some((c, utf8_c)) = input.next_utf8() {
+ if c == '\0' {
+- self.syntax_violation("NULL characters are ignored in URL fragment identifiers")
++ self.violation_fn.call(SyntaxViolation::NullInFragment)
+ } else {
+ self.check_url_code_point(c, &input);
+ self.serialization.extend(utf8_percent_encode(utf8_c,
+@@ -1097,15 +1204,16 @@
+ }
+
+ fn check_url_code_point(&self, c: char, input: &Input) {
+- if let Some(log) = self.log_syntax_violation {
++ let vfn = self.violation_fn;
++ if vfn.is_set() {
+ if c == '%' {
+ let mut input = input.clone();
+ if !matches!((input.next(), input.next()), (Some(a), Some(b))
+ if is_ascii_hex_digit(a) && is_ascii_hex_digit(b)) {
+- log("expected 2 hex digits after %")
++ vfn.call(SyntaxViolation::PercentDecode)
+ }
+ } else if !is_url_code_point(c) {
+- log("non-URL code point")
++ vfn.call(SyntaxViolation::NonUrlCodePoint)
+ }
+ }
+ }
+diff -u -r --new-file seamonkey-2.53.1.orig/mozilla/third_party/rust/url/src/quirks.rs seamonkey-2.53.1/mozilla/third_party/rust/url/src/quirks.rs
+--- seamonkey-2.53.1.orig/mozilla/third_party/rust/url/src/quirks.rs 2020-02-17 17:39:21.000000000 -0600
++++ seamonkey-2.53.1/mozilla/third_party/rust/url/src/quirks.rs 2020-02-29 21:15:07.670769022 -0600
+@@ -46,7 +46,7 @@
+
+ /// Getter for https://url.spec.whatwg.org/#dom-url-origin
+ pub fn origin(url: &Url) -> String {
+- url.origin().unicode_serialization()
++ url.origin().ascii_serialization()
+ }
+
+ /// Getter for https://url.spec.whatwg.org/#dom-url-protocol
+@@ -152,7 +152,7 @@
+ {
+ // has_host implies !cannot_be_a_base
+ let scheme = url.scheme();
+- if !url.has_host() || scheme == "file" {
++ if !url.has_host() || url.host() == Some(Host::Domain("")) || scheme == "file" {
+ return Err(())
+ }
+ result = Parser::parse_port(Input::new(new_port), || default_port(scheme), Context::Setter)
+diff -u -r --new-file seamonkey-2.53.1.orig/mozilla/third_party/rust/url/tests/data.rs seamonkey-2.53.1/mozilla/third_party/rust/url/tests/data.rs
+--- seamonkey-2.53.1.orig/mozilla/third_party/rust/url/tests/data.rs 2020-02-17 17:39:21.000000000 -0600
++++ seamonkey-2.53.1/mozilla/third_party/rust/url/tests/data.rs 2020-02-29 21:15:43.807770565 -0600
+@@ -9,7 +9,7 @@
+ //! Data-driven tests
+
+ extern crate rustc_serialize;
+-extern crate test;
++extern crate rustc_test as test;
+ extern crate url;
+
+ use rustc_serialize::json::{self, Json};
+@@ -29,6 +29,7 @@
+ fn run_parsing(input: &str, base: &str, expected: Result<ExpectedAttributes, ()>) {
+ let base = match Url::parse(&base) {
+ Ok(base) => base,
++ Err(_) if expected.is_err() => return,
+ Err(message) => panic!("Error parsing base {:?}: {}", base, message)
+ };
+ let (url, expected) = match (base.join(&input), expected) {
+@@ -188,11 +189,7 @@
+ {
+ let mut add_one = |name: String, run: test::TestFn| {
+ tests.push(test::TestDescAndFn {
+- desc: test::TestDesc {
+- name: test::DynTestName(name),
+- ignore: false,
+- should_panic: test::ShouldPanic::No,
+- },
++ desc: test::TestDesc::new(test::DynTestName(name)),
+ testfn: run,
+ })
+ };
+diff -u -r --new-file seamonkey-2.53.1.orig/mozilla/third_party/rust/url/tests/setters_tests.json seamonkey-2.53.1/mozilla/third_party/rust/url/tests/setters_tests.json
+--- seamonkey-2.53.1.orig/mozilla/third_party/rust/url/tests/setters_tests.json 2020-02-17 17:39:21.000000000 -0600
++++ seamonkey-2.53.1/mozilla/third_party/rust/url/tests/setters_tests.json 2020-02-29 21:15:07.674769022 -0600
+@@ -102,6 +102,31 @@
+ }
+ },
+ {
++ "comment": "Can’t switch from file URL with no host",
++ "href": "file://localhost/",
++ "new_value": "http",
++ "expected": {
++ "href": "file:///",
++ "protocol": "file:"
++ }
++ },
++ {
++ "href": "file:///test",
++ "new_value": "gopher",
++ "expected": {
++ "href": "file:///test",
++ "protocol": "file:"
++ }
++ },
++ {
++ "href": "file:",
++ "new_value": "wss",
++ "expected": {
++ "href": "file:///",
++ "protocol": "file:"
++ }
++ },
++ {
+ "comment": "Spec deviation: from special scheme to not is not problematic. https://github.com/whatwg/url/issues/104",
+ "href": "http://example.net",
+ "new_value": "b",
+@@ -176,6 +201,14 @@
+ }
+ },
+ {
++ "href": "javascript:alert(1)",
++ "new_value": "wario",
++ "expected": {
++ "href": "javascript:alert(1)",
++ "username": ""
++ }
++ },
++ {
+ "href": "http://example.net",
+ "new_value": "me",
+ "expected": {
+@@ -224,6 +257,30 @@
+ "href": "http://%c3%89t%C3%A9@example.net/",
+ "username": "%c3%89t%C3%A9"
+ }
++ },
++ {
++ "href": "sc:///",
++ "new_value": "x",
++ "expected": {
++ "href": "sc:///",
++ "username": ""
++ }
++ },
++ {
++ "href": "file://test/",
++ "new_value": "test",
++ "expected": {
++ "href": "file://test/",
++ "username": ""
++ }
++ },
++ {
++ "href": "javascript://x/",
++ "new_value": "wario",
++ "expected": {
++ "href": "javascript://wario@x/",
++ "username": "wario"
++ }
+ }
+ ],
+ "password": [
+@@ -303,10 +360,106 @@
+ "href": "http://:%c3%89t%C3%A9@example.net/",
+ "password": "%c3%89t%C3%A9"
+ }
++ },
++ {
++ "href": "sc:///",
++ "new_value": "x",
++ "expected": {
++ "href": "sc:///",
++ "password": ""
++ }
++ },
++ {
++ "href": "file://test/",
++ "new_value": "test",
++ "expected": {
++ "href": "file://test/",
++ "password": ""
++ }
++ },
++ {
++ "href": "javascript://x/",
++ "new_value": "bowser",
++ "expected": {
++ "href": "javascript://:bowser@x/",
++ "password": "bowser"
++ }
+ }
+ ],
+ "host": [
+ {
++ "href": "sc://x/",
++ "new_value": "\u0009",
++ "expected": {
++ "href": "sc:///",
++ "host": "",
++ "hostname": ""
++ }
++ },
++ {
++ "href": "sc://x/",
++ "new_value": "\u000A",
++ "expected": {
++ "href": "sc:///",
++ "host": "",
++ "hostname": ""
++ }
++ },
++ {
++ "href": "sc://x/",
++ "new_value": "\u000D",
++ "expected": {
++ "href": "sc:///",
++ "host": "",
++ "hostname": ""
++ }
++ },
++ {
++ "href": "sc://x/",
++ "new_value": "#",
++ "expected": {
++ "href": "sc:///",
++ "host": "",
++ "hostname": ""
++ }
++ },
++ {
++ "href": "sc://x/",
++ "new_value": "/",
++ "expected": {
++ "href": "sc:///",
++ "host": "",
++ "hostname": ""
++ }
++ },
++ {
++ "href": "sc://x/",
++ "new_value": "?",
++ "expected": {
++ "href": "sc:///",
++ "host": "",
++ "hostname": ""
++ }
++ },
++ {
++ "href": "sc://x/",
++ "new_value": "@",
++ "expected": {
++ "href": "sc://x/",
++ "host": "x",
++ "hostname": "x"
++ }
++ },
++ {
++ "href": "sc://x/",
++ "new_value": "ß",
++ "expected": {
++ "href": "sc://%C3%9F/",
++ "host": "%C3%9F",
++ "hostname": "%C3%9F"
++ }
++ },
++ {
+ "comment": "Cannot-be-a-base means no host",
+ "href": "mailto:me@example.net",
+ "new_value": "example.com",
+@@ -384,15 +537,6 @@
+ }
+ },
+ {
+- "comment": "Path-only URLs can gain a host",
+- "href": "a:/foo",
+- "new_value": "example.net",
+- "expected": {
+- "href": "a://example.net/foo",
+- "host": "example.net"
+- }
+- },
+- {
+ "comment": "IPv4 address syntax is normalized",
+ "href": "http://example.net",
+ "new_value": "0x7F000001:8080",
+@@ -536,7 +680,7 @@
+ }
+ },
+ {
+- "comment": "\\ is not a delimiter for non-special schemes, and it’s invalid in a domain",
++ "comment": "\\ is not a delimiter for non-special schemes, but still forbidden in hosts",
+ "href": "view-source+http://example.net/path",
+ "new_value": "example.com\\stuff",
+ "expected": {
+@@ -600,10 +744,119 @@
+ "hostname": "example.com",
+ "port": ""
+ }
++ },
++ {
++ "comment": "Broken IPv6",
++ "href": "http://example.net/",
++ "new_value": "[google.com]",
++ "expected": {
++ "href": "http://example.net/",
++ "host": "example.net",
++ "hostname": "example.net"
++ }
++ },
++ {
++ "href": "http://example.net/",
++ "new_value": "[::1.2.3.4x]",
++ "expected": {
++ "href": "http://example.net/",
++ "host": "example.net",
++ "hostname": "example.net"
++ }
++ },
++ {
++ "href": "http://example.net/",
++ "new_value": "[::1.2.3.]",
++ "expected": {
++ "href": "http://example.net/",
++ "host": "example.net",
++ "hostname": "example.net"
++ }
++ },
++ {
++ "href": "http://example.net/",
++ "new_value": "[::1.2.]",
++ "expected": {
++ "href": "http://example.net/",
++ "host": "example.net",
++ "hostname": "example.net"
++ }
++ },
++ {
++ "href": "http://example.net/",
++ "new_value": "[::1.]",
++ "expected": {
++ "href": "http://example.net/",
++ "host": "example.net",
++ "hostname": "example.net"
++ }
+ }
+ ],
+ "hostname": [
+ {
++ "href": "sc://x/",
++ "new_value": "\u0009",
++ "expected": {
++ "href": "sc:///",
++ "host": "",
++ "hostname": ""
++ }
++ },
++ {
++ "href": "sc://x/",
++ "new_value": "\u000A",
++ "expected": {
++ "href": "sc:///",
++ "host": "",
++ "hostname": ""
++ }
++ },
++ {
++ "href": "sc://x/",
++ "new_value": "\u000D",
++ "expected": {
++ "href": "sc:///",
++ "host": "",
++ "hostname": ""
++ }
++ },
++ {
++ "href": "sc://x/",
++ "new_value": "#",
++ "expected": {
++ "href": "sc:///",
++ "host": "",
++ "hostname": ""
++ }
++ },
++ {
++ "href": "sc://x/",
++ "new_value": "/",
++ "expected": {
++ "href": "sc:///",
++ "host": "",
++ "hostname": ""
++ }
++ },
++ {
++ "href": "sc://x/",
++ "new_value": "?",
++ "expected": {
++ "href": "sc:///",
++ "host": "",
++ "hostname": ""
++ }
++ },
++ {
++ "href": "sc://x/",
++ "new_value": "@",
++ "expected": {
++ "href": "sc://x/",
++ "host": "x",
++ "hostname": "x"
++ }
++ },
++ {
+ "comment": "Cannot-be-a-base means no host",
+ "href": "mailto:me@example.net",
+ "new_value": "example.com",
+@@ -659,15 +912,6 @@
+ }
+ },
+ {
+- "comment": "Path-only URLs can gain a host",
+- "href": "a:/foo",
+- "new_value": "example.net",
+- "expected": {
+- "href": "a://example.net/foo",
+- "host": "example.net"
+- }
+- },
+- {
+ "comment": "IPv4 address syntax is normalized",
+ "href": "http://example.net:8080",
+ "new_value": "0x7F000001",
+@@ -756,7 +1000,7 @@
+ }
+ },
+ {
+- "comment": "\\ is not a delimiter for non-special schemes, and it’s invalid in a domain",
++ "comment": "\\ is not a delimiter for non-special schemes, but still forbidden in hosts",
+ "href": "view-source+http://example.net/path",
+ "new_value": "example.com\\stuff",
+ "expected": {
+@@ -765,6 +1009,52 @@
+ "hostname": "example.net",
+ "port": ""
+ }
++ },
++ {
++ "comment": "Broken IPv6",
++ "href": "http://example.net/",
++ "new_value": "[google.com]",
++ "expected": {
++ "href": "http://example.net/",
++ "host": "example.net",
++ "hostname": "example.net"
++ }
++ },
++ {
++ "href": "http://example.net/",
++ "new_value": "[::1.2.3.4x]",
++ "expected": {
++ "href": "http://example.net/",
++ "host": "example.net",
++ "hostname": "example.net"
++ }
++ },
++ {
++ "href": "http://example.net/",
++ "new_value": "[::1.2.3.]",
++ "expected": {
++ "href": "http://example.net/",
++ "host": "example.net",
++ "hostname": "example.net"
++ }
++ },
++ {
++ "href": "http://example.net/",
++ "new_value": "[::1.2.]",
++ "expected": {
++ "href": "http://example.net/",
++ "host": "example.net",
++ "hostname": "example.net"
++ }
++ },
++ {
++ "href": "http://example.net/",
++ "new_value": "[::1.]",
++ "expected": {
++ "href": "http://example.net/",
++ "host": "example.net",
++ "hostname": "example.net"
++ }
+ }
+ ],
+ "port": [
+@@ -779,7 +1069,7 @@
+ }
+ },
+ {
+- "comment": "Port number is removed if empty in the new value: https://github.com/whatwg/url/pull/113",
++ "comment": "Port number is removed if empty is the new value",
+ "href": "http://example.net:8080",
+ "new_value": "",
+ "expected": {
+@@ -920,6 +1210,65 @@
+ "hostname": "example.net",
+ "port": "8080"
+ }
++ },
++ {
++ "comment": "Port numbers are 16 bit integers, overflowing is an error",
++ "href": "non-special://example.net:8080/path",
++ "new_value": "65536",
++ "expected": {
++ "href": "non-special://example.net:8080/path",
++ "host": "example.net:8080",
++ "hostname": "example.net",
++ "port": "8080"
++ }
++ },
++ {
++ "href": "file://test/",
++ "new_value": "12",
++ "expected": {
++ "href": "file://test/",
++ "port": ""
++ }
++ },
++ {
++ "href": "file://localhost/",
++ "new_value": "12",
++ "expected": {
++ "href": "file:///",
++ "port": ""
++ }
++ },
++ {
++ "href": "non-base:value",
++ "new_value": "12",
++ "expected": {
++ "href": "non-base:value",
++ "port": ""
++ }
++ },
++ {
++ "href": "sc:///",
++ "new_value": "12",
++ "expected": {
++ "href": "sc:///",
++ "port": ""
++ }
++ },
++ {
++ "href": "sc://x/",
++ "new_value": "12",
++ "expected": {
++ "href": "sc://x:12/",
++ "port": "12"
++ }
++ },
++ {
++ "href": "javascript://x/",
++ "new_value": "12",
++ "expected": {
++ "href": "javascript://x:12/",
++ "port": "12"
++ }
+ }
+ ],
+ "pathname": [
+@@ -970,8 +1319,8 @@
+ "href": "view-source+http://example.net/home?lang=fr#nav",
+ "new_value": "\\a\\%2E\\b\\%2e.\\c",
+ "expected": {
+- "href": "view-source+http://example.net/\\a\\.\\b\\..\\c?lang=fr#nav",
+- "pathname": "/\\a\\.\\b\\..\\c"
++ "href": "view-source+http://example.net/\\a\\%2E\\b\\%2e.\\c?lang=fr#nav",
++ "pathname": "/\\a\\%2E\\b\\%2e.\\c"
+ }
+ },
+ {
+@@ -984,12 +1333,48 @@
+ }
+ },
+ {
+- "comment": "Bytes already percent-encoded are left as-is, except %2E.",
++ "comment": "Bytes already percent-encoded are left as-is, including %2E outside dotted segments.",
+ "href": "http://example.net",
+ "new_value": "%2e%2E%c3%89té",
+ "expected": {
+- "href": "http://example.net/..%c3%89t%C3%A9",
+- "pathname": "/..%c3%89t%C3%A9"
++ "href": "http://example.net/%2e%2E%c3%89t%C3%A9",
++ "pathname": "/%2e%2E%c3%89t%C3%A9"
++ }
++ },
++ {
++ "comment": "? needs to be encoded",
++ "href": "http://example.net",
++ "new_value": "?",
++ "expected": {
++ "href": "http://example.net/%3F",
++ "pathname": "/%3F"
++ }
++ },
++ {
++ "comment": "# needs to be encoded",
++ "href": "http://example.net",
++ "new_value": "#",
++ "expected": {
++ "href": "http://example.net/%23",
++ "pathname": "/%23"
++ }
++ },
++ {
++ "comment": "? needs to be encoded, non-special scheme",
++ "href": "sc://example.net",
++ "new_value": "?",
++ "expected": {
++ "href": "sc://example.net/%3F",
++ "pathname": "/%3F"
++ }
++ },
++ {
++ "comment": "# needs to be encoded, non-special scheme",
++ "href": "sc://example.net",
++ "new_value": "#",
++ "expected": {
++ "href": "sc://example.net/%23",
++ "pathname": "/%23"
+ }
+ }
+ ],
+diff -u -r --new-file seamonkey-2.53.1.orig/mozilla/third_party/rust/url/tests/unit.rs seamonkey-2.53.1/mozilla/third_party/rust/url/tests/unit.rs
+--- seamonkey-2.53.1.orig/mozilla/third_party/rust/url/tests/unit.rs 2020-02-17 17:39:21.000000000 -0600
++++ seamonkey-2.53.1/mozilla/third_party/rust/url/tests/unit.rs 2020-02-29 21:15:43.808770565 -0600
+@@ -11,7 +11,9 @@
+ #[macro_use]
+ extern crate url;
+
++use std::ascii::AsciiExt;
+ use std::borrow::Cow;
++use std::cell::{Cell, RefCell};
+ use std::net::{Ipv4Addr, Ipv6Addr};
+ use std::path::{Path, PathBuf};
+ use url::{Host, HostAndPort, Url, form_urlencoded};
+@@ -108,6 +110,17 @@
+ }
+
+ #[test]
++fn path_backslash_fun() {
++ let mut special_url = "http://foobar.com".parse::<Url>().unwrap();
++ special_url.path_segments_mut().unwrap().push("foo\\bar");
++ assert_eq!(special_url.as_str(), "http://foobar.com/foo%5Cbar");
++
++ let mut nonspecial_url = "thing://foobar.com".parse::<Url>().unwrap();
++ nonspecial_url.path_segments_mut().unwrap().push("foo\\bar");
++ assert_eq!(nonspecial_url.as_str(), "thing://foobar.com/foo\\bar");
++}
++
++#[test]
+ fn from_str() {
+ assert!("http://testing.com/this".parse::<Url>().is_ok());
+ }
+@@ -221,7 +234,7 @@
+ ("http://example.com/", "http://example.com/"),
+ ("http://addslash.com", "http://addslash.com/"),
+ ("http://@emptyuser.com/", "http://emptyuser.com/"),
+- ("http://:@emptypass.com/", "http://:@emptypass.com/"),
++ ("http://:@emptypass.com/", "http://emptypass.com/"),
+ ("http://user@user.com/", "http://user@user.com/"),
+ ("http://user:pass@userpass.com/", "http://user:pass@userpass.com/"),
+ ("http://slashquery.com/path/?q=something", "http://slashquery.com/path/?q=something"),
+@@ -256,6 +269,15 @@
+ }
+
+ #[test]
++fn form_urlencoded_custom_encoding_override() {
++ let encoded = form_urlencoded::Serializer::new(String::new())
++ .custom_encoding_override(|s| s.as_bytes().to_ascii_uppercase().into())
++ .append_pair("foo", "bar")
++ .finish();
++ assert_eq!(encoded, "FOO=BAR");
++}
++
++#[test]
+ fn host_and_port_display() {
+ assert_eq!(
+ format!(
+@@ -286,22 +308,6 @@
+ }
+
+ #[test]
+-/// https://github.com/servo/rust-url/issues/25
+-fn issue_25() {
+- let filename = if cfg!(windows) { r"C:\run\pg.sock" } else { "/run/pg.sock" };
+- let mut url = Url::from_file_path(filename).unwrap();
+- url.check_invariants().unwrap();
+- url.set_scheme("postgres").unwrap();
+- url.check_invariants().unwrap();
+- url.set_host(Some("")).unwrap();
+- url.check_invariants().unwrap();
+- url.set_username("me").unwrap();
+- url.check_invariants().unwrap();
+- let expected = format!("postgres://me@/{}run/pg.sock", if cfg!(windows) { "C:/" } else { "" });
+- assert_eq!(url.as_str(), expected);
+-}
+-
+-#[test]
+ /// https://github.com/servo/rust-url/issues/61
+ fn issue_61() {
+ let mut url = Url::parse("http://mozilla.org").unwrap();
+@@ -372,6 +378,11 @@
+ let mut url = Url::parse("foobar://example.net/hello").unwrap();
+ url.set_host(None).unwrap();
+ assert_eq!(url.as_str(), "foobar:/hello");
++
++ let mut url = Url::parse("foo://ș").unwrap();
++ assert_eq!(url.as_str(), "foo://%C8%99/");
++ url.set_host(Some("goșu.ro")).unwrap();
++ assert_eq!(url.as_str(), "foo://go%C8%99u.ro/");
+ }
+
+ #[test]
+@@ -478,3 +489,68 @@
+ let url = Url::from_file_path(Path::new(r"\\.\some\path\file.txt"));
+ assert!(url.is_err());
+ }
++
++// Test the now deprecated log_syntax_violation method for backward
++// compatibility
++#[test]
++#[allow(deprecated)]
++fn test_old_log_violation_option() {
++ let violation = Cell::new(None);
++ let url = Url::options()
++ .log_syntax_violation(Some(&|s| violation.set(Some(s.to_owned()))))
++ .parse("http:////mozilla.org:42").unwrap();
++ assert_eq!(url.port(), Some(42));
++
++ let violation = violation.take();
++ assert_eq!(violation, Some("expected //".to_string()));
++}
++
++#[test]
++fn test_syntax_violation_callback() {
++ use url::SyntaxViolation::*;
++ let violation = Cell::new(None);
++ let url = Url::options()
++ .syntax_violation_callback(Some(&|v| violation.set(Some(v))))
++ .parse("http:////mozilla.org:42").unwrap();
++ assert_eq!(url.port(), Some(42));
++
++ let v = violation.take().unwrap();
++ assert_eq!(v, ExpectedDoubleSlash);
++ assert_eq!(v.description(), "expected //");
++}
++
++#[test]
++fn test_syntax_violation_callback_lifetimes() {
++ use url::SyntaxViolation::*;
++ let violation = Cell::new(None);
++ let vfn = |s| violation.set(Some(s));
++
++ let url = Url::options()
++ .syntax_violation_callback(Some(&vfn))
++ .parse("http:////mozilla.org:42").unwrap();
++ assert_eq!(url.port(), Some(42));
++ assert_eq!(violation.take(), Some(ExpectedDoubleSlash));
++
++ let url = Url::options()
++ .syntax_violation_callback(Some(&vfn))
++ .parse("http://mozilla.org\\path").unwrap();
++ assert_eq!(url.path(), "/path");
++ assert_eq!(violation.take(), Some(Backslash));
++}
++
++#[test]
++fn test_options_reuse() {
++ use url::SyntaxViolation::*;
++ let violations = RefCell::new(Vec::new());
++ let vfn = |v| violations.borrow_mut().push(v);
++
++ let options = Url::options()
++ .syntax_violation_callback(Some(&vfn));
++ let url = options.parse("http:////mozilla.org").unwrap();
++
++ let options = options.base_url(Some(&url));
++ let url = options.parse("/sub\\path").unwrap();
++ assert_eq!(url.as_str(), "http://mozilla.org/sub/path");
++ assert_eq!(*violations.borrow(),
++ vec!(ExpectedDoubleSlash, Backslash));
++}
+diff -u -r --new-file seamonkey-2.53.1.orig/mozilla/third_party/rust/url/tests/urltestdata.json seamonkey-2.53.1/mozilla/third_party/rust/url/tests/urltestdata.json
+--- seamonkey-2.53.1.orig/mozilla/third_party/rust/url/tests/urltestdata.json 2020-02-17 17:39:21.000000000 -0600
++++ seamonkey-2.53.1/mozilla/third_party/rust/url/tests/urltestdata.json 2020-02-29 21:15:07.679769022 -0600
+@@ -31,6 +31,66 @@
+ "hash": "#c"
+ },
+ {
++ "input": "https://test:@test",
++ "base": "about:blank",
++ "href": "https://test@test/",
++ "origin": "https://test",
++ "protocol": "https:",
++ "username": "test",
++ "password": "",
++ "host": "test",
++ "hostname": "test",
++ "port": "",
++ "pathname": "/",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "https://:@test",
++ "base": "about:blank",
++ "href": "https://test/",
++ "origin": "https://test",
++ "protocol": "https:",
++ "username": "",
++ "password": "",
++ "host": "test",
++ "hostname": "test",
++ "port": "",
++ "pathname": "/",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "non-special://test:@test/x",
++ "base": "about:blank",
++ "href": "non-special://test@test/x",
++ "origin": "null",
++ "protocol": "non-special:",
++ "username": "test",
++ "password": "",
++ "host": "test",
++ "hostname": "test",
++ "port": "",
++ "pathname": "/x",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "non-special://:@test/x",
++ "base": "about:blank",
++ "href": "non-special://test/x",
++ "origin": "null",
++ "protocol": "non-special:",
++ "username": "",
++ "password": "",
++ "host": "test",
++ "hostname": "test",
++ "port": "",
++ "pathname": "/x",
++ "search": "",
++ "hash": ""
++ },
++ {
+ "input": "http:foo.com",
+ "base": "http://example.org/foo/bar",
+ "href": "http://example.org/foo/foo.com",
+@@ -106,6 +166,20 @@
+ "hash": "# e"
+ },
+ {
++ "input": "lolscheme:x x#x x",
++ "base": "about:blank",
++ "href": "lolscheme:x x#x x",
++ "protocol": "lolscheme:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "x x",
++ "search": "",
++ "hash": "#x x"
++ },
++ {
+ "input": "http://f:/c",
+ "base": "http://example.org/foo/bar",
+ "href": "http://f/c",
+@@ -201,6 +275,11 @@
+ "failure": true
+ },
+ {
++ "input": "non-special://f:999999/c",
++ "base": "http://example.org/foo/bar",
++ "failure": true
++ },
++ {
+ "input": "http://f: 21 / b ? d # e ",
+ "base": "http://example.org/foo/bar",
+ "failure": true
+@@ -960,6 +1039,26 @@
+ "hash": ""
+ },
+ {
++ "input": "file://example:1/",
++ "base": "about:blank",
++ "failure": true
++ },
++ {
++ "input": "file://example:test/",
++ "base": "about:blank",
++ "failure": true
++ },
++ {
++ "input": "file://example%/",
++ "base": "about:blank",
++ "failure": true
++ },
++ {
++ "input": "file://[example]/",
++ "base": "about:blank",
++ "failure": true
++ },
++ {
+ "input": "ftps:/example.com/",
+ "base": "http://example.org/foo/bar",
+ "href": "ftps:/example.com/",
+@@ -1785,7 +1884,7 @@
+ {
+ "input": "http://example.com/foo/%2e%2",
+ "base": "about:blank",
+- "href": "http://example.com/foo/.%2",
++ "href": "http://example.com/foo/%2e%2",
+ "origin": "http://example.com",
+ "protocol": "http:",
+ "username": "",
+@@ -1793,14 +1892,14 @@
+ "host": "example.com",
+ "hostname": "example.com",
+ "port": "",
+- "pathname": "/foo/.%2",
++ "pathname": "/foo/%2e%2",
+ "search": "",
+ "hash": ""
+ },
+ {
+ "input": "http://example.com/foo/%2e./%2e%2e/.%2e/%2e.bar",
+ "base": "about:blank",
+- "href": "http://example.com/..bar",
++ "href": "http://example.com/%2e.bar",
+ "origin": "http://example.com",
+ "protocol": "http:",
+ "username": "",
+@@ -1808,7 +1907,7 @@
+ "host": "example.com",
+ "hostname": "example.com",
+ "port": "",
+- "pathname": "/..bar",
++ "pathname": "/%2e.bar",
+ "search": "",
+ "hash": ""
+ },
+@@ -2189,11 +2288,6 @@
+ "hash": "# %C2%BB"
+ },
+ {
+- "input": "http://[www.google.com]/",
+- "base": "about:blank",
+- "failure": true
+- },
+- {
+ "input": "http://www.google.com",
+ "base": "about:blank",
+ "href": "http://www.google.com/",
+@@ -2226,7 +2320,7 @@
+ {
+ "input": "http://www/foo%2Ehtml",
+ "base": "about:blank",
+- "href": "http://www/foo.html",
++ "href": "http://www/foo%2Ehtml",
+ "origin": "http://www",
+ "protocol": "http:",
+ "username": "",
+@@ -2234,7 +2328,7 @@
+ "host": "www",
+ "hostname": "www",
+ "port": "",
+- "pathname": "/foo.html",
++ "pathname": "/foo%2Ehtml",
+ "search": "",
+ "hash": ""
+ },
+@@ -3096,7 +3190,7 @@
+ {
+ "input": "http:a:@www.example.com",
+ "base": "about:blank",
+- "href": "http://a:@www.example.com/",
++ "href": "http://a@www.example.com/",
+ "origin": "http://www.example.com",
+ "protocol": "http:",
+ "username": "a",
+@@ -3111,7 +3205,7 @@
+ {
+ "input": "http:/a:@www.example.com",
+ "base": "about:blank",
+- "href": "http://a:@www.example.com/",
++ "href": "http://a@www.example.com/",
+ "origin": "http://www.example.com",
+ "protocol": "http:",
+ "username": "a",
+@@ -3126,7 +3220,7 @@
+ {
+ "input": "http://a:@www.example.com",
+ "base": "about:blank",
+- "href": "http://a:@www.example.com/",
++ "href": "http://a@www.example.com/",
+ "origin": "http://www.example.com",
+ "protocol": "http:",
+ "username": "a",
+@@ -3171,7 +3265,7 @@
+ {
+ "input": "http://:@www.example.com",
+ "base": "about:blank",
+- "href": "http://:@www.example.com/",
++ "href": "http://www.example.com/",
+ "origin": "http://www.example.com",
+ "protocol": "http:",
+ "username": "",
+@@ -3465,6 +3559,22 @@
+ "search": "",
+ "hash": ""
+ },
++ "Leading and trailing C0 control or space",
++ {
++ "input": "\u0000\u001b\u0004\u0012 http://example.com/\u001f \u000d ",
++ "base": "about:blank",
++ "href": "http://example.com/",
++ "origin": "http://example.com",
++ "protocol": "http:",
++ "username": "",
++ "password": "",
++ "host": "example.com",
++ "hostname": "example.com",
++ "port": "",
++ "pathname": "/",
++ "search": "",
++ "hash": ""
++ },
+ "Ideographic full stop (full-width period for Chinese, etc.) should be treated as a dot. U+3002 is mapped to U+002E (dot)",
+ {
+ "input": "http://www.foo。bar.com",
+@@ -3493,6 +3603,32 @@
+ "base": "http://other.com/",
+ "failure": true
+ },
++ "U+FFFD",
++ {
++ "input": "https://\ufffd",
++ "base": "about:blank",
++ "failure": true
++ },
++ {
++ "input": "https://%EF%BF%BD",
++ "base": "about:blank",
++ "failure": true
++ },
++ {
++ "input": "https://x/\ufffd?\ufffd#\ufffd",
++ "base": "about:blank",
++ "href": "https://x/%EF%BF%BD?%EF%BF%BD#%EF%BF%BD",
++ "origin": "https://x",
++ "protocol": "https:",
++ "username": "",
++ "password": "",
++ "host": "x",
++ "hostname": "x",
++ "port": "",
++ "pathname": "/%EF%BF%BD",
++ "search": "?%EF%BF%BD",
++ "hash": "#%EF%BF%BD"
++ },
+ "Test name prepping, fullwidth input should be converted to ASCII and NOT IDN-ized. This is 'Go' in fullwidth UTF-8/UTF-16.",
+ {
+ "input": "http://Go.com",
+@@ -3536,7 +3672,7 @@
+ "input": "http://你好你好",
+ "base": "http://other.com/",
+ "href": "http://xn--6qqa088eba/",
+- "origin": "http://你好你好",
++ "origin": "http://xn--6qqa088eba",
+ "protocol": "http:",
+ "username": "",
+ "password": "",
+@@ -3547,6 +3683,36 @@
+ "search": "",
+ "hash": ""
+ },
++ {
++ "input": "https://faß.ExAmPlE/",
++ "base": "about:blank",
++ "href": "https://xn--fa-hia.example/",
++ "origin": "https://xn--fa-hia.example",
++ "protocol": "https:",
++ "username": "",
++ "password": "",
++ "host": "xn--fa-hia.example",
++ "hostname": "xn--fa-hia.example",
++ "port": "",
++ "pathname": "/",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "sc://faß.ExAmPlE/",
++ "base": "about:blank",
++ "href": "sc://fa%C3%9F.ExAmPlE/",
++ "origin": "null",
++ "protocol": "sc:",
++ "username": "",
++ "password": "",
++ "host": "fa%C3%9F.ExAmPlE",
++ "hostname": "fa%C3%9F.ExAmPlE",
++ "port": "",
++ "pathname": "/",
++ "search": "",
++ "hash": ""
++ },
+ "Invalid escaped characters should fail and the percents should be escaped. https://www.w3.org/Bugs/Public/show_bug.cgi?id=24191",
+ {
+ "input": "http://%zz%66%a.com",
+@@ -3600,18 +3766,23 @@
+ "base": "http://other.com/",
+ "failure": true
+ },
+- "Invalid escaping should trigger the regular host error handling",
++ "Invalid escaping in hosts causes failure",
+ {
+ "input": "http://%3g%78%63%30%2e%30%32%35%30%2E.01",
+ "base": "http://other.com/",
+ "failure": true
+ },
+- "Something that isn't exactly an IP should get treated as a host and spaces escaped",
++ "A space in a host causes failure",
+ {
+ "input": "http://192.168.0.1 hello",
+ "base": "http://other.com/",
+ "failure": true
+ },
++ {
++ "input": "https://x x:12",
++ "base": "about:blank",
++ "failure": true
++ },
+ "Fullwidth and escaped UTF-8 fullwidth should still be treated as IP",
+ {
+ "input": "http://0Xc0.0250.01",
+@@ -3628,12 +3799,83 @@
+ "search": "",
+ "hash": ""
+ },
++ "Domains with empty labels",
++ {
++ "input": "http://./",
++ "base": "about:blank",
++ "href": "http://./",
++ "origin": "http://.",
++ "protocol": "http:",
++ "username": "",
++ "password": "",
++ "host": ".",
++ "hostname": ".",
++ "port": "",
++ "pathname": "/",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "http://../",
++ "base": "about:blank",
++ "href": "http://../",
++ "origin": "http://..",
++ "protocol": "http:",
++ "username": "",
++ "password": "",
++ "host": "..",
++ "hostname": "..",
++ "port": "",
++ "pathname": "/",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "http://0..0x300/",
++ "base": "about:blank",
++ "href": "http://0..0x300/",
++ "origin": "http://0..0x300",
++ "protocol": "http:",
++ "username": "",
++ "password": "",
++ "host": "0..0x300",
++ "hostname": "0..0x300",
++ "port": "",
++ "pathname": "/",
++ "search": "",
++ "hash": ""
++ },
+ "Broken IPv6",
+ {
++ "input": "http://[www.google.com]/",
++ "base": "about:blank",
++ "failure": true
++ },
++ {
+ "input": "http://[google.com]",
+ "base": "http://other.com/",
+ "failure": true
+ },
++ {
++ "input": "http://[::1.2.3.4x]",
++ "base": "http://other.com/",
++ "failure": true
++ },
++ {
++ "input": "http://[::1.2.3.]",
++ "base": "http://other.com/",
++ "failure": true
++ },
++ {
++ "input": "http://[::1.2.]",
++ "base": "http://other.com/",
++ "failure": true
++ },
++ {
++ "input": "http://[::1.]",
++ "base": "http://other.com/",
++ "failure": true
++ },
+ "Misc Unicode",
+ {
+ "input": "http://foo:💩@example.com/bar",
+@@ -4176,22 +4418,91 @@
+ "search": "",
+ "hash": ""
+ },
+- "# unknown schemes and non-ASCII domains",
++ "# unknown schemes and their hosts",
+ {
+ "input": "sc://ñ.test/",
+ "base": "about:blank",
+- "href": "sc://xn--ida.test/",
++ "href": "sc://%C3%B1.test/",
+ "origin": "null",
+ "protocol": "sc:",
+ "username": "",
+ "password": "",
+- "host": "xn--ida.test",
+- "hostname": "xn--ida.test",
++ "host": "%C3%B1.test",
++ "hostname": "%C3%B1.test",
+ "port": "",
+ "pathname": "/",
+ "search": "",
+ "hash": ""
+ },
++ {
++ "input": "sc://\u001F!\"$&'()*+,-.;<=>^_`{|}~/",
++ "base": "about:blank",
++ "href": "sc://%1F!\"$&'()*+,-.;<=>^_`{|}~/",
++ "origin": "null",
++ "protocol": "sc:",
++ "username": "",
++ "password": "",
++ "host": "%1F!\"$&'()*+,-.;<=>^_`{|}~",
++ "hostname": "%1F!\"$&'()*+,-.;<=>^_`{|}~",
++ "port": "",
++ "pathname": "/",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "sc://\u0000/",
++ "base": "about:blank",
++ "failure": true
++ },
++ {
++ "input": "sc:// /",
++ "base": "about:blank",
++ "failure": true
++ },
++ {
++ "input": "sc://%/",
++ "base": "about:blank",
++ "href": "sc://%/",
++ "protocol": "sc:",
++ "username": "",
++ "password": "",
++ "host": "%",
++ "hostname": "%",
++ "port": "",
++ "pathname": "/",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "sc://[/",
++ "base": "about:blank",
++ "failure": true
++ },
++ {
++ "input": "sc://\\/",
++ "base": "about:blank",
++ "failure": true
++ },
++ {
++ "input": "sc://]/",
++ "base": "about:blank",
++ "failure": true
++ },
++ {
++ "input": "x",
++ "base": "sc://ñ",
++ "href": "sc://%C3%B1/x",
++ "origin": "null",
++ "protocol": "sc:",
++ "username": "",
++ "password": "",
++ "host": "%C3%B1",
++ "hostname": "%C3%B1",
++ "port": "",
++ "pathname": "/x",
++ "search": "",
++ "hash": ""
++ },
+ "# unknown schemes and backslashes",
+ {
+ "input": "sc:\\../",
+@@ -4224,6 +4535,88 @@
+ "search": "",
+ "hash": ""
+ },
++ "# unknown scheme with bogus percent-encoding",
++ {
++ "input": "wow:%NBD",
++ "base": "about:blank",
++ "href": "wow:%NBD",
++ "origin": "null",
++ "protocol": "wow:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "%NBD",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "wow:%1G",
++ "base": "about:blank",
++ "href": "wow:%1G",
++ "origin": "null",
++ "protocol": "wow:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "%1G",
++ "search": "",
++ "hash": ""
++ },
++ "# Hosts and percent-encoding",
++ {
++ "input": "ftp://example.com%80/",
++ "base": "about:blank",
++ "failure": true
++ },
++ {
++ "input": "ftp://example.com%A0/",
++ "base": "about:blank",
++ "failure": true
++ },
++ {
++ "input": "https://example.com%80/",
++ "base": "about:blank",
++ "failure": true
++ },
++ {
++ "input": "https://example.com%A0/",
++ "base": "about:blank",
++ "failure": true
++ },
++ {
++ "input": "ftp://%e2%98%83",
++ "base": "about:blank",
++ "href": "ftp://xn--n3h/",
++ "origin": "ftp://xn--n3h",
++ "protocol": "ftp:",
++ "username": "",
++ "password": "",
++ "host": "xn--n3h",
++ "hostname": "xn--n3h",
++ "port": "",
++ "pathname": "/",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "https://%e2%98%83",
++ "base": "about:blank",
++ "href": "https://xn--n3h/",
++ "origin": "https://xn--n3h",
++ "protocol": "https:",
++ "username": "",
++ "password": "",
++ "host": "xn--n3h",
++ "hostname": "xn--n3h",
++ "port": "",
++ "pathname": "/",
++ "search": "",
++ "hash": ""
++ },
+ "# tests from jsdom/whatwg-url designed for code coverage",
+ {
+ "input": "http://127.0.0.1:10100/relative_import.html",
+@@ -4371,75 +4764,1385 @@
+ "port": "",
+ "pathname": "/baz",
+ "search": "?qux",
+- "searchParams": "",
++ "searchParams": "qux=",
+ "hash": "#foo%08bar"
+ },
+- "# IPv6 compression and serialization",
++ "# IPv4 parsing (via https://github.com/nodejs/node/pull/10317)",
++ {
++ "input": "http://192.168.257",
++ "base": "http://other.com/",
++ "href": "http://192.168.1.1/",
++ "origin": "http://192.168.1.1",
++ "protocol": "http:",
++ "username": "",
++ "password": "",
++ "host": "192.168.1.1",
++ "hostname": "192.168.1.1",
++ "port": "",
++ "pathname": "/",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "http://192.168.257.com",
++ "base": "http://other.com/",
++ "href": "http://192.168.257.com/",
++ "origin": "http://192.168.257.com",
++ "protocol": "http:",
++ "username": "",
++ "password": "",
++ "host": "192.168.257.com",
++ "hostname": "192.168.257.com",
++ "port": "",
++ "pathname": "/",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "http://256",
++ "base": "http://other.com/",
++ "href": "http://0.0.1.0/",
++ "origin": "http://0.0.1.0",
++ "protocol": "http:",
++ "username": "",
++ "password": "",
++ "host": "0.0.1.0",
++ "hostname": "0.0.1.0",
++ "port": "",
++ "pathname": "/",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "http://256.com",
++ "base": "http://other.com/",
++ "href": "http://256.com/",
++ "origin": "http://256.com",
++ "protocol": "http:",
++ "username": "",
++ "password": "",
++ "host": "256.com",
++ "hostname": "256.com",
++ "port": "",
++ "pathname": "/",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "http://999999999",
++ "base": "http://other.com/",
++ "href": "http://59.154.201.255/",
++ "origin": "http://59.154.201.255",
++ "protocol": "http:",
++ "username": "",
++ "password": "",
++ "host": "59.154.201.255",
++ "hostname": "59.154.201.255",
++ "port": "",
++ "pathname": "/",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "http://999999999.com",
++ "base": "http://other.com/",
++ "href": "http://999999999.com/",
++ "origin": "http://999999999.com",
++ "protocol": "http:",
++ "username": "",
++ "password": "",
++ "host": "999999999.com",
++ "hostname": "999999999.com",
++ "port": "",
++ "pathname": "/",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "http://10000000000",
++ "base": "http://other.com/",
++ "failure": true
++ },
++ {
++ "input": "http://10000000000.com",
++ "base": "http://other.com/",
++ "href": "http://10000000000.com/",
++ "origin": "http://10000000000.com",
++ "protocol": "http:",
++ "username": "",
++ "password": "",
++ "host": "10000000000.com",
++ "hostname": "10000000000.com",
++ "port": "",
++ "pathname": "/",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "http://4294967295",
++ "base": "http://other.com/",
++ "href": "http://255.255.255.255/",
++ "origin": "http://255.255.255.255",
++ "protocol": "http:",
++ "username": "",
++ "password": "",
++ "host": "255.255.255.255",
++ "hostname": "255.255.255.255",
++ "port": "",
++ "pathname": "/",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "http://4294967296",
++ "base": "http://other.com/",
++ "failure": true
++ },
++ {
++ "input": "http://0xffffffff",
++ "base": "http://other.com/",
++ "href": "http://255.255.255.255/",
++ "origin": "http://255.255.255.255",
++ "protocol": "http:",
++ "username": "",
++ "password": "",
++ "host": "255.255.255.255",
++ "hostname": "255.255.255.255",
++ "port": "",
++ "pathname": "/",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "http://0xffffffff1",
++ "base": "http://other.com/",
++ "failure": true
++ },
++ {
++ "input": "http://256.256.256.256",
++ "base": "http://other.com/",
++ "failure": true
++ },
++ {
++ "input": "http://256.256.256.256.256",
++ "base": "http://other.com/",
++ "href": "http://256.256.256.256.256/",
++ "origin": "http://256.256.256.256.256",
++ "protocol": "http:",
++ "username": "",
++ "password": "",
++ "host": "256.256.256.256.256",
++ "hostname": "256.256.256.256.256",
++ "port": "",
++ "pathname": "/",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "https://0x.0x.0",
++ "base": "about:blank",
++ "href": "https://0.0.0.0/",
++ "origin": "https://0.0.0.0",
++ "protocol": "https:",
++ "username": "",
++ "password": "",
++ "host": "0.0.0.0",
++ "hostname": "0.0.0.0",
++ "port": "",
++ "pathname": "/",
++ "search": "",
++ "hash": ""
++ },
++ "More IPv4 parsing (via https://github.com/jsdom/whatwg-url/issues/92)",
++ {
++ "input": "https://256.0.0.1/test",
++ "base": "about:blank",
++ "failure": true
++ },
++ "# file URLs containing percent-encoded Windows drive letters (shouldn't work)",
++ {
++ "input": "file:///C%3A/",
++ "base": "about:blank",
++ "href": "file:///C%3A/",
++ "protocol": "file:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "/C%3A/",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "file:///C%7C/",
++ "base": "about:blank",
++ "href": "file:///C%7C/",
++ "protocol": "file:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "/C%7C/",
++ "search": "",
++ "hash": ""
++ },
++ "# file URLs relative to other file URLs (via https://github.com/jsdom/whatwg-url/pull/60)",
++ {
++ "input": "pix/submit.gif",
++ "base": "file:///C:/Users/Domenic/Dropbox/GitHub/tmpvar/jsdom/test/level2/html/files/anchor.html",
++ "href": "file:///C:/Users/Domenic/Dropbox/GitHub/tmpvar/jsdom/test/level2/html/files/pix/submit.gif",
++ "protocol": "file:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "/C:/Users/Domenic/Dropbox/GitHub/tmpvar/jsdom/test/level2/html/files/pix/submit.gif",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "..",
++ "base": "file:///C:/",
++ "href": "file:///C:/",
++ "protocol": "file:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "/C:/",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "..",
++ "base": "file:///",
++ "href": "file:///",
++ "protocol": "file:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "/",
++ "search": "",
++ "hash": ""
++ },
++ "# More file URL tests by zcorpan and annevk",
++ {
++ "input": "/",
++ "base": "file:///C:/a/b",
++ "href": "file:///C:/",
++ "protocol": "file:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "/C:/",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "//d:",
++ "base": "file:///C:/a/b",
++ "href": "file:///d:",
++ "protocol": "file:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "/d:",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "//d:/..",
++ "base": "file:///C:/a/b",
++ "href": "file:///d:/",
++ "protocol": "file:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "/d:/",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "..",
++ "base": "file:///ab:/",
++ "href": "file:///",
++ "protocol": "file:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "/",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "..",
++ "base": "file:///1:/",
++ "href": "file:///",
++ "protocol": "file:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "/",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "",
++ "base": "file:///test?test#test",
++ "href": "file:///test?test",
++ "protocol": "file:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "/test",
++ "search": "?test",
++ "hash": ""
++ },
++ {
++ "input": "file:",
++ "base": "file:///test?test#test",
++ "href": "file:///test?test",
++ "protocol": "file:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "/test",
++ "search": "?test",
++ "hash": ""
++ },
++ {
++ "input": "?x",
++ "base": "file:///test?test#test",
++ "href": "file:///test?x",
++ "protocol": "file:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "/test",
++ "search": "?x",
++ "hash": ""
++ },
++ {
++ "input": "file:?x",
++ "base": "file:///test?test#test",
++ "href": "file:///test?x",
++ "protocol": "file:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "/test",
++ "search": "?x",
++ "hash": ""
++ },
++ {
++ "input": "#x",
++ "base": "file:///test?test#test",
++ "href": "file:///test?test#x",
++ "protocol": "file:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "/test",
++ "search": "?test",
++ "hash": "#x"
++ },
++ {
++ "input": "file:#x",
++ "base": "file:///test?test#test",
++ "href": "file:///test?test#x",
++ "protocol": "file:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "/test",
++ "search": "?test",
++ "hash": "#x"
++ },
++ "# File URLs and many (back)slashes",
++ {
++ "input": "file:///localhost//cat",
++ "base": "about:blank",
++ "href": "file:///localhost//cat",
++ "protocol": "file:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "/localhost//cat",
++ "search": "",
++ "hash": ""
++ },
+ {
+- "input": "http://[fe80:cd00::1257:0:211e:729c]/",
++ "input": "\\//pig",
++ "base": "file://lion/",
++ "href": "file:///pig",
++ "protocol": "file:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "/pig",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "file://",
++ "base": "file://ape/",
++ "href": "file:///",
++ "protocol": "file:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "/",
++ "search": "",
++ "hash": ""
++ },
++ "# Windows drive letter handling with the 'file:' base URL",
++ {
++ "input": "C|#",
++ "base": "file://host/dir/file",
++ "href": "file:///C:#",
++ "protocol": "file:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "/C:",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "C|?",
++ "base": "file://host/dir/file",
++ "href": "file:///C:?",
++ "protocol": "file:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "/C:",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "C|/",
++ "base": "file://host/dir/file",
++ "href": "file:///C:/",
++ "protocol": "file:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "/C:/",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "C|\n/",
++ "base": "file://host/dir/file",
++ "href": "file:///C:/",
++ "protocol": "file:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "/C:/",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "C|\\",
++ "base": "file://host/dir/file",
++ "href": "file:///C:/",
++ "protocol": "file:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "/C:/",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "C",
++ "base": "file://host/dir/file",
++ "href": "file://host/dir/C",
++ "protocol": "file:",
++ "username": "",
++ "password": "",
++ "host": "host",
++ "hostname": "host",
++ "port": "",
++ "pathname": "/dir/C",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "C|a",
++ "base": "file://host/dir/file",
++ "href": "file://host/dir/C|a",
++ "protocol": "file:",
++ "username": "",
++ "password": "",
++ "host": "host",
++ "hostname": "host",
++ "port": "",
++ "pathname": "/dir/C|a",
++ "search": "",
++ "hash": ""
++ },
++ "# Windows drive letter quirk in the file slash state",
++ {
++ "input": "/c:/foo/bar",
++ "base": "file://host/path",
++ "href": "file:///c:/foo/bar",
++ "protocol": "file:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "/c:/foo/bar",
++ "search": "",
++ "hash": ""
++ },
++ "# Windows drive letter quirk (no host)",
++ {
++ "input": "file:/C|/",
+ "base": "about:blank",
+- "href": "http://[fe80:cd00::1257:0:211e:729c]/",
+- "origin": "http://[fe80:cd00::1257:0:211e:729c]",
++ "href": "file:///C:/",
++ "protocol": "file:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "/C:/",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "file://C|/",
++ "base": "about:blank",
++ "href": "file:///C:/",
++ "protocol": "file:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "/C:/",
++ "search": "",
++ "hash": ""
++ },
++ "# Windows drive letter quirk with not empty host",
++ {
++ "input": "file://example.net/C:/",
++ "base": "about:blank",
++ "href": "file:///C:/",
++ "protocol": "file:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "/C:/",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "file://1.2.3.4/C:/",
++ "base": "about:blank",
++ "href": "file:///C:/",
++ "protocol": "file:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "/C:/",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "file://[1::8]/C:/",
++ "base": "about:blank",
++ "href": "file:///C:/",
++ "protocol": "file:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "/C:/",
++ "search": "",
++ "hash": ""
++ },
++ "# file URLs without base URL by Rimas Misevičius",
++ {
++ "input": "file:",
++ "base": "about:blank",
++ "href": "file:///",
++ "protocol": "file:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "/",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "file:?q=v",
++ "base": "about:blank",
++ "href": "file:///?q=v",
++ "protocol": "file:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "/",
++ "search": "?q=v",
++ "hash": ""
++ },
++ {
++ "input": "file:#frag",
++ "base": "about:blank",
++ "href": "file:///#frag",
++ "protocol": "file:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "/",
++ "search": "",
++ "hash": "#frag"
++ },
++ "# IPv6 tests",
++ {
++ "input": "http://[1:0::]",
++ "base": "http://example.net/",
++ "href": "http://[1::]/",
++ "origin": "http://[1::]",
+ "protocol": "http:",
+ "username": "",
+ "password": "",
+- "host": "[fe80:cd00::1257:0:211e:729c]",
+- "hostname": "[fe80:cd00::1257:0:211e:729c]",
++ "host": "[1::]",
++ "hostname": "[1::]",
+ "port": "",
+ "pathname": "/",
+ "search": "",
+- "searchParams": "",
+ "hash": ""
+ },
+- "# IPv6 compression and serialization: Compress sequences of two or more zeroes",
+ {
+- "input": "http://[fe80:cd00:0:0:1257:0:211e:729c]/",
++ "input": "http://[0:1:2:3:4:5:6:7:8]",
++ "base": "http://example.net/",
++ "failure": true
++ },
++ {
++ "input": "https://[0::0::0]",
++ "base": "about:blank",
++ "failure": true
++ },
++ {
++ "input": "https://[0:.0]",
++ "base": "about:blank",
++ "failure": true
++ },
++ {
++ "input": "https://[0:0:]",
++ "base": "about:blank",
++ "failure": true
++ },
++ {
++ "input": "https://[0:1:2:3:4:5:6:7.0.0.0.1]",
++ "base": "about:blank",
++ "failure": true
++ },
++ {
++ "input": "https://[0:1.00.0.0.0]",
++ "base": "about:blank",
++ "failure": true
++ },
++ {
++ "input": "https://[0:1.290.0.0.0]",
++ "base": "about:blank",
++ "failure": true
++ },
++ {
++ "input": "https://[0:1.23.23]",
++ "base": "about:blank",
++ "failure": true
++ },
++ "# Empty host",
++ {
++ "input": "http://?",
+ "base": "about:blank",
+- "href": "http://[fe80:cd00::1257:0:211e:729c]/",
+- "origin": "http://[fe80:cd00::1257:0:211e:729c]",
++ "failure": true
++ },
++ {
++ "input": "http://#",
++ "base": "about:blank",
++ "failure": true
++ },
++ "Port overflow (2^32 + 81)",
++ {
++ "input": "http://f:4294967377/c",
++ "base": "http://example.org/",
++ "failure": true
++ },
++ "Port overflow (2^64 + 81)",
++ {
++ "input": "http://f:18446744073709551697/c",
++ "base": "http://example.org/",
++ "failure": true
++ },
++ "Port overflow (2^128 + 81)",
++ {
++ "input": "http://f:340282366920938463463374607431768211537/c",
++ "base": "http://example.org/",
++ "failure": true
++ },
++ "# Non-special-URL path tests",
++ {
++ "input": "///",
++ "base": "sc://x/",
++ "href": "sc:///",
++ "protocol": "sc:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "/",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "tftp://foobar.com/someconfig;mode=netascii",
++ "base": "about:blank",
++ "href": "tftp://foobar.com/someconfig;mode=netascii",
++ "origin": "null",
++ "protocol": "tftp:",
++ "username": "",
++ "password": "",
++ "host": "foobar.com",
++ "hostname": "foobar.com",
++ "port": "",
++ "pathname": "/someconfig;mode=netascii",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "telnet://user:pass@foobar.com:23/",
++ "base": "about:blank",
++ "href": "telnet://user:pass@foobar.com:23/",
++ "origin": "null",
++ "protocol": "telnet:",
++ "username": "user",
++ "password": "pass",
++ "host": "foobar.com:23",
++ "hostname": "foobar.com",
++ "port": "23",
++ "pathname": "/",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "ut2004://10.10.10.10:7777/Index.ut2",
++ "base": "about:blank",
++ "href": "ut2004://10.10.10.10:7777/Index.ut2",
++ "origin": "null",
++ "protocol": "ut2004:",
++ "username": "",
++ "password": "",
++ "host": "10.10.10.10:7777",
++ "hostname": "10.10.10.10",
++ "port": "7777",
++ "pathname": "/Index.ut2",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "redis://foo:bar@somehost:6379/0?baz=bam&qux=baz",
++ "base": "about:blank",
++ "href": "redis://foo:bar@somehost:6379/0?baz=bam&qux=baz",
++ "origin": "null",
++ "protocol": "redis:",
++ "username": "foo",
++ "password": "bar",
++ "host": "somehost:6379",
++ "hostname": "somehost",
++ "port": "6379",
++ "pathname": "/0",
++ "search": "?baz=bam&qux=baz",
++ "hash": ""
++ },
++ {
++ "input": "rsync://foo@host:911/sup",
++ "base": "about:blank",
++ "href": "rsync://foo@host:911/sup",
++ "origin": "null",
++ "protocol": "rsync:",
++ "username": "foo",
++ "password": "",
++ "host": "host:911",
++ "hostname": "host",
++ "port": "911",
++ "pathname": "/sup",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "git://github.com/foo/bar.git",
++ "base": "about:blank",
++ "href": "git://github.com/foo/bar.git",
++ "origin": "null",
++ "protocol": "git:",
++ "username": "",
++ "password": "",
++ "host": "github.com",
++ "hostname": "github.com",
++ "port": "",
++ "pathname": "/foo/bar.git",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "irc://myserver.com:6999/channel?passwd",
++ "base": "about:blank",
++ "href": "irc://myserver.com:6999/channel?passwd",
++ "origin": "null",
++ "protocol": "irc:",
++ "username": "",
++ "password": "",
++ "host": "myserver.com:6999",
++ "hostname": "myserver.com",
++ "port": "6999",
++ "pathname": "/channel",
++ "search": "?passwd",
++ "hash": ""
++ },
++ {
++ "input": "dns://fw.example.org:9999/foo.bar.org?type=TXT",
++ "base": "about:blank",
++ "href": "dns://fw.example.org:9999/foo.bar.org?type=TXT",
++ "origin": "null",
++ "protocol": "dns:",
++ "username": "",
++ "password": "",
++ "host": "fw.example.org:9999",
++ "hostname": "fw.example.org",
++ "port": "9999",
++ "pathname": "/foo.bar.org",
++ "search": "?type=TXT",
++ "hash": ""
++ },
++ {
++ "input": "ldap://localhost:389/ou=People,o=JNDITutorial",
++ "base": "about:blank",
++ "href": "ldap://localhost:389/ou=People,o=JNDITutorial",
++ "origin": "null",
++ "protocol": "ldap:",
++ "username": "",
++ "password": "",
++ "host": "localhost:389",
++ "hostname": "localhost",
++ "port": "389",
++ "pathname": "/ou=People,o=JNDITutorial",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "git+https://github.com/foo/bar",
++ "base": "about:blank",
++ "href": "git+https://github.com/foo/bar",
++ "origin": "null",
++ "protocol": "git+https:",
++ "username": "",
++ "password": "",
++ "host": "github.com",
++ "hostname": "github.com",
++ "port": "",
++ "pathname": "/foo/bar",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "urn:ietf:rfc:2648",
++ "base": "about:blank",
++ "href": "urn:ietf:rfc:2648",
++ "origin": "null",
++ "protocol": "urn:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "ietf:rfc:2648",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "tag:joe@example.org,2001:foo/bar",
++ "base": "about:blank",
++ "href": "tag:joe@example.org,2001:foo/bar",
++ "origin": "null",
++ "protocol": "tag:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "joe@example.org,2001:foo/bar",
++ "search": "",
++ "hash": ""
++ },
++ "# percent encoded hosts in non-special-URLs",
++ {
++ "input": "non-special://%E2%80%A0/",
++ "base": "about:blank",
++ "href": "non-special://%E2%80%A0/",
++ "protocol": "non-special:",
++ "username": "",
++ "password": "",
++ "host": "%E2%80%A0",
++ "hostname": "%E2%80%A0",
++ "port": "",
++ "pathname": "/",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "non-special://H%4fSt/path",
++ "base": "about:blank",
++ "href": "non-special://H%4fSt/path",
++ "protocol": "non-special:",
++ "username": "",
++ "password": "",
++ "host": "H%4fSt",
++ "hostname": "H%4fSt",
++ "port": "",
++ "pathname": "/path",
++ "search": "",
++ "hash": ""
++ },
++ "# IPv6 in non-special-URLs",
++ {
++ "input": "non-special://[1:2:0:0:5:0:0:0]/",
++ "base": "about:blank",
++ "href": "non-special://[1:2:0:0:5::]/",
++ "protocol": "non-special:",
++ "username": "",
++ "password": "",
++ "host": "[1:2:0:0:5::]",
++ "hostname": "[1:2:0:0:5::]",
++ "port": "",
++ "pathname": "/",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "non-special://[1:2:0:0:0:0:0:3]/",
++ "base": "about:blank",
++ "href": "non-special://[1:2::3]/",
++ "protocol": "non-special:",
++ "username": "",
++ "password": "",
++ "host": "[1:2::3]",
++ "hostname": "[1:2::3]",
++ "port": "",
++ "pathname": "/",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "non-special://[1:2::3]:80/",
++ "base": "about:blank",
++ "href": "non-special://[1:2::3]:80/",
++ "protocol": "non-special:",
++ "username": "",
++ "password": "",
++ "host": "[1:2::3]:80",
++ "hostname": "[1:2::3]",
++ "port": "80",
++ "pathname": "/",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "non-special://[:80/",
++ "base": "about:blank",
++ "failure": true
++ },
++ {
++ "input": "blob:https://example.com:443/",
++ "base": "about:blank",
++ "href": "blob:https://example.com:443/",
++ "protocol": "blob:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "https://example.com:443/",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "blob:d3958f5c-0777-0845-9dcf-2cb28783acaf",
++ "base": "about:blank",
++ "href": "blob:d3958f5c-0777-0845-9dcf-2cb28783acaf",
++ "protocol": "blob:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "d3958f5c-0777-0845-9dcf-2cb28783acaf",
++ "search": "",
++ "hash": ""
++ },
++ "Invalid IPv4 radix digits",
++ {
++ "input": "http://0177.0.0.0189",
++ "base": "about:blank",
++ "href": "http://0177.0.0.0189/",
+ "protocol": "http:",
+ "username": "",
+ "password": "",
+- "host": "[fe80:cd00::1257:0:211e:729c]",
+- "hostname": "[fe80:cd00::1257:0:211e:729c]",
++ "host": "0177.0.0.0189",
++ "hostname": "0177.0.0.0189",
+ "port": "",
+ "pathname": "/",
+ "search": "",
+- "searchParams": "",
+ "hash": ""
+ },
+- "# IPv6 compression and serialization: Compress longest sequence of zeroes",
+ {
+- "input": "http://[fe80:0:0:1257:0:0:0:cd00]/",
++ "input": "http://0x7f.0.0.0x7g",
+ "base": "about:blank",
+- "href": "http://[fe80:0:0:1257::cd00]/",
+- "origin": "http://[fe80:0:0:1257::cd00]",
++ "href": "http://0x7f.0.0.0x7g/",
+ "protocol": "http:",
+ "username": "",
+ "password": "",
+- "host": "[fe80:0:0:1257::cd00]",
+- "hostname": "[fe80:0:0:1257::cd00]",
++ "host": "0x7f.0.0.0x7g",
++ "hostname": "0x7f.0.0.0x7g",
+ "port": "",
+ "pathname": "/",
+ "search": "",
+- "searchParams": "",
+ "hash": ""
+ },
+- "# IPv6 compression and serialization: Do not compress lone zeroes",
+ {
+- "input": "http://[fe80:cd00:0:cde:1257:0:211e:729c]/",
++ "input": "http://0X7F.0.0.0X7G",
+ "base": "about:blank",
+- "href": "http://[fe80:cd00:0:cde:1257:0:211e:729c]/",
+- "origin": "http://[fe80:cd00:0:cde:1257:0:211e:729c]",
++ "href": "http://0x7f.0.0.0x7g/",
+ "protocol": "http:",
+ "username": "",
+ "password": "",
+- "host": "[fe80:cd00:0:cde:1257:0:211e:729c]",
+- "hostname": "[fe80:cd00:0:cde:1257:0:211e:729c]",
++ "host": "0x7f.0.0.0x7g",
++ "hostname": "0x7f.0.0.0x7g",
+ "port": "",
+ "pathname": "/",
+ "search": "",
+- "searchParams": "",
+ "hash": ""
++ },
++ "Invalid IPv4 portion of IPv6 address",
++ {
++ "input": "http://[::127.0.0.0.1]",
++ "base": "about:blank",
++ "failure": true
++ },
++ "Uncompressed IPv6 addresses with 0",
++ {
++ "input": "http://[0:1:0:1:0:1:0:1]",
++ "base": "about:blank",
++ "href": "http://[0:1:0:1:0:1:0:1]/",
++ "protocol": "http:",
++ "username": "",
++ "password": "",
++ "host": "[0:1:0:1:0:1:0:1]",
++ "hostname": "[0:1:0:1:0:1:0:1]",
++ "port": "",
++ "pathname": "/",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "http://[1:0:1:0:1:0:1:0]",
++ "base": "about:blank",
++ "href": "http://[1:0:1:0:1:0:1:0]/",
++ "protocol": "http:",
++ "username": "",
++ "password": "",
++ "host": "[1:0:1:0:1:0:1:0]",
++ "hostname": "[1:0:1:0:1:0:1:0]",
++ "port": "",
++ "pathname": "/",
++ "search": "",
++ "hash": ""
++ },
++ "Percent-encoded query and fragment",
++ {
++ "input": "http://example.org/test?\u0022",
++ "base": "about:blank",
++ "href": "http://example.org/test?%22",
++ "protocol": "http:",
++ "username": "",
++ "password": "",
++ "host": "example.org",
++ "hostname": "example.org",
++ "port": "",
++ "pathname": "/test",
++ "search": "?%22",
++ "hash": ""
++ },
++ {
++ "input": "http://example.org/test?\u0023",
++ "base": "about:blank",
++ "href": "http://example.org/test?#",
++ "protocol": "http:",
++ "username": "",
++ "password": "",
++ "host": "example.org",
++ "hostname": "example.org",
++ "port": "",
++ "pathname": "/test",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "http://example.org/test?\u003C",
++ "base": "about:blank",
++ "href": "http://example.org/test?%3C",
++ "protocol": "http:",
++ "username": "",
++ "password": "",
++ "host": "example.org",
++ "hostname": "example.org",
++ "port": "",
++ "pathname": "/test",
++ "search": "?%3C",
++ "hash": ""
++ },
++ {
++ "input": "http://example.org/test?\u003E",
++ "base": "about:blank",
++ "href": "http://example.org/test?%3E",
++ "protocol": "http:",
++ "username": "",
++ "password": "",
++ "host": "example.org",
++ "hostname": "example.org",
++ "port": "",
++ "pathname": "/test",
++ "search": "?%3E",
++ "hash": ""
++ },
++ {
++ "input": "http://example.org/test?\u2323",
++ "base": "about:blank",
++ "href": "http://example.org/test?%E2%8C%A3",
++ "protocol": "http:",
++ "username": "",
++ "password": "",
++ "host": "example.org",
++ "hostname": "example.org",
++ "port": "",
++ "pathname": "/test",
++ "search": "?%E2%8C%A3",
++ "hash": ""
++ },
++ {
++ "input": "http://example.org/test?%23%23",
++ "base": "about:blank",
++ "href": "http://example.org/test?%23%23",
++ "protocol": "http:",
++ "username": "",
++ "password": "",
++ "host": "example.org",
++ "hostname": "example.org",
++ "port": "",
++ "pathname": "/test",
++ "search": "?%23%23",
++ "hash": ""
++ },
++ {
++ "input": "http://example.org/test?%GH",
++ "base": "about:blank",
++ "href": "http://example.org/test?%GH",
++ "protocol": "http:",
++ "username": "",
++ "password": "",
++ "host": "example.org",
++ "hostname": "example.org",
++ "port": "",
++ "pathname": "/test",
++ "search": "?%GH",
++ "hash": ""
++ },
++ {
++ "input": "http://example.org/test?a#%EF",
++ "base": "about:blank",
++ "href": "http://example.org/test?a#%EF",
++ "protocol": "http:",
++ "username": "",
++ "password": "",
++ "host": "example.org",
++ "hostname": "example.org",
++ "port": "",
++ "pathname": "/test",
++ "search": "?a",
++ "hash": "#%EF"
++ },
++ {
++ "input": "http://example.org/test?a#%GH",
++ "base": "about:blank",
++ "href": "http://example.org/test?a#%GH",
++ "protocol": "http:",
++ "username": "",
++ "password": "",
++ "host": "example.org",
++ "hostname": "example.org",
++ "port": "",
++ "pathname": "/test",
++ "search": "?a",
++ "hash": "#%GH"
++ },
++ "Bad bases",
++ {
++ "input": "test-a.html",
++ "base": "a",
++ "failure": true
++ },
++ {
++ "input": "test-a-slash.html",
++ "base": "a/",
++ "failure": true
++ },
++ {
++ "input": "test-a-slash-slash.html",
++ "base": "a//",
++ "failure": true
++ },
++ {
++ "input": "test-a-colon.html",
++ "base": "a:",
++ "failure": true
++ },
++ {
++ "input": "test-a-colon-slash.html",
++ "base": "a:/",
++ "href": "a:/test-a-colon-slash.html",
++ "protocol": "a:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "/test-a-colon-slash.html",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "test-a-colon-slash-slash.html",
++ "base": "a://",
++ "href": "a:///test-a-colon-slash-slash.html",
++ "protocol": "a:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "/test-a-colon-slash-slash.html",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "test-a-colon-b.html",
++ "base": "a:b",
++ "failure": true
++ },
++ {
++ "input": "test-a-colon-slash-b.html",
++ "base": "a:/b",
++ "href": "a:/test-a-colon-slash-b.html",
++ "protocol": "a:",
++ "username": "",
++ "password": "",
++ "host": "",
++ "hostname": "",
++ "port": "",
++ "pathname": "/test-a-colon-slash-b.html",
++ "search": "",
++ "hash": ""
++ },
++ {
++ "input": "test-a-colon-slash-slash-b.html",
++ "base": "a://b",
++ "href": "a://b/test-a-colon-slash-slash-b.html",
++ "protocol": "a:",
++ "username": "",
++ "password": "",
++ "host": "b",
++ "hostname": "b",
++ "port": "",
++ "pathname": "/test-a-colon-slash-slash-b.html",
++ "search": "",
++ "hash": ""
++ },
++ "Null code point in fragment",
++ {
++ "input": "http://example.org/test?a#b\u0000c",
++ "base": "about:blank",
++ "href": "http://example.org/test?a#bc",
++ "protocol": "http:",
++ "username": "",
++ "password": "",
++ "host": "example.org",
++ "hostname": "example.org",
++ "port": "",
++ "pathname": "/test",
++ "search": "?a",
++ "hash": "#bc"
+ }
+ ]
+diff -u -r --new-file seamonkey-2.53.1.orig/mozilla/toolkit/library/rust/Cargo.lock seamonkey-2.53.1/mozilla/toolkit/library/rust/Cargo.lock
+--- seamonkey-2.53.1.orig/mozilla/toolkit/library/rust/Cargo.lock 2020-02-17 17:39:43.000000000 -0600
++++ seamonkey-2.53.1/mozilla/toolkit/library/rust/Cargo.lock 2020-02-29 21:16:23.120772244 -0600
+@@ -808,7 +808,7 @@
+ "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "nserror 0.1.0",
+ "nsstring 0.1.0",
+- "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
++ "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ ]
+
+ [[package]]
+@@ -1154,7 +1154,7 @@
+
+ [[package]]
+ name = "url"
+-version = "1.5.1"
++version = "1.7.2"
+ source = "registry+https://github.com/rust-lang/crates.io-index"
+ dependencies = [
+ "idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+@@ -1383,7 +1383,7 @@
+ "checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f"
+ "checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
+ "checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91"
+-"checksum url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb819346883532a271eb626deb43c4a1bb4c4dd47c519bd78137c3e72a4fe27"
++"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a"
+ "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
+ "checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c"
+ "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
diff --git a/source/xap/seamonkey/slack-desc b/source/xap/seamonkey/slack-desc
index 414a845d..31325576 100644
--- a/source/xap/seamonkey/slack-desc
+++ b/source/xap/seamonkey/slack-desc
@@ -12,7 +12,7 @@ seamonkey: The SeaMonkey browser suite. SeaMonkey features a state-of-the-art
seamonkey: web browser and powerful email client, as well as a WYSIWYG web page
seamonkey: composer and a feature-rich IRC chat client.
seamonkey:
-seamonkey: Homepage: http://www.mozilla.org/projects/seamonkey/
+seamonkey: Homepage: https://www.seamonkey-project.org/
seamonkey:
seamonkey:
seamonkey: