Update googleurl to the latest version from Chromium

Version used is 222c2227273db27cb5724809c986923147fab4bd from
Tue Nov 2 18:13:07 2021 +0000.

Change-Id: I9a0f35bb724137f99bc3b76439055fa6cc80aef4
diff --git a/AUTHORS b/AUTHORS
index 1aa2922..012e246 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -18,6 +18,7 @@
 Aaryaman Vasishta <jem456.vasishta@gmail.com>
 Abdu Ameen <abdu.ameen000@gmail.com>
 Abhijeet Kandalkar <abhijeet.k@samsung.com>
+Abhinav Vij <abhinav.vij@samsung.com>
 Abhishek Agarwal <abhishek.a21@samsung.com>
 Abhishek Kanike <abhishek.ka@samsung.com>
 Abhishek Singh <abhi.rathore@samsung.com>
@@ -31,6 +32,7 @@
 Adam Yi <i@adamyi.com>
 Addanki Gandhi Kishor <kishor.ag@samsung.com>
 Adenilson Cavalcanti <a.cavalcanti@samsung.com>
+Aditi Singh <a20.singh@samsung.com>
 Aditya Bhargava <heuristicist@gmail.com>
 Adrian Belgun <adrian.belgun@intel.com>
 Adrian Ratiu <adrian.ratiu@collabora.corp-partner.google.com>
@@ -42,6 +44,7 @@
 Akos Kiss <akiss@inf.u-szeged.hu>
 Aku Kotkavuo <a.kotkavuo@partner.samsung.com>
 Aldo Culquicondor <alculquicondor@gmail.com>
+Alec Petridis <alecthechop@gmail.com>
 Aleksandar Stojiljkovic <aleksandar.stojiljkovic@intel.com>
 Aleksei Gurianov <gurianov@gmail.com>
 Alex Chronopoulos <achronop@gmail.com>
@@ -89,6 +92,7 @@
 Andrei Borza <andrei.borza@gmail.com>
 Andrei Parvu <andrei.prv@gmail.com>
 Andrei Parvu <parvu@adobe.com>
+Andreu Botella <andreu@andreubotella.com>
 Andrew Boyarshin <andrew.boyarshin@gmail.com>
 Andrew Brampton <me@bramp.net>
 Andrew Brindamour <abrindamour@bluejeans.com>
@@ -103,6 +107,7 @@
 Ankur Verma <ankur1.verma@samsung.com>
 Anna Henningsen <anna@addaleax.net>
 Anne Kao <annekao94@gmail.com>
+Anshul Jain <anshul.jain@samsung.com>
 Anssi Hannula <anssi.hannula@iki.fi>
 Anthony Halliday <anth.halliday12@gmail.com>
 Anton Bershanskiy <bershanskiy@pm.me>
@@ -127,7 +132,7 @@
 Asami Doi <d0iasm.pub@gmail.com>
 Ashish Kumar Gupta <guptaag@amazon.com>
 Ashlin Joseph <ashlin.j@samsung.com>
-Ashutosh  <coder.commando@gmail.com>
+Ashutosh  <codingtosh@gmail.com>
 Asish Singh <asish.singh@samsung.com>
 Attila Dusnoki <dati91@gmail.com>
 Avinaash Doreswamy <avi.nitk@samsung.com>
@@ -204,6 +209,7 @@
 Chaobin Zhang <zhchbin@gmail.com>
 Charles Vaughn <cvaughn@gmail.com>
 Cheng Zhao <zcbenz@gmail.com>
+Cheng Yu <yuzichengcode@gmail.com>
 Choongwoo Han <cwhan.tunz@gmail.com>
 Chris Greene <cwgreene@amazon.com>
 Chris Harrelson <chrishtr@gmail.com>
@@ -271,12 +277,14 @@
 Deepak Mohan <hop2deep@gmail.com>
 Deepak Sharma <deepak.sharma@amd.com>
 Deepak Singla <deepak.s@samsung.com>
+Deniz Eren Evrendilek <devrendilek@gmail.com>
 Deokjin Kim <deokjin81.kim@samsung.com>
 Derek Halman <d.halman@gmail.com>
 Devlin Cronin <rdevlin.cronin@gmail.com>
 Dhi Aurrahman <dio@rockybars.com>
 Di Wu <meetwudi@gmail.com>
 Diana Suvorova <diana.suvorova@gmail.com>
+Diego Fernández Santos <agujaydedal@gmail.com>
 Diego Ferreiro Val <elfogris@gmail.com>
 Dillon Sellars <dill.sellars@gmail.com>
 Divya Bansal <divya.bansal@samsung.com>
@@ -309,6 +317,7 @@
 Eero Häkkinen <eero.hakkinen@intel.com>
 Egor Starkov <egor.starkov@samsung.com>
 Ehsan Akhgari <ehsan.akhgari@gmail.com>
+Ehsan Akhgari <ehsan@mightyapp.com>
 Elan Ruusamäe <elan.ruusamae@gmail.com>
 Ergun Erdogmus <erdogmusergun@gmail.com>
 Eric Ahn <byungwook.ahn@gmail.com>
@@ -337,6 +346,7 @@
 Fernando Jiménez Moreno <ferjmoreno@gmail.com>
 Finbar Crago <finbar.crago@gmail.com>
 François Beaufort <beaufort.francois@gmail.com>
+François Devatine <devatine@verizonmedia.com>
 Francois Kritzinger <francoisk777@gmail.com>
 Francois Marier <francois@brave.com>
 Francois Rauch <leopardb@gmail.com>
@@ -416,7 +426,9 @@
 Hwanseung Lee <hs1217.lee@samsung.com>
 Hyemi Shin <hyemi.sin@samsung.com>
 HyeockJin Kim <kherootz@gmail.com>
+Hyojeong Kim <42.4.hyojekim@gmail.com>
 Hyungchan Kim <inlinechan@gmail.com>
+Hyungun Kim <khw3754@gmail.com>
 Hyungwook Lee <hyungwook.lee@navercorp.com>
 Hyungwook Lee <withlhw@gmail.com>
 HyunJi Kim <hjkim3323@gmail.com>
@@ -451,6 +463,7 @@
 Jaeseok Yoon <yjaeseok@gmail.com>
 Jaewon Choi <jaewon.james.choi@gmail.com>
 Jaeyong Bae <jdragon.bae@gmail.com>
+Jagdish Chourasia <jagdish.c@samsung.com>
 Jaime Soriano Pastor <jsorianopastor@gmail.com>
 Jake Helfert <jake@helfert.us>
 Jake Hendy <me@jakehendy.com>
@@ -477,6 +490,7 @@
 Jeado Ko <haibane84@gmail.com>
 Jeffrey C <jeffreyca16@gmail.com>
 Jeffrey Yeung <jeffrey.yeung@poly.com>
+Jeong A Shin <jeonga@khu.ac.kr>
 Jeongeun Kim <je_julie.kim@samsung.com>
 Jeongmin Kim <kimwjdalsl@gmail.com>
 Jeongwoo Park <jwoo.park@navercorp.com>
@@ -558,6 +572,7 @@
 Joyer Huang <collger@gmail.com>
 Juan Cruz Viotti <jv@jviotti.com>
 Juan Jose Lopez Jaimez <jj.lopezjaimez@gmail.com>
+Juba Borgohain <chromiumjuba@gmail.com>
 Juhui Lee <juhui24.lee@samsung.com>
 Julian Geppert <spctstr@gmail.com>
 Julien Brianceau <jbriance@cisco.com>
@@ -565,6 +580,7 @@
 Julien Racle <jracle@logitech.com>
 Jun Fang <jun_fang@foxitsoftware.com>
 Jun Jiang <jun.a.jiang@intel.com>
+Jungchang Park <valley84265@gmail.com>
 Junchao Han <junchao.han@intel.com>
 Junghoon Lee <sjh836@gmail.com>
 Junghyuk Yoo <wjdgurdl272@gmail.com>
@@ -595,6 +611,7 @@
 Kaustubh Atrawalkar <kaustubh.ra@gmail.com>
 Ke He <ke.he@intel.com>
 Keene Pan <keenepan@linpus.com>
+Keiichiro Nagashima <n4ag3a2sh1i@gmail.com>
 Keita Suzuki <keitasuzuki.park@gmail.com>
 Keita Yoshimoto <y073k3@gmail.com>
 Keith Chen <keitchen@amazon.com>
@@ -603,6 +620,7 @@
 Kenneth Zhou <knthzh@gmail.com>
 Kenny Levinsen <kl@kl.wtf>
 Keonho Kim <keonho07.kim@samsung.com>
+Ketan Atri <ketan.atri@samsung.com>
 Ketan Goyal <ketan.goyal@samsung.com>
 Kevin Gibbons <bakkot@gmail.com>
 Kevin Lee Helpingstine <sig11@reprehensible.net>
@@ -693,6 +711,7 @@
 Marc des Garets <marc.desgarets@googlemail.com>
 Marcin Wiacek <marcin@mwiacek.com>
 Marco Rodrigues <gothicx@gmail.com>
+Marcos Caceres <marcos@marcosc.com>
 Mariam Ali <alimariam@noogler.google.com>
 Mario Pistrich <m.pistrich@gmail.com>
 Mario Sanchez Prada <mario.prada@samsung.com>
@@ -736,6 +755,7 @@
 Md. Hasanur Rashid <hasanur.r@samsung.com>
 Md Jobed Hossain <jobed.h@samsung.com>
 Md Sami Uddin <md.sami@samsung.com>
+Micha Hanselmann <micha.hanselmann@gmail.com>
 Michael Cirone <mikecirone@gmail.com>
 Michael Constant <mconst@gmail.com>
 Michael Forney <mforney@mforney.org>
@@ -760,6 +780,7 @@
 Milton Chiang <milton.chiang@mediatek.com>
 Milutin Smiljanic <msmiljanic.gm@gmail.com>
 Minchul Kang <tegongkang@gmail.com>
+Mingeun Park <mindal99546@gmail.com>
 Minggang Wang <minggang.wang@intel.com>
 Mingmin Xie <melvinxie@gmail.com>
 Minjeong Kim <deoxyribonucleicacid150@gmail.com>
@@ -795,6 +816,7 @@
 Naveen Kumar S G <naveensg@samsung.com>
 Nayan Kumar K <qtc746@motorola.com>
 Nayeem Hasan <nayeemhasan.nh01@gmail.com>
+Nayeon Kim <skdus3373@gmail.com>
 Neal Gompa <ngompa13@gmail.com>
 Ned Williamson <nedwilliamson@gmail.com>
 Nedeljko Babic <nedeljko.babic@imgtec.com>
@@ -888,6 +910,7 @@
 Raghavendra Ghatage <r.ghatage@samsung.com>
 Raghu Ram Nagaraj <r.nagaraj@samsung.com>
 Rahul Gupta <rahul.g@samsung.com>
+Rahul Yadav <rahul.yadav@samsung.com>
 Rajesh Mahindra <rmahindra@uber.com>
 Rajneesh Rana <rajneesh.r@samsung.com>
 Raman Tenneti <raman.tenneti@gmail.com>
@@ -906,7 +929,7 @@
 Réda Housni Alaoui <alaoui.rda@gmail.com>
 Refael Ackermann <refack@gmail.com>
 Rémi Arnaud <jsremi@gmail.com>
-Renata Hodovan <rhodovan.u-szeged@partner.samsung.com>
+Renata Hodovan <hodovan.renata@gmail.com>
 Rene Bolldorf <rb@radix.io>
 Rene Ladan <r.c.ladan@gmail.com>
 Richard Baranyi <lordprotector@gmail.com>
@@ -931,6 +954,7 @@
 Rosen Dash <rosen.dash@gmail.com>
 Ross Kirsling <rkirsling@gmail.com>
 Ross Wollman <ross.wollman@gmail.com>
+Ruan Beihong <ruanbeihong@gmail.com>
 ruben <chromium@hybridsource.org>
 Ruben Bridgewater <ruben@bridgewater.de>
 Ruben Terrazas <rubentopo@gmail.com>
@@ -1019,6 +1043,7 @@
 Shreyas Gopal <shreyas.g@samsung.com>
 Shreyas VA <v.a.shreyas@gmail.com>
 Shubham Agrawal <shubag@amazon.com>
+Shubham Gupta <shubh.gupta@samsung.com>
 Siba Samal <siba.samal@samsung.com>
 Siddharth Bagai <b.siddharth@samsung.com>
 Siddharth Shankar <funkysidd@gmail.com>
@@ -1079,7 +1104,10 @@
 Taeheon Kim <skyrabbits1@gmail.com>
 Taeho Nam <thn7440@gmail.com>
 Taehoon Lee <taylor.hoon@gmail.com>
+Taeseong Yu <yugeeklab@gmail.com>
+Taeyeon Kim <ssg9732@gmail.com>
 Tae Shin <taeshindev@gmail.com>
+Takaaki Suzuki <takaakisuzuki.14@gmail.com>
 Takashi Fujita <tgfjt.mail@gmail.com>
 Takeshi Kurosawa <taken.spc@gmail.com>
 Tanay Chowdhury <tanay.c@samsung.com>
@@ -1241,6 +1269,7 @@
 Zoltan Kuscsik <zoltan.kuscsik@linaro.org>
 Zsolt Borbely <zsborbely.u-szeged@partner.samsung.com>
 方觉 (Fang Jue) <fangjue23303@gmail.com>
+迷渡 <justjavac@gmail.com>
 # Please DO NOT APPEND here. See comments at the top of the file.
 # END individuals section.
 
@@ -1296,6 +1325,8 @@
 Pengutronix e.K. <*@pengutronix.de>
 Rakuten Kobo Inc. <*@kobo.com>
 Rakuten Kobo Inc. <*@rakuten.com>
+Red Hat Inc. <*@redhat.com>
+Semihalf <*@semihalf.com>
 Seznam.cz, a.s. <*@firma.seznam.cz>
 Slack Technologies Inc. <*@slack-corp.com>
 Spotify AB <*@spotify.com>
diff --git a/base/compiler_specific.h b/base/compiler_specific.h
index 6651220..58a7d0d 100644
--- a/base/compiler_specific.h
+++ b/base/compiler_specific.h
@@ -51,7 +51,7 @@
 // Annotate a function indicating it should not be inlined.
 // Use like:
 //   NOINLINE void DoStuff() { ... }
-#if defined(COMPILER_GCC)
+#if defined(COMPILER_GCC) || defined(__clang__)
 #define NOINLINE __attribute__((noinline))
 #elif defined(COMPILER_MSVC)
 #define NOINLINE __declspec(noinline)
diff --git a/base/containers/span.h b/base/containers/span.h
index d43814e..550eec8 100644
--- a/base/containers/span.h
+++ b/base/containers/span.h
@@ -19,7 +19,6 @@
 #include "base/containers/contiguous_iterator.h"
 #include "base/cxx17_backports.h"
 #include "base/cxx20_to_address.h"
-#include "base/macros.h"
 #include "base/template_util.h"
 
 namespace gurl_base {
diff --git a/base/cxx17_backports.h b/base/cxx17_backports.h
index 77d689a..81e573f 100644
--- a/base/cxx17_backports.h
+++ b/base/cxx17_backports.h
@@ -10,8 +10,12 @@
 #include <initializer_list>
 #include <memory>
 #include <string>
+#include <tuple>
+#include <type_traits>
+#include <utility>
 
 #include "polyfills/base/check.h"
+#include "base/functional/invoke.h"
 
 namespace gurl_base {
 
@@ -105,7 +109,27 @@
 
 template <typename T>
 constexpr const T& clamp(const T& v, const T& lo, const T& hi) {
-  return clamp(v, lo, hi, std::less<T>{});
+  return gurl_base::clamp(v, lo, hi, std::less<T>{});
+}
+
+// C++14 implementation of C++17's std::apply():
+// https://en.cppreference.com/w/cpp/utility/apply
+namespace internal {
+template <class F, class Tuple, std::size_t... I>
+constexpr decltype(auto) apply_impl(F&& f,
+                                    Tuple&& t,
+                                    std::index_sequence<I...>) {
+  return gurl_base::invoke(std::forward<F>(f),
+                      std::get<I>(std::forward<Tuple>(t))...);
+}
+}  // namespace internal
+
+template <class F, class Tuple>
+constexpr decltype(auto) apply(F&& f, Tuple&& t) {
+  return internal::apply_impl(
+      std::forward<F>(f), std::forward<Tuple>(t),
+      std::make_index_sequence<
+          std::tuple_size<std::remove_reference_t<Tuple>>::value>{});
 }
 
 }  // namespace base
diff --git a/base/debug/leak_annotations.h b/base/debug/leak_annotations.h
index dc50246..b551552 100644
--- a/base/debug/leak_annotations.h
+++ b/base/debug/leak_annotations.h
@@ -5,7 +5,6 @@
 #ifndef BASE_DEBUG_LEAK_ANNOTATIONS_H_
 #define BASE_DEBUG_LEAK_ANNOTATIONS_H_
 
-#include "base/macros.h"
 #include "build/build_config.h"
 
 // This file defines macros which can be used to annotate intentional memory
@@ -26,9 +25,12 @@
 class ScopedLeakSanitizerDisabler {
  public:
   ScopedLeakSanitizerDisabler() { __lsan_disable(); }
+
+  ScopedLeakSanitizerDisabler(const ScopedLeakSanitizerDisabler&) = delete;
+  ScopedLeakSanitizerDisabler& operator=(const ScopedLeakSanitizerDisabler&) =
+      delete;
+
   ~ScopedLeakSanitizerDisabler() { __lsan_enable(); }
- private:
-  DISALLOW_COPY_AND_ASSIGN(ScopedLeakSanitizerDisabler);
 };
 
 #define ANNOTATE_SCOPED_MEMORY_LEAK \
diff --git a/base/strings/safe_sprintf.cc b/base/strings/safe_sprintf.cc
index 0569da1..c9a69ec 100644
--- a/base/strings/safe_sprintf.cc
+++ b/base/strings/safe_sprintf.cc
@@ -126,6 +126,9 @@
     DEBUG_CHECK(size <= kSSizeMax);
   }
 
+  Buffer(const Buffer&) = delete;
+  Buffer& operator=(const Buffer&) = delete;
+
   ~Buffer() {
     // The code calling the constructor guaranteed that there was enough space
     // to store a trailing NUL -- and in debug builds, we are actually
@@ -270,8 +273,6 @@
   // was sufficiently big. This number always excludes the trailing NUL byte
   // and it is guaranteed to never grow bigger than kSSizeMax-1.
   size_t count_;
-
-  DISALLOW_COPY_AND_ASSIGN(Buffer);
 };
 
 
diff --git a/base/strings/safe_sprintf_unittest.cc b/base/strings/safe_sprintf_unittest.cc
index cde415d..be8af13 100644
--- a/base/strings/safe_sprintf_unittest.cc
+++ b/base/strings/safe_sprintf_unittest.cc
@@ -466,14 +466,17 @@
     internal::SetSafeSPrintfSSizeMaxForTest(sz);
   }
 
+  ScopedSafeSPrintfSSizeMaxSetter(const ScopedSafeSPrintfSSizeMaxSetter&) =
+      delete;
+  ScopedSafeSPrintfSSizeMaxSetter& operator=(
+      const ScopedSafeSPrintfSSizeMaxSetter&) = delete;
+
   ~ScopedSafeSPrintfSSizeMaxSetter() {
     internal::SetSafeSPrintfSSizeMaxForTest(old_ssize_max_);
   }
 
  private:
   size_t old_ssize_max_;
-
-  DISALLOW_COPY_AND_ASSIGN(ScopedSafeSPrintfSSizeMaxSetter);
 };
 #endif
 
diff --git a/base/strings/string_piece.h b/base/strings/string_piece.h
index 8a22e8d..f01722d 100644
--- a/base/strings/string_piece.h
+++ b/base/strings/string_piece.h
@@ -23,6 +23,7 @@
 
 #include <stddef.h>
 
+#include <algorithm>
 #include <iosfwd>
 #include <limits>
 #include <string>
diff --git a/build/build_config.h b/build/build_config.h
index daf51ff..63cec87 100644
--- a/build/build_config.h
+++ b/build/build_config.h
@@ -90,6 +90,8 @@
 #define OS_AIX 1
 #elif defined(__asmjs__) || defined(__wasm__)
 #define OS_ASMJS 1
+#elif defined(__MVS__)
+#define OS_ZOS 1
 #else
 #error Please add support for your platform in build/build_config.h
 #endif
@@ -112,7 +114,7 @@
     defined(OS_FREEBSD) || defined(OS_IOS) || defined(OS_LINUX) ||  \
     defined(OS_CHROMEOS) || defined(OS_MAC) || defined(OS_NACL) ||  \
     defined(OS_NETBSD) || defined(OS_OPENBSD) || defined(OS_QNX) || \
-    defined(OS_SOLARIS)
+    defined(OS_SOLARIS) || defined(OS_ZOS)
 #define OS_POSIX 1
 #endif
 
diff --git a/copy.bara.sky b/copy.bara.sky
index 33c0f00..ffe4f61 100644
--- a/copy.bara.sky
+++ b/copy.bara.sky
@@ -64,6 +64,7 @@
     "base/debug/alias.h",
     "base/export_template.h",
     "base/logging.h",
+    "base/metrics/histogram_macros.h",
     "base/notreached.h",
     "base/trace_event/memory_usage_estimator.h",
     "third_party/perfetto/include/perfetto/tracing/traced_value.h",
diff --git a/polyfills/base/metrics/histogram_macros.h b/polyfills/base/metrics/histogram_macros.h
index 127c53c..efd8cff 100644
--- a/polyfills/base/metrics/histogram_macros.h
+++ b/polyfills/base/metrics/histogram_macros.h
@@ -6,6 +6,7 @@
 #define POLYFILLS_BASE_METRICS_HISTOGRAM_MACROS_H_
 
 #define UMA_HISTOGRAM_ENUMERATION(name, ...) do {} while(false)
+#define UMA_HISTOGRAM_BOOLEAN(name, ...) do {} while(false)
 
 #endif  /* POLYFILLS_BASE_METRICS_HISTOGRAM_MACROS_H_ */
 
diff --git a/url/gurl.cc b/url/gurl.cc
index 18a46f1..474919a 100644
--- a/url/gurl.cc
+++ b/url/gurl.cc
@@ -238,7 +238,7 @@
 
   output.Complete();
 
-  ProcessFileOrFileSystemURLAfterReplaceComponents(result);
+  result.ProcessFileSystemURLAfterReplaceComponents();
   return result;
 }
 
@@ -258,41 +258,28 @@
 
   output.Complete();
 
-  ProcessFileOrFileSystemURLAfterReplaceComponents(result);
+  result.ProcessFileSystemURLAfterReplaceComponents();
 
   return result;
 }
 
-void GURL::ProcessFileOrFileSystemURLAfterReplaceComponents(GURL& url) const {
-  if (!url.is_valid_)
+void GURL::ProcessFileSystemURLAfterReplaceComponents() {
+  if (!is_valid_)
     return;
-  if (url.SchemeIsFileSystem()) {
-    url.inner_url_ =
-        std::make_unique<GURL>(url.spec_.data(), url.parsed_.Length(),
-                               *url.parsed_.inner_parsed(), true);
+  if (SchemeIsFileSystem()) {
+    inner_url_ = std::make_unique<GURL>(spec_.data(), parsed_.Length(),
+                                        *parsed_.inner_parsed(), true);
   }
-#ifdef WIN32
-  if (url.SchemeIsFile()) {
-    // On Win32, some file URLs created through ReplaceComponents used to lose
-    // its hostname after getting reparsed (e.g. when it's sent through IPC) due
-    // to special handling of file URLs with Windows-drive paths in the URL
-    // parser. To make the behavior for URLs modified through ReplaceComponents
-    // (instead of getting fully reparsed) the same, immediately reparse the
-    // URL here to trigger the special handling.
-    // See https://crbug.com/1214098.
-    url = GURL(url.spec());
-  }
-#endif
 }
 
-GURL GURL::GetOrigin() const {
+GURL GURL::DeprecatedGetOriginAsURL() const {
   // This doesn't make sense for invalid or nonstandard URLs, so return
   // the empty URL.
   if (!is_valid_ || !IsStandard())
     return GURL();
 
   if (SchemeIsFileSystem())
-    return inner_url_->GetOrigin();
+    return inner_url_->DeprecatedGetOriginAsURL();
 
   url::Replacements<char> replacements;
   replacements.ClearUsername();
diff --git a/url/gurl.h b/url/gurl.h
index c70c5a4..64a2ee3 100644
--- a/url/gurl.h
+++ b/url/gurl.h
@@ -197,7 +197,13 @@
   //
   // It is an error to get the origin of an invalid URL. The result
   // will be the empty URL.
-  GURL GetOrigin() const;
+  //
+  // WARNING: Please avoid converting urls into origins if at all possible!
+  // //docs/security/origin-vs-url.md is a list of gotchas that can result. Such
+  // conversions will likely return a wrong result for about:blank and/or
+  // in the presence of iframe.sandbox attribute. Prefer to get origins directly
+  // from the source (e.g. RenderFrameHost::GetLastCommittedOrigin).
+  GURL DeprecatedGetOriginAsURL() const;
 
   // A helper function to return a GURL stripped from the elements that are not
   // supposed to be sent as HTTP referrer: username, password and ref fragment.
@@ -468,7 +474,7 @@
     return gurl_base::StringPiece(&spec_[comp.begin], comp.len);
   }
 
-  void ProcessFileOrFileSystemURLAfterReplaceComponents(GURL& url) const;
+  void ProcessFileSystemURLAfterReplaceComponents();
 
   // The actual text of the URL, in canonical ASCII form.
   std::string spec_;
diff --git a/url/gurl_unittest.cc b/url/gurl_unittest.cc
index f3b9f3c..68817af 100644
--- a/url/gurl_unittest.cc
+++ b/url/gurl_unittest.cc
@@ -398,7 +398,7 @@
   };
   for (size_t i = 0; i < gurl_base::size(cases); i++) {
     GURL url(cases[i].input);
-    GURL origin = url.GetOrigin();
+    GURL origin = url.DeprecatedGetOriginAsURL();
     EXPECT_EQ(cases[i].expected, origin.spec());
   }
 }
@@ -558,23 +558,34 @@
   // http://crbug.com/291747 - a data URL may legitimately have trailing
   // whitespace in the spec after the ref is cleared. Test this does not trigger
   // the Parsed importing validation GURL_DCHECK in GURL.
-  GURL url(" data: one ? two # three ");
+  GURL url(" data: one # two ");
+  EXPECT_TRUE(url.is_valid());
 
   // By default the trailing whitespace will have been stripped.
-  EXPECT_EQ("data: one ?%20two%20#%20three", url.spec());
+  EXPECT_EQ("data: one #%20two", url.spec());
+
+  // Clear the URL's ref and observe the trailing whitespace.
   GURL::Replacements repl;
   repl.ClearRef();
   GURL url_no_ref = url.ReplaceComponents(repl);
-
-  EXPECT_EQ("data: one ?%20two%20", url_no_ref.spec());
+  EXPECT_TRUE(url_no_ref.is_valid());
+  EXPECT_EQ("data: one ", url_no_ref.spec());
 
   // Importing a parsed URL via this constructor overload will retain trailing
   // whitespace.
   GURL import_url(url_no_ref.spec(),
                   url_no_ref.parsed_for_possibly_invalid_spec(),
                   url_no_ref.is_valid());
+  EXPECT_TRUE(import_url.is_valid());
   EXPECT_EQ(url_no_ref, import_url);
-  EXPECT_EQ(import_url.query(), "%20two%20");
+  EXPECT_EQ("data: one ", import_url.spec());
+  EXPECT_EQ(" one ", import_url.path());
+
+  // For completeness, test that re-parsing the same URL rather than importing
+  // it trims the trailing whitespace.
+  GURL reparsed_url(url_no_ref.spec());
+  EXPECT_TRUE(reparsed_url.is_valid());
+  EXPECT_EQ("data: one", reparsed_url.spec());
 }
 
 TEST(GURLTest, PathForRequest) {
diff --git a/url/origin_abstract_tests.h b/url/origin_abstract_tests.h
index 82d1f55..4aaf495 100644
--- a/url/origin_abstract_tests.h
+++ b/url/origin_abstract_tests.h
@@ -370,15 +370,7 @@
       {"file:///etc/passwd", {"file", "", 0}},
       {"file://example.com/etc/passwd", {"file", "example.com", 0}},
       {"file:///", {"file", "", 0}},
-
-#ifdef WIN32
-      // TODO(https://crbug.com/1214098): Consider unifying URL parsing behavior
-      // on all platforms (or at least make sure that serialization always
-      // round-trips - see https://crbug.com/1214098).
-      {"file://hostname/C:/dir/file.txt", {"file", "", 0}},
-#else
       {"file://hostname/C:/dir/file.txt", {"file", "hostname", 0}},
-#endif
 
       // HTTP URLs
       {"http://example.com/", {"http", "example.com", 80}},
diff --git a/url/scheme_host_port_unittest.cc b/url/scheme_host_port_unittest.cc
index a8bde47..e55c9d5 100644
--- a/url/scheme_host_port_unittest.cc
+++ b/url/scheme_host_port_unittest.cc
@@ -16,12 +16,14 @@
 class SchemeHostPortTest : public testing::Test {
  public:
   SchemeHostPortTest() = default;
+
+  SchemeHostPortTest(const SchemeHostPortTest&) = delete;
+  SchemeHostPortTest& operator=(const SchemeHostPortTest&) = delete;
+
   ~SchemeHostPortTest() override = default;
 
  private:
   url::ScopedSchemeRegistryForTests scoped_registry_;
-
-  DISALLOW_COPY_AND_ASSIGN(SchemeHostPortTest);
 };
 
 void ExpectParsedUrlsEqual(const GURL& a, const GURL& b) {
diff --git a/url/url_canon_fileurl.cc b/url/url_canon_fileurl.cc
index 8f6c2f8..b0740a2 100644
--- a/url/url_canon_fileurl.cc
+++ b/url/url_canon_fileurl.cc
@@ -4,6 +4,7 @@
 
 // Functions for canonicalizing "file:" URLs.
 
+#include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
 #include "url/url_canon.h"
 #include "url/url_canon_internal.h"
@@ -14,6 +15,44 @@
 
 namespace {
 
+bool IsLocalhost(const char* spec, int begin, int end) {
+  if (begin > end)
+    return false;
+  return gurl_base::StringPiece(&spec[begin], end - begin) == "localhost";
+}
+
+bool IsLocalhost(const char16_t* spec, int begin, int end) {
+  if (begin > end)
+    return false;
+  return gurl_base::StringPiece16(&spec[begin], end - begin) == u"localhost";
+}
+
+template <typename CHAR>
+int DoFindWindowsDriveLetter(const CHAR* spec, int begin, int end) {
+  if (begin > end)
+    return -1;
+
+  // First guess the beginning of the drive letter.
+  // If there is something that looks like a drive letter in the spec between
+  // begin and end, store its position in drive_letter_pos.
+  int drive_letter_pos =
+      DoesContainWindowsDriveSpecUntil(spec, begin, end, end);
+  if (drive_letter_pos < begin)
+    return -1;
+
+  // Check if the path up to the drive letter candidate can be canonicalized as
+  // "/".
+  Component sub_path = MakeRange(begin, drive_letter_pos);
+  RawCanonOutput<1024> output;
+  Component output_path;
+  bool success = CanonicalizePath(spec, sub_path, &output, &output_path);
+  if (!success || output_path.len != 1 || output.at(output_path.begin) != '/') {
+    return -1;
+  }
+
+  return drive_letter_pos;
+}
+
 #ifdef WIN32
 
 // Given a pointer into the spec, this copies and canonicalizes the drive
@@ -21,41 +60,16 @@
 // spec, it won't do anything. The index of the next character in the input
 // spec is returned (after the colon when a drive spec is found, the begin
 // offset if one is not).
-template<typename CHAR>
-int FileDoDriveSpec(const CHAR* spec, int begin, int end,
-                    CanonOutput* output) {
-  // The path could be one of several things: /foo/bar, c:/foo/bar, /c:/foo,
-  // /./c:/foo, (with backslashes instead of slashes as well). The code
-  // first guesses the beginning of the drive letter, then verifies that the
-  // path up to that point can be canonicalised as "/". If it can, then the
-  // found drive letter is indeed a drive letter, otherwise the path has no
-  // drive letter in it.
-  if (begin > end)  // Nothing to search in.
-    return begin;   // Found no letter, so didn't consum any characters.
-
-  // If there is something that looks like a drive letter in the spec between
-  // being and end, store its position in drive_letter_pos.
-  int drive_letter_pos =
-      DoesContainWindowsDriveSpecUntil(spec, begin, end, end);
+template <typename CHAR>
+int FileDoDriveSpec(const CHAR* spec, int begin, int end, CanonOutput* output) {
+  int drive_letter_pos = FindWindowsDriveLetter(spec, begin, end);
   if (drive_letter_pos < begin)
-    return begin;  // Found no letter, so didn't consum any characters.
+    return begin;
 
-  // Check if the path up to the drive letter candidate can be canonicalized as
-  // "/".
-  Component sub_path = MakeRange(begin, drive_letter_pos);
-  Component output_path;
-  const int initial_length = output->length();
-  bool success = CanonicalizePath(spec, sub_path, output, &output_path);
-  if (!success || output_path.len != 1 ||
-      output->at(output_path.begin) != '/') {
-    // Undo writing the canonicalized path.
-    output->set_length(initial_length);
-    return begin;  // Found no letter, so didn't consum any characters.
-  }
+  // By now, a valid drive letter is confirmed at position drive_letter_pos,
+  // followed by a valid drive letter separator (a colon or a pipe).
 
-  // By now, "/" has been written to the output and a valid drive letter is
-  // confirmed at position drive_letter_pos, followed by a valid drive letter
-  // separator (a colon or a pipe).
+  output->push_back('/');
 
   // Normalize Windows drive letters to uppercase.
   if (gurl_base::IsAsciiLower(spec[drive_letter_pos]))
@@ -88,9 +102,12 @@
   // drive colon (if any, Windows only), or the first slash of the path.
   bool success = true;
   if (after_drive < path.end()) {
-    // Use the regular path canonicalizer to canonicalize the rest of the
-    // path. Give it a fake output component to write into. DoCanonicalizeFile
-    // will compute the full path component.
+    // Use the regular path canonicalizer to canonicalize the rest of the path
+    // after the drive.
+    //
+    // Give it a fake output component to write into, since we will be
+    // calculating the out_path ourselves (consisting of both the drive and the
+    // path we canonicalize here).
     Component sub_path = MakeRange(after_drive, path.end());
     Component fake_output_path;
     success = CanonicalizePath(spec, sub_path, output, &fake_output_path);
@@ -120,19 +137,33 @@
   output->Append("file://", 7);
   new_parsed->scheme.len = 4;
 
+  // If the host is localhost, and the path starts with a Windows drive letter,
+  // remove the host component. This does the following transformation:
+  //     file://localhost/C:/hello.txt -> file:///C:/hello.txt
+  //
+  // Note: we do this on every platform per URL Standard, not just Windows.
+  //
+  // TODO(https://crbug.com/688961): According to the latest URL spec, this
+  // transformation should be done regardless of the path.
+  Component host_range = parsed.host;
+  if (IsLocalhost(source.host, host_range.begin, host_range.end()) &&
+      FindWindowsDriveLetter(source.path, parsed.path.begin,
+                             parsed.path.end()) >= parsed.path.begin) {
+    host_range.reset();
+  }
+
   // Append the host. For many file URLs, this will be empty. For UNC, this
   // will be present.
   // TODO(brettw) This doesn't do any checking for host name validity. We
   // should probably handle validity checking of UNC hosts differently than
   // for regular IP hosts.
-  bool success = CanonicalizeHost(source.host, parsed.host,
-                                  output, &new_parsed->host);
+  bool success =
+      CanonicalizeHost(source.host, host_range, output, &new_parsed->host);
   success &= DoFileCanonicalizePath<CHAR, UCHAR>(source.path, parsed.path,
                                     output, &new_parsed->path);
+
   CanonicalizeQuery(source.query, parsed.query, query_converter,
                     output, &new_parsed->query);
-
-  // Ignore failure for refs since the URL can probably still be loaded.
   CanonicalizeRef(source.ref, parsed.ref, output, &new_parsed->ref);
 
   return success;
@@ -140,6 +171,14 @@
 
 } // namespace
 
+int FindWindowsDriveLetter(const char* spec, int begin, int end) {
+  return DoFindWindowsDriveLetter(spec, begin, end);
+}
+
+int FindWindowsDriveLetter(const char16_t* spec, int begin, int end) {
+  return DoFindWindowsDriveLetter(spec, begin, end);
+}
+
 bool CanonicalizeFileURL(const char* spec,
                          int spec_len,
                          const Parsed& parsed,
diff --git a/url/url_canon_host.cc b/url/url_canon_host.cc
index abcf615..7a97522 100644
--- a/url/url_canon_host.cc
+++ b/url/url_canon_host.cc
@@ -2,7 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <unordered_set>
+
 #include "polyfills/base/check.h"
+#include "polyfills/base/metrics/histogram_macros.h"
 #include "url/url_canon.h"
 #include "url/url_canon_internal.h"
 
@@ -129,6 +132,8 @@
                   bool* has_non_ascii) {
   *has_non_ascii = false;
 
+  std::unordered_set<char> escaped_chars_to_measure;
+
   bool success = true;
   for (int i = 0; i < host_len; ++i) {
     unsigned int source = host[i];
@@ -156,6 +161,7 @@
       } else if (replacement == kEsc) {
         // This character is valid but should be escaped.
         AppendEscapedChar(source, output);
+        escaped_chars_to_measure.insert(source);
       } else {
         // Common case, the given character is valid in a hostname, the lookup
         // table tells us the canonical representation of that character (lower
@@ -170,6 +176,16 @@
       *has_non_ascii = true;
     }
   }
+  if (success) {
+    bool did_escape = !escaped_chars_to_measure.empty();
+    UMA_HISTOGRAM_BOOLEAN("URL.Host.DidEscape", did_escape);
+    if (did_escape) {
+      for (char c : escaped_chars_to_measure) {
+        UMA_HISTOGRAM_ENUMERATION("URL.Host.EscapeChar",
+                                  EscapedHostCharToEnum(c));
+      }
+    }
+  }
   return success;
 }
 
diff --git a/url/url_canon_internal.cc b/url/url_canon_internal.cc
index 99541bd..961a3be 100644
--- a/url/url_canon_internal.cc
+++ b/url/url_canon_internal.cc
@@ -435,4 +435,49 @@
 
 #endif  // !WIN32
 
+EscapedHostChar EscapedHostCharToEnum(char c) {
+  switch (c) {
+    case ' ':
+      return EscapedHostChar::kSpace;
+    case '!':
+      return EscapedHostChar::kBang;
+    case '"':
+      return EscapedHostChar::kDoubleQuote;
+    case '#':
+      return EscapedHostChar::kHash;
+    case '$':
+      return EscapedHostChar::kDollar;
+    case '&':
+      return EscapedHostChar::kAmpersand;
+    case '\'':
+      return EscapedHostChar::kSingleQuote;
+    case '(':
+      return EscapedHostChar::kLeftParen;
+    case ')':
+      return EscapedHostChar::kRightParen;
+    case '*':
+      return EscapedHostChar::kAsterisk;
+    case ',':
+      return EscapedHostChar::kComma;
+    case '<':
+      return EscapedHostChar::kLeftAngle;
+    case '=':
+      return EscapedHostChar::kEquals;
+    case '>':
+      return EscapedHostChar::kRightAngle;
+    case '@':
+      return EscapedHostChar::kAt;
+    case '`':
+      return EscapedHostChar::kBackTick;
+    case '{':
+      return EscapedHostChar::kLeftCurly;
+    case '|':
+      return EscapedHostChar::kPipe;
+    case '}':
+      return EscapedHostChar::kRightCurly;
+    default:
+      return EscapedHostChar::kUnknown;
+  }
+}
+
 }  // namespace url
diff --git a/url/url_canon_internal.h b/url/url_canon_internal.h
index 11e0f7a..6601587 100644
--- a/url/url_canon_internal.h
+++ b/url/url_canon_internal.h
@@ -418,6 +418,17 @@
                                      int path_begin_in_output,
                                      CanonOutput* output);
 
+// Find the position of a bona fide Windows drive letter in the given path. If
+// no leading drive letter is found, -1 is returned. This function correctly
+// treats /c:/foo and /./c:/foo as having drive letters, and /def/c:/foo as not
+// having a drive letter.
+//
+// Exported for tests.
+COMPONENT_EXPORT(URL)
+int FindWindowsDriveLetter(const char* spec, int begin, int end);
+COMPONENT_EXPORT(URL)
+int FindWindowsDriveLetter(const char16_t* spec, int begin, int end);
+
 #ifndef WIN32
 
 // Implementations of Windows' int-to-string conversions
@@ -445,6 +456,35 @@
 
 #endif  // WIN32
 
+// These values are logged to UMA. Entries should not be renumbered and
+// numeric values should never be reused. Please keep in sync with
+// "URLHostEscapedHostChar" in src/tools/metrics/histograms/enums.xml.
+enum class EscapedHostChar {
+  kUnknown = 0,
+  kSpace = 1,
+  kBang = 2,
+  kDoubleQuote = 3,
+  kHash = 4,
+  kDollar = 5,
+  kAmpersand = 6,
+  kSingleQuote = 7,
+  kLeftParen = 8,
+  kRightParen = 9,
+  kAsterisk = 10,
+  kComma = 11,
+  kLeftAngle = 12,
+  kEquals = 13,
+  kRightAngle = 14,
+  kAt = 15,
+  kBackTick = 16,
+  kLeftCurly = 17,
+  kPipe = 18,
+  kRightCurly = 19,
+  kMaxValue = kRightCurly,
+};
+
+COMPONENT_EXPORT(URL) EscapedHostChar EscapedHostCharToEnum(char c);
+
 }  // namespace url
 
 #endif  // URL_URL_CANON_INTERNAL_H_
diff --git a/url/url_canon_relative.cc b/url/url_canon_relative.cc
index f047d7f..309f596 100644
--- a/url/url_canon_relative.cc
+++ b/url/url_canon_relative.cc
@@ -543,10 +543,7 @@
   // have a host, we want to use the special host detection logic for file
   // URLs provided by DoResolveAbsoluteFile(), as opposed to the generic host
   // detection logic, for consistency with parsing file URLs from scratch.
-  // This also handles the special case where the URL is only slashes,
-  // since that doesn't have a host part either.
-  if (base_is_file &&
-      (num_slashes >= 2 || num_slashes == relative_component.len)) {
+  if (base_is_file && num_slashes >= 2) {
     return DoResolveAbsoluteFile(relative_url, relative_component,
                                  query_converter, output, out_parsed);
   }
diff --git a/url/url_canon_stdstring.h b/url/url_canon_stdstring.h
index 6d23abf..cef33cd 100644
--- a/url/url_canon_stdstring.h
+++ b/url/url_canon_stdstring.h
@@ -37,6 +37,10 @@
 class COMPONENT_EXPORT(URL) StdStringCanonOutput : public CanonOutput {
  public:
   StdStringCanonOutput(std::string* str);
+
+  StdStringCanonOutput(const StdStringCanonOutput&) = delete;
+  StdStringCanonOutput& operator=(const StdStringCanonOutput&) = delete;
+
   ~StdStringCanonOutput() override;
 
   // Must be called after writing has completed but before the string is used.
@@ -46,7 +50,6 @@
 
  protected:
   std::string* str_;
-  DISALLOW_COPY_AND_ASSIGN(StdStringCanonOutput);
 };
 
 // An extension of the Replacements class that allows the setters to use
diff --git a/url/url_canon_stdurl.cc b/url/url_canon_stdurl.cc
index c7e7454..d7e4197 100644
--- a/url/url_canon_stdurl.cc
+++ b/url/url_canon_stdurl.cc
@@ -103,6 +103,10 @@
   // Ref: ignore failure for this, since the page can probably still be loaded.
   CanonicalizeRef(source.ref, parsed.ref, output, &new_parsed->ref);
 
+  // Carry over the flag for potentially dangling markup:
+  if (parsed.potentially_dangling_markup)
+    new_parsed->potentially_dangling_markup = true;
+
   return success;
 }
 
diff --git a/url/url_canon_unittest.cc b/url/url_canon_unittest.cc
index aa2a8ce..d7dc876 100644
--- a/url/url_canon_unittest.cc
+++ b/url/url_canon_unittest.cc
@@ -6,8 +6,10 @@
 #include <stddef.h>
 
 #include "base/cxx17_backports.h"
+#include "base/strings/string_piece.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/gtest_util.h"
+#include "base/test/metrics/histogram_tester.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/third_party/mozilla/url_parse.h"
 #include "url/url_canon.h"
@@ -2373,6 +2375,11 @@
       // is not file.
     {"http://host/a", true, false, "/c:\\foo", true, true, true, "http://host/c:/foo"},
     {"http://host/a", true, false, "//c:\\foo", true, true, true, "http://c/foo"},
+      // Cross-platform relative file: resolution behavior.
+    {"file://host/a", true, true, "/", true, true, true, "file://host/"},
+    {"file://host/a", true, true, "//", true, true, true, "file:///"},
+    {"file://host/a", true, true, "/b", true, true, true, "file://host/b"},
+    {"file://host/a", true, true, "//b", true, true, true, "file://b/"},
       // Ensure that ports aren't allowed for hosts relative to a file url.
       // Although the result string shows a host:port portion, the call to
       // resolve the relative URL returns false, indicating parse failure,
@@ -2510,6 +2517,47 @@
   }
 }
 
+TEST(URLCanonTest, FindWindowsDriveLetter) {
+  struct TestCase {
+    gurl_base::StringPiece spec;
+    int begin;
+    int end;  // -1 for end of spec
+    int expected_drive_letter_pos;
+  } cases[] = {
+      {"/", 0, -1, -1},
+
+      {"c:/foo", 0, -1, 0},
+      {"/c:/foo", 0, -1, 1},
+      {"//c:/foo", 0, -1, -1},  // "//" does not canonicalize to "/"
+      {"\\C|\\foo", 0, -1, 1},
+      {"/cd:/foo", 0, -1, -1},  // "/c" does not canonicalize to "/"
+      {"/./c:/foo", 0, -1, 3},
+      {"/.//c:/foo", 0, -1, -1},  // "/.//" does not canonicalize to "/"
+      {"/././c:/foo", 0, -1, 5},
+      {"/abc/c:/foo", 0, -1, -1},  // "/abc/" does not canonicalize to "/"
+      {"/abc/./../c:/foo", 0, -1, 10},
+
+      {"/c:/c:/foo", 3, -1, 4},  // actual input is "/c:/foo"
+      {"/c:/foo", 3, -1, -1},    // actual input is "/foo"
+      {"/c:/foo", 0, 1, -1},     // actual input is "/"
+  };
+
+  for (const auto& c : cases) {
+    int end = c.end;
+    if (end == -1)
+      end = c.spec.size();
+
+    EXPECT_EQ(c.expected_drive_letter_pos,
+              FindWindowsDriveLetter(c.spec.data(), c.begin, end))
+        << "for " << c.spec << "[" << c.begin << ":" << end << "] (UTF-8)";
+
+    std::u16string spec16 = gurl_base::ASCIIToUTF16(c.spec);
+    EXPECT_EQ(c.expected_drive_letter_pos,
+              FindWindowsDriveLetter(spec16.data(), c.begin, end))
+        << "for " << c.spec << "[" << c.begin << ":" << end << "] (UTF-16)";
+  }
+}
+
 TEST(URLCanonTest, IDNToASCII) {
   RawCanonOutputW<1024> output;
 
@@ -2561,4 +2609,49 @@
   output.set_length(0);
 }
 
+TEST(URLCanonTest, EscapedHostCharToEnum) {
+  EXPECT_EQ(EscapedHostChar::kSpace, EscapedHostCharToEnum(' '));
+  EXPECT_EQ(EscapedHostChar::kBang, EscapedHostCharToEnum('!'));
+  EXPECT_EQ(EscapedHostChar::kDoubleQuote, EscapedHostCharToEnum('"'));
+  EXPECT_EQ(EscapedHostChar::kHash, EscapedHostCharToEnum('#'));
+  EXPECT_EQ(EscapedHostChar::kDollar, EscapedHostCharToEnum('$'));
+  EXPECT_EQ(EscapedHostChar::kAmpersand, EscapedHostCharToEnum('&'));
+  EXPECT_EQ(EscapedHostChar::kSingleQuote, EscapedHostCharToEnum('\''));
+  EXPECT_EQ(EscapedHostChar::kLeftParen, EscapedHostCharToEnum('('));
+  EXPECT_EQ(EscapedHostChar::kRightParen, EscapedHostCharToEnum(')'));
+  EXPECT_EQ(EscapedHostChar::kAsterisk, EscapedHostCharToEnum('*'));
+  EXPECT_EQ(EscapedHostChar::kComma, EscapedHostCharToEnum(','));
+  EXPECT_EQ(EscapedHostChar::kLeftAngle, EscapedHostCharToEnum('<'));
+  EXPECT_EQ(EscapedHostChar::kEquals, EscapedHostCharToEnum('='));
+  EXPECT_EQ(EscapedHostChar::kRightAngle, EscapedHostCharToEnum('>'));
+  EXPECT_EQ(EscapedHostChar::kAt, EscapedHostCharToEnum('@'));
+  EXPECT_EQ(EscapedHostChar::kBackTick, EscapedHostCharToEnum('`'));
+  EXPECT_EQ(EscapedHostChar::kLeftCurly, EscapedHostCharToEnum('{'));
+  EXPECT_EQ(EscapedHostChar::kPipe, EscapedHostCharToEnum('|'));
+  EXPECT_EQ(EscapedHostChar::kRightCurly, EscapedHostCharToEnum('}'));
+
+  EXPECT_EQ(EscapedHostChar::kUnknown, EscapedHostCharToEnum('a'));
+  EXPECT_EQ(EscapedHostChar::kUnknown, EscapedHostCharToEnum('\\'));
+}
+
+TEST(URLCanonTest, EscapedHostCharHistograms) {
+  std::string input("foo  <bar>");
+
+  Component in_comp(0, input.size());
+  Component out_comp;
+  std::string out_str;
+  StdStringCanonOutput output(&out_str);
+
+  gurl_base::HistogramTester histogram_tester;
+  bool success = CanonicalizeHost(input.data(), in_comp, &output, &out_comp);
+  ASSERT_TRUE(success);
+  histogram_tester.ExpectBucketCount("URL.Host.DidEscape", 1, 1);
+  histogram_tester.ExpectBucketCount("URL.Host.EscapeChar",
+                                     EscapedHostChar::kSpace, 1);
+  histogram_tester.ExpectBucketCount("URL.Host.EscapeChar",
+                                     EscapedHostChar::kLeftAngle, 1);
+  histogram_tester.ExpectBucketCount("URL.Host.EscapeChar",
+                                     EscapedHostChar::kRightAngle, 1);
+}
+
 }  // namespace url
diff --git a/url/url_constants.cc b/url/url_constants.cc
index 9da6426..d7a5de7 100644
--- a/url/url_constants.cc
+++ b/url/url_constants.cc
@@ -29,6 +29,7 @@
 const char kQuicTransportScheme[] = "quic-transport";
 const char kTelScheme[] = "tel";
 const char kUrnScheme[] = "urn";
+const char kUuidInPackageScheme[] = "uuid-in-package";
 const char kWsScheme[] = "ws";
 const char kWssScheme[] = "wss";
 
diff --git a/url/url_constants.h b/url/url_constants.h
index dcd7c90..69a72f5 100644
--- a/url/url_constants.h
+++ b/url/url_constants.h
@@ -33,6 +33,7 @@
 COMPONENT_EXPORT(URL) extern const char kQuicTransportScheme[];
 COMPONENT_EXPORT(URL) extern const char kTelScheme[];
 COMPONENT_EXPORT(URL) extern const char kUrnScheme[];
+COMPONENT_EXPORT(URL) extern const char kUuidInPackageScheme[];
 COMPONENT_EXPORT(URL) extern const char kWsScheme[];
 COMPONENT_EXPORT(URL) extern const char kWssScheme[];
 
diff --git a/url/url_file.h b/url/url_file.h
index 6ad79b4..c15c8f5 100644
--- a/url/url_file.h
+++ b/url/url_file.h
@@ -13,15 +13,11 @@
 
 namespace url {
 
-#ifdef WIN32
-
 // We allow both "c:" and "c|" as drive identifiers.
 inline bool IsWindowsDriveSeparator(char16_t ch) {
   return ch == ':' || ch == '|';
 }
 
-#endif  // WIN32
-
 // Returns the index of the next slash in the input after the given index, or
 // spec_len if the end of the input is reached.
 template<typename CHAR>
@@ -32,8 +28,6 @@
   return idx;
 }
 
-#ifdef WIN32
-
 // DoesContainWindowsDriveSpecUntil returns the least number between
 // start_offset and max_offset such that the spec has a valid drive
 // specification starting at that offset. Otherwise it returns -1. This function
@@ -74,6 +68,8 @@
                                           spec_len) == start_offset;
 }
 
+#ifdef WIN32
+
 // Returns true if the start_offset in the given text looks like it begins a
 // UNC path, for example "\\". This function explicitly handles start_offset
 // values that are equal to or larger than the spec_len to simplify callers.
diff --git a/url/url_parse_file.cc b/url/url_parse_file.cc
index ceb75d8..77a622f 100644
--- a/url/url_parse_file.cc
+++ b/url/url_parse_file.cc
@@ -42,48 +42,24 @@
 
 namespace {
 
-// A subcomponent of DoInitFileURL, the input of this function should be a UNC
+// A subcomponent of DoParseFileURL, the input of this function should be a UNC
 // path name, with the index of the first character after the slashes following
 // the scheme given in |after_slashes|. This will initialize the host, path,
 // query, and ref, and leave the other output components untouched
-// (DoInitFileURL handles these for us).
-template<typename CHAR>
+// (DoParseFileURL handles these for us).
+template <typename CHAR>
 void DoParseUNC(const CHAR* spec,
                 int after_slashes,
                 int spec_len,
-               Parsed* parsed) {
+                Parsed* parsed) {
   int next_slash = FindNextSlash(spec, after_slashes, spec_len);
-  if (next_slash == spec_len) {
-    // No additional slash found, as in "file://foo", treat the text as the
-    // host with no path (this will end up being UNC to server "foo").
-    int host_len = spec_len - after_slashes;
-    if (host_len)
-      parsed->host = Component(after_slashes, host_len);
-    else
-      parsed->host.reset();
-    parsed->path.reset();
-    return;
-  }
 
-#ifdef WIN32
-  // See if we have something that looks like a path following the first
-  // component. As in "file://localhost/c:/", we get "c:/" out. We want to
-  // treat this as a having no host but the path given. Works on Windows only.
-  if (DoesBeginWindowsDriveSpec(spec, next_slash + 1, spec_len)) {
-    parsed->host.reset();
-    ParsePathInternal(spec, MakeRange(next_slash, spec_len),
-                      &parsed->path, &parsed->query, &parsed->ref);
-    return;
-  }
-#endif
-
-  // Otherwise, everything up until that first slash we found is the host name,
-  // which will end up being the UNC host. For example "file://foo/bar.txt"
-  // will get a server name of "foo" and a path of "/bar". Later, on Windows,
-  // this should be treated as the filename "\\foo\bar.txt" in proper UNC
-  // notation.
-  int host_len = next_slash - after_slashes;
-  if (host_len)
+  // Everything up until that first slash we found (or end of string) is the
+  // host name, which will end up being the UNC host. For example,
+  // "file://foo/bar.txt" will get a server name of "foo" and a path of "/bar".
+  // Later, on Windows, this should be treated as the filename "\\foo\bar.txt"
+  // in proper UNC notation.
+  if (after_slashes < next_slash)
     parsed->host = MakeRange(after_slashes, next_slash);
   else
     parsed->host.reset();
@@ -98,7 +74,7 @@
 // A subcomponent of DoParseFileURL, the input should be a local file, with the
 // beginning of the path indicated by the index in |path_begin|. This will
 // initialize the host, path, query, and ref, and leave the other output
-// components untouched (DoInitFileURL handles these for us).
+// components untouched (DoParseFileURL handles these for us).
 template<typename CHAR>
 void DoParseLocalFile(const CHAR* spec,
                       int path_begin,
diff --git a/url/url_parse_unittest.cc b/url/url_parse_unittest.cc
index b23dcf8..7cd3fe8 100644
--- a/url/url_parse_unittest.cc
+++ b/url/url_parse_unittest.cc
@@ -374,8 +374,8 @@
 {"FiLe:c|",                  "FiLe", NULL, NULL, NULL,     -1, "c|",          NULL, NULL},
 {"FILE:/\\\\/server/file",   "FILE", NULL, NULL, "server", -1, "/file",       NULL, NULL},
 {"file://server/",           "file", NULL, NULL, "server", -1, "/",           NULL, NULL},
-{"file://localhost/c:/",     "file", NULL, NULL, NULL,     -1, "/c:/",        NULL, NULL},
-{"file://127.0.0.1/c|\\",    "file", NULL, NULL, NULL,     -1, "/c|\\",       NULL, NULL},
+{"file://localhost/c:/",     "file", NULL, NULL, "localhost", -1, "/c:/",     NULL, NULL},
+{"file://127.0.0.1/c|\\",    "file", NULL, NULL, "127.0.0.1", -1, "/c|\\",    NULL, NULL},
 {"file:/",                   "file", NULL, NULL, NULL,     -1, NULL,          NULL, NULL},
 {"file:",                    "file", NULL, NULL, NULL,     -1, NULL,          NULL, NULL},
   // If there is a Windows drive letter, treat any number of slashes as the
diff --git a/url/url_util.cc b/url/url_util.cc
index 470da30..3162fdf 100644
--- a/url/url_util.cc
+++ b/url/url_util.cc
@@ -217,6 +217,13 @@
                     CharsetConverter* charset_converter,
                     CanonOutput* output,
                     Parsed* output_parsed) {
+  // Trim leading C0 control characters and spaces.
+  int begin = 0;
+  TrimURL(spec, &begin, &spec_len, trim_path_end);
+  GURL_DCHECK(0 <= begin && begin <= spec_len);
+  spec += begin;
+  spec_len -= begin;
+
   output->ReserveSizeIfNeeded(spec_len);
 
   // Remove any whitespace from the middle of the relative URL if necessary.
diff --git a/url/url_util_unittest.cc b/url/url_util_unittest.cc
index 158e3d6..a455ff6 100644
--- a/url/url_util_unittest.cc
+++ b/url/url_util_unittest.cc
@@ -5,7 +5,10 @@
 #include <stddef.h>
 
 #include "base/cxx17_backports.h"
+#include "base/strings/string_piece.h"
+#include "testing/gtest/include/gtest/gtest-message.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "absl/types/optional.h"
 #include "url/third_party/mozilla/url_parse.h"
 #include "url/url_canon.h"
 #include "url/url_canon_stdstring.h"
@@ -17,12 +20,14 @@
 class URLUtilTest : public testing::Test {
  public:
   URLUtilTest() = default;
+
+  URLUtilTest(const URLUtilTest&) = delete;
+  URLUtilTest& operator=(const URLUtilTest&) = delete;
+
   ~URLUtilTest() override = default;
 
  private:
   ScopedSchemeRegistryForTests scoped_registry_;
-
-  DISALLOW_COPY_AND_ASSIGN(URLUtilTest);
 };
 
 TEST_F(URLUtilTest, FindAndCompareScheme) {
@@ -492,6 +497,25 @@
   }
 }
 
+TEST_F(URLUtilTest, PotentiallyDanglingMarkupAfterReplacement) {
+  // Parse a URL with potentially dangling markup.
+  Parsed original_parsed;
+  RawCanonOutput<32> original;
+  const char* url = "htt\nps://example.com/<path";
+  Canonicalize(url, strlen(url), false, nullptr, &original, &original_parsed);
+  ASSERT_TRUE(original_parsed.potentially_dangling_markup);
+
+  // Perform a replacement, and validate that the potentially_dangling_markup
+  // flag carried over to the new Parsed object.
+  Replacements<char> replacements;
+  replacements.ClearRef();
+  Parsed replaced_parsed;
+  RawCanonOutput<32> replaced;
+  ReplaceComponents(original.data(), original.length(), original_parsed,
+                    replacements, nullptr, &replaced, &replaced_parsed);
+  EXPECT_TRUE(replaced_parsed.potentially_dangling_markup);
+}
+
 TEST_F(URLUtilTest, TestDomainIs) {
   const struct {
     const char* canonicalized_host;
@@ -535,4 +559,52 @@
   }
 }
 
+namespace {
+absl::optional<std::string> CanonicalizeSpec(gurl_base::StringPiece spec,
+                                             bool trim_path_end) {
+  std::string canonicalized;
+  StdStringCanonOutput output(&canonicalized);
+  Parsed parsed;
+  if (!Canonicalize(spec.data(), spec.size(), trim_path_end,
+                    /*charset_converter=*/nullptr, &output, &parsed)) {
+    return {};
+  }
+  output.Complete();  // Must be called before string is used.
+  return canonicalized;
+}
+}  // namespace
+
+#ifdef OS_WIN
+// Regression test for https://crbug.com/1252658.
+TEST_F(URLUtilTest, TestCanonicalizeWindowsPathWithLeadingNUL) {
+  auto PrefixWithNUL = [](std::string&& s) -> std::string { return '\0' + s; };
+  EXPECT_EQ(CanonicalizeSpec(PrefixWithNUL("w:"), /*trim_path_end=*/false),
+            absl::make_optional("file:///W:"));
+  EXPECT_EQ(CanonicalizeSpec(PrefixWithNUL("\\\\server\\share"),
+                             /*trim_path_end=*/false),
+            absl::make_optional("file://server/share"));
+}
+#endif
+
+TEST_F(URLUtilTest, TestCanonicalizeIdempotencyWithLeadingControlCharacters) {
+  std::string spec = "_w:";
+  // Loop over all C0 control characters and the space character.
+  for (char c = '\0'; c <= ' '; c++) {
+    SCOPED_TRACE(testing::Message() << "c: " << c);
+
+    // Overwrite the first character of `spec`. Note that replacing the first
+    // character with NUL will not change the length!
+    spec[0] = c;
+
+    for (bool trim_path_end : {false, true}) {
+      SCOPED_TRACE(testing::Message() << "trim_path_end: " << trim_path_end);
+
+      absl::optional<std::string> canonicalized =
+          CanonicalizeSpec(spec, trim_path_end);
+      ASSERT_TRUE(canonicalized);
+      EXPECT_EQ(canonicalized, CanonicalizeSpec(*canonicalized, trim_path_end));
+    }
+  }
+}
+
 }  // namespace url