File webkit2gtk3-libsoup2.patch of Package webkit2gtk3

diff -urpN webkitgtk-2.51.90.orig/Source/cmake/FindLibSoup.cmake webkitgtk-2.51.90/Source/cmake/FindLibSoup.cmake
--- webkitgtk-2.51.90.orig/Source/cmake/FindLibSoup.cmake	1969-12-31 18:00:00.000000000 -0600
+++ webkitgtk-2.51.90/Source/cmake/FindLibSoup.cmake	2026-01-24 10:41:12.911751287 -0600
@@ -0,0 +1,67 @@
+# - Try to find LibSoup 2.4
+# This module defines the following variables:
+#
+#  LIBSOUP_FOUND - LibSoup 2.4 was found
+#  LIBSOUP_INCLUDE_DIRS - the LibSoup 2.4 include directories
+#  LIBSOUP_LIBRARIES - link these to use LibSoup 2.4
+#
+# Copyright (C) 2012 Raphael Kubo da Costa <rakuco@webkit.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1.  Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer.
+# 2.  Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in the
+#     documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND ITS CONTRIBUTORS ``AS
+# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ITS
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+if (NOT DEFINED LibSoup_FIND_VERSION)
+    message(FATAL_ERROR "No LibSoup version specified")
+endif ()
+
+if (LibSoup_FIND_VERSION VERSION_LESS 2.91)
+    set(LIBSOUP_API_VERSION "2.4")
+else ()
+    set(LIBSOUP_API_VERSION "3.0")
+endif ()
+
+# LibSoup does not provide an easy way to retrieve its version other than its
+# .pc file, so we need to rely on PC_LIBSOUP_VERSION and REQUIRE the .pc file
+# to be found.
+find_package(PkgConfig QUIET)
+pkg_check_modules(PC_LIBSOUP QUIET "libsoup-${LIBSOUP_API_VERSION}")
+
+find_path(LIBSOUP_INCLUDE_DIRS
+    NAMES libsoup/soup.h
+    HINTS ${PC_LIBSOUP_INCLUDEDIR}
+          ${PC_LIBSOUP_INCLUDE_DIRS}
+    PATH_SUFFIXES "libsoup-${LIBSOUP_API_VERSION}"
+)
+
+find_library(LIBSOUP_LIBRARIES
+    NAMES "soup-${LIBSOUP_API_VERSION}"
+    HINTS ${PC_LIBSOUP_LIBDIR}
+          ${PC_LIBSOUP_LIBRARY_DIRS}
+)
+
+include(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibSoup REQUIRED_VARS LIBSOUP_INCLUDE_DIRS LIBSOUP_LIBRARIES
+                                          VERSION_VAR   PC_LIBSOUP_VERSION)
+
+mark_as_advanced(
+    LIBSOUP_INCLUDE_DIRS
+    LIBSOUP_LIBRARIES
+)
diff -urpN webkitgtk-2.51.90.orig/Source/cmake/OptionsGTK.cmake webkitgtk-2.51.90/Source/cmake/OptionsGTK.cmake
--- webkitgtk-2.51.90.orig/Source/cmake/OptionsGTK.cmake	2026-01-23 02:50:35.730358800 -0600
+++ webkitgtk-2.51.90/Source/cmake/OptionsGTK.cmake	2026-01-24 10:39:45.379550640 -0600
@@ -11,7 +11,6 @@ set(USER_AGENT_BRANDING "" CACHE STRING
 find_package(GLib 2.70.0 REQUIRED COMPONENTS GioUnix Thread Module)
 find_package(Cairo 1.16.0 REQUIRED)
 find_package(LibGcrypt 1.7.0 REQUIRED)
-find_package(Soup3 3.0.0 REQUIRED)
 find_package(Tasn1 REQUIRED)
 find_package(HarfBuzz 2.7.4 REQUIRED COMPONENTS ICU)
 find_package(ICU 70.1 REQUIRED COMPONENTS data i18n uc)
@@ -54,6 +53,7 @@ WEBKIT_OPTION_DEFINE(USE_LIBDRM "Whether
 WEBKIT_OPTION_DEFINE(USE_LIBHYPHEN "Whether to enable the default automatic hyphenation implementation." PUBLIC ON)
 WEBKIT_OPTION_DEFINE(USE_LIBSECRET "Whether to enable the persistent credential storage using libsecret." PUBLIC ON)
 WEBKIT_OPTION_DEFINE(USE_SKIA_OPENTYPE_SVG "Whether to use the Skia built-in support for OpenType SVG fonts." PUBLIC ON)
+WEBKIT_OPTION_DEFINE(USE_SOUP2 "Whether to enable usage of Soup 2 instead of Soup 3." PUBLIC OFF)
 WEBKIT_OPTION_DEFINE(USE_SYSTEM_SYSPROF_CAPTURE "Whether to use a system-provided libsysprof-capture" PUBLIC ON)
 WEBKIT_OPTION_DEFINE(ENABLE_JSC_RESTRICTED_OPTIONS_BY_DEFAULT "Whether to enable dangerous development options in JSC by default." PRIVATE OFF)
 
@@ -61,6 +61,8 @@ WEBKIT_OPTION_DEPEND(ENABLE_DOCUMENTATIO
 WEBKIT_OPTION_DEPEND(USE_GBM USE_LIBDRM)
 WEBKIT_OPTION_DEPEND(USE_SKIA_OPENTYPE_SVG USE_SKIA)
 
+WEBKIT_OPTION_CONFLICT(USE_GTK4 USE_SOUP2)
+
 # Private options specific to the GTK port. Changing these options is
 # completely unsupported. They are intended for use only by WebKit developers.
 WEBKIT_OPTION_DEFINE(USE_SPIEL "Whether to enable usage of LibSpiel for speech synthesis." PRIVATE OFF)
@@ -177,10 +179,32 @@ if (ENABLE_WAYLAND_TARGET AND NOT ${GTK_
     set(ENABLE_WAYLAND_TARGET OFF)
 endif ()
 
+if (USE_SOUP2)
+    set(SOUP_MINIMUM_VERSION 2.54.0)
+    set(SOUP_API_VERSION 2.4)
+else ()
+    set(SOUP_MINIMUM_VERSION 3.0.0)
+    set(SOUP_API_VERSION 3.0)
+    set(ENABLE_SERVER_PRECONNECT ON)
+endif ()
+find_package(LibSoup ${SOUP_MINIMUM_VERSION})
+
+if (NOT LibSoup_FOUND)
+if (USE_SOUP2)
+    message(FATAL_ERROR "libsoup is required.")
+else ()
+    message(FATAL_ERROR "libsoup 3 is required. Enable USE_SOUP2 to use libsoup 2 (disables HTTP/2)")
+endif ()
+endif ()
+
 if (USE_GTK4)
     set(WEBKITGTK_API_INFIX "")
     set(WEBKITGTK_API_VERSION "6.0")
     SET_AND_EXPOSE_TO_BUILD(ENABLE_2022_GLIB_API ON)
+elseif (USE_SOUP2)
+    set(WEBKITGTK_API_INFIX "2")
+    set(WEBKITGTK_API_VERSION "4.0")
+    SET_AND_EXPOSE_TO_BUILD(ENABLE_2022_GLIB_API OFF)
 else ()
     set(WEBKITGTK_API_INFIX "2")
     set(WEBKITGTK_API_VERSION "4.1")
@@ -190,7 +214,10 @@ endif ()
 EXPOSE_STRING_VARIABLE_TO_BUILD(WEBKITGTK_API_INFIX)
 EXPOSE_STRING_VARIABLE_TO_BUILD(WEBKITGTK_API_VERSION)
 
-if (WEBKITGTK_API_VERSION VERSION_EQUAL "4.1")
+if (WEBKITGTK_API_VERSION VERSION_EQUAL "4.0")
+    CALCULATE_LIBRARY_VERSIONS_FROM_LIBTOOL_TRIPLE(WEBKIT 112 0 75)
+    CALCULATE_LIBRARY_VERSIONS_FROM_LIBTOOL_TRIPLE(JAVASCRIPTCORE 47 0 29)
+elseif (WEBKITGTK_API_VERSION VERSION_EQUAL "4.1")
     CALCULATE_LIBRARY_VERSIONS_FROM_LIBTOOL_TRIPLE(WEBKIT 21 0 21)
     CALCULATE_LIBRARY_VERSIONS_FROM_LIBTOOL_TRIPLE(JAVASCRIPTCORE 10 4 10)
 elseif (WEBKITGTK_API_VERSION VERSION_EQUAL "6.0")
diff -urpN webkitgtk-2.51.90.orig/Source/cmake/WebKitFeatures.cmake webkitgtk-2.51.90/Source/cmake/WebKitFeatures.cmake
--- webkitgtk-2.51.90.orig/Source/cmake/WebKitFeatures.cmake	2026-01-23 02:35:26.907442300 -0600
+++ webkitgtk-2.51.90/Source/cmake/WebKitFeatures.cmake	2026-01-24 09:50:16.696693318 -0600
@@ -212,6 +212,7 @@ macro(WEBKIT_OPTION_BEGIN)
     WEBKIT_OPTION_DEFINE(ENABLE_RESOURCE_USAGE "Toggle resource usage support" PRIVATE OFF)
     WEBKIT_OPTION_DEFINE(ENABLE_SAMPLING_PROFILER "Toggle sampling profiler support" PRIVATE ${ENABLE_SAMPLING_PROFILER_DEFAULT})
     WEBKIT_OPTION_DEFINE(ENABLE_SANDBOX_EXTENSIONS "Toggle sandbox extensions support" PRIVATE OFF)
+    WEBKIT_OPTION_DEFINE(ENABLE_SERVER_PRECONNECT "Toggle server preconnect support" PRIVATE OFF)
     WEBKIT_OPTION_DEFINE(ENABLE_SERVICE_CONTROLS "Toggle service controls support" PRIVATE OFF)
     WEBKIT_OPTION_DEFINE(ENABLE_SHAREABLE_RESOURCE "Toggle network shareable resources support" PRIVATE OFF)
     WEBKIT_OPTION_DEFINE(ENABLE_SMOOTH_SCROLLING "Toggle smooth scrolling" PRIVATE ON)
diff -urpN webkitgtk-2.51.90.orig/Source/WebCore/platform/network/soup/AuthenticationChallenge.h webkitgtk-2.51.90/Source/WebCore/platform/network/soup/AuthenticationChallenge.h
--- webkitgtk-2.51.90.orig/Source/WebCore/platform/network/soup/AuthenticationChallenge.h	2026-01-23 02:35:25.971609600 -0600
+++ webkitgtk-2.51.90/Source/WebCore/platform/network/soup/AuthenticationChallenge.h	2026-01-24 09:48:37.065766734 -0600
@@ -56,6 +56,9 @@ public:
     AuthenticationChallenge(SoupMessage*, GTlsClientConnection*);
     AuthenticationChallenge(SoupMessage*, GTlsPassword*);
     AuthenticationClient* authenticationClient() const { RELEASE_ASSERT_NOT_REACHED(); }
+#if USE(SOUP2)
+    SoupMessage* soupMessage() const { return m_soupMessage.get(); }
+#endif
     SoupAuth* soupAuth() const { return m_soupAuth.get(); }
     GTlsPassword* tlsPassword() const { return m_tlsPassword.get(); }
     void setProposedCredential(const Credential& credential) { m_proposedCredential = credential; }
@@ -70,6 +73,9 @@ private:
     friend class AuthenticationChallengeBase;
     static bool platformCompare(const AuthenticationChallenge&, const AuthenticationChallenge&);
 
+#if USE(SOUP2)
+    GRefPtr<SoupMessage> m_soupMessage;
+#endif
     GRefPtr<SoupAuth> m_soupAuth;
     GRefPtr<GTlsPassword> m_tlsPassword;
     uint32_t m_tlsPasswordFlags { 0 };
diff -urpN webkitgtk-2.51.90.orig/Source/WebCore/platform/network/soup/AuthenticationChallengeSoup.cpp webkitgtk-2.51.90/Source/WebCore/platform/network/soup/AuthenticationChallengeSoup.cpp
--- webkitgtk-2.51.90.orig/Source/WebCore/platform/network/soup/AuthenticationChallengeSoup.cpp	2026-01-23 02:35:25.971680900 -0600
+++ webkitgtk-2.51.90/Source/WebCore/platform/network/soup/AuthenticationChallengeSoup.cpp	2026-01-24 09:48:37.065891180 -0600
@@ -62,9 +62,16 @@ static ProtectionSpace protectionSpaceFr
     else
         scheme = ProtectionSpace::AuthenticationScheme::Unknown;
 
+#if USE(SOUP2)
+    auto host = url.host();
+    auto port = url.port();
+    if (!port)
+        port = defaultPortForProtocol(url.protocol());
+#else
     URL authURL({ }, makeString("http://"_s, unsafeSpan(soup_auth_get_authority(soupAuth))));
     auto host = authURL.host();
     auto port = authURL.port();
+#endif
 
     return ProtectionSpace(host.toString(), static_cast<int>(port.value_or(0)),
         protectionSpaceServerTypeFromURL(url, soup_auth_is_for_proxy(soupAuth)),
@@ -77,6 +84,9 @@ AuthenticationChallenge::AuthenticationC
         , retrying ? 1 : 0 // previousFailureCount
         , soupMessage // failureResponse
         , ResourceError::authenticationError(soupMessage))
+#if USE(SOUP2)
+    , m_soupMessage(soupMessage)
+#endif
     , m_soupAuth(soupAuth)
 {
 }
@@ -130,6 +140,10 @@ bool AuthenticationChallenge::platformCo
     if (a.tlsPasswordFlags() != b.tlsPasswordFlags())
         return false;
 
+#if USE(SOUP2)
+    return a.soupMessage() == b.soupMessage();
+#endif
+
     return true;
 }
 
diff -urpN webkitgtk-2.51.90.orig/Source/WebCore/platform/network/soup/CookieSoup.cpp webkitgtk-2.51.90/Source/WebCore/platform/network/soup/CookieSoup.cpp
--- webkitgtk-2.51.90.orig/Source/WebCore/platform/network/soup/CookieSoup.cpp	2026-01-23 02:35:25.971680900 -0600
+++ webkitgtk-2.51.90/Source/WebCore/platform/network/soup/CookieSoup.cpp	2026-01-24 09:48:37.066076551 -0600
@@ -32,6 +32,7 @@
 
 namespace WebCore {
 
+#if SOUP_CHECK_VERSION(2, 69, 90)
 static Cookie::SameSitePolicy coreSameSitePolicy(SoupSameSitePolicy policy)
 {
     switch (policy) {
@@ -61,19 +62,40 @@ static SoupSameSitePolicy soupSameSitePo
     ASSERT_NOT_REACHED();
     return SOUP_SAME_SITE_POLICY_NONE;
 }
+#endif
 
 Cookie::Cookie(SoupCookie* cookie)
     : name(String::fromUTF8(soup_cookie_get_name(cookie)))
     , value(String::fromUTF8(soup_cookie_get_value(cookie)))
     , domain(String::fromUTF8(soup_cookie_get_domain(cookie)))
     , path(String::fromUTF8(soup_cookie_get_path(cookie)))
+#if USE(SOUP2)
+    , expires(soup_cookie_get_expires(cookie) ? std::make_optional(static_cast<double>(soup_date_to_time_t(soup_cookie_get_expires(cookie))) * 1000) : std::nullopt)
+#else
     , expires(soup_cookie_get_expires(cookie) ? std::make_optional(static_cast<double>(g_date_time_to_unix(soup_cookie_get_expires(cookie))) * 1000) : std::nullopt)
+#endif
     , httpOnly(soup_cookie_get_http_only(cookie))
     , secure(soup_cookie_get_secure(cookie))
     , session(!soup_cookie_get_expires(cookie))
-    , sameSite(coreSameSitePolicy(soup_cookie_get_same_site_policy(cookie)))
+
+{
+#if SOUP_CHECK_VERSION(2, 69, 90)
+    sameSite = coreSameSitePolicy(soup_cookie_get_same_site_policy(cookie));
+#endif
+}
+
+#if USE(SOUP2)
+static SoupDate* msToSoupDate(double ms)
 {
+    int year = msToYear(ms);
+    int dayOfYear = dayInYear(ms, year);
+    bool leapYear = isLeapYear(year);
+
+    // monthFromDayInYear() returns a value in the [0,11] range, while soup_date_new() expects
+    // a value in the [1,12] range, meaning we have to manually adjust the month value.
+    return soup_date_new(year, monthFromDayInYear(dayOfYear, leapYear) + 1, dayInMonthFromDayInYear(dayOfYear, leapYear), msToHours(ms), msToMinutes(ms), static_cast<int64_t>(ms / 1000) % 60);
 }
+#endif
 
 SoupCookie* Cookie::toSoupCookie() const
 {
@@ -85,11 +107,19 @@ SoupCookie* Cookie::toSoupCookie() const
 
     soup_cookie_set_http_only(soupCookie, httpOnly);
     soup_cookie_set_secure(soupCookie, secure);
+#if SOUP_CHECK_VERSION(2, 69, 90)
     soup_cookie_set_same_site_policy(soupCookie, soupSameSitePolicy(sameSite));
+#endif
 
     if (!session && expires) {
+#if USE(SOUP2)
+        SoupDate* date = msToSoupDate(*expires);
+        soup_cookie_set_expires(soupCookie, date);
+        soup_date_free(date);
+#else
         GRefPtr<GDateTime> date = adoptGRef(g_date_time_new_from_unix_utc(*expires / 1000.));
         soup_cookie_set_expires(soupCookie, date.get());
+#endif
     }
 
     return soupCookie;
diff -urpN webkitgtk-2.51.90.orig/Source/WebCore/platform/network/soup/GUniquePtrSoup.h webkitgtk-2.51.90/Source/WebCore/platform/network/soup/GUniquePtrSoup.h
--- webkitgtk-2.51.90.orig/Source/WebCore/platform/network/soup/GUniquePtrSoup.h	2026-01-23 02:35:25.971680900 -0600
+++ webkitgtk-2.51.90/Source/WebCore/platform/network/soup/GUniquePtrSoup.h	2026-01-24 09:48:37.066166973 -0600
@@ -29,8 +29,17 @@
 namespace WTF {
 
 WTF_DEFINE_GPTR_DELETER(SoupCookie, soup_cookie_free)
+#if SOUP_CHECK_VERSION(2, 67, 1)
 WTF_DEFINE_GPTR_DELETER(SoupHSTSPolicy, soup_hsts_policy_free)
+#endif
+#if USE(SOUP2)
+WTF_DEFINE_GPTR_DELETER(SoupURI, soup_uri_free)
+#endif
+#if SOUP_CHECK_VERSION(2, 99, 3)
 WTF_DEFINE_GPTR_DELETER(SoupMessageHeaders, soup_message_headers_unref)
+#else
+WTF_DEFINE_GPTR_DELETER(SoupMessageHeaders, soup_message_headers_free)
+#endif
 
 } // namespace WTF
 
diff -urpN webkitgtk-2.51.90.orig/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp webkitgtk-2.51.90/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp
--- webkitgtk-2.51.90.orig/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp	2026-01-23 02:35:25.971680900 -0600
+++ webkitgtk-2.51.90/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp	2026-01-24 09:48:37.066333799 -0600
@@ -353,8 +353,12 @@ void NetworkStorageSession::setCookieAcc
         soupPolicy = SOUP_COOKIE_JAR_ACCEPT_NEVER;
         break;
     case HTTPCookieAcceptPolicy::OnlyFromMainDocumentDomain:
+#if SOUP_CHECK_VERSION(2, 71, 0)
         soupPolicy = SOUP_COOKIE_JAR_ACCEPT_GRANDFATHERED_THIRD_PARTY;
         break;
+#else
+        [[fallthrough]];
+#endif
     case HTTPCookieAcceptPolicy::ExclusivelyFromMainDocumentDomain:
         soupPolicy = SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY;
         break;
@@ -370,8 +374,10 @@ HTTPCookieAcceptPolicy NetworkStorageSes
         return HTTPCookieAcceptPolicy::AlwaysAccept;
     case SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY:
         return HTTPCookieAcceptPolicy::ExclusivelyFromMainDocumentDomain;
+#if SOUP_CHECK_VERSION(2, 71, 0)
     case SOUP_COOKIE_JAR_ACCEPT_GRANDFATHERED_THIRD_PARTY:
         return HTTPCookieAcceptPolicy::OnlyFromMainDocumentDomain;
+#endif
     case SOUP_COOKIE_JAR_ACCEPT_NEVER:
         return HTTPCookieAcceptPolicy::Never;
     }
@@ -443,13 +449,21 @@ void NetworkStorageSession::setCookiesFr
         // Cap lifetime of persistent, client-side cookies to a week.
         if (cappedLifetime) {
             if (auto* expiresDate = soup_cookie_get_expires(cookie.get())) {
+#if USE(SOUP2)
+                auto timeIntervalSinceNow = Seconds(static_cast<double>(soup_date_to_time_t(expiresDate))) - WallTime::now().secondsSinceEpoch();
+#else
                 auto timeIntervalSinceNow = Seconds(static_cast<double>(g_date_time_to_unix(expiresDate))) - WallTime::now().secondsSinceEpoch();
+#endif
                 if (timeIntervalSinceNow > cappedLifetime.value())
                     soup_cookie_set_max_age(cookie.get(), cappedLifetime->secondsAs<int>());
             }
         }
 
+#if SOUP_CHECK_VERSION(2, 67, 1)
         soup_cookie_jar_add_cookie_full(jar, cookie.release(), origin.get(), firstPartyURI.get());
+#else
+        soup_cookie_jar_add_cookie_with_first_party(jar, firstPartyURI.get(), cookie.release());
+#endif
     }
 
     soup_cookies_free(existingCookies);
@@ -483,7 +497,12 @@ bool NetworkStorageSession::setCookieFro
     }
     soup_cookies_free(existingCookies);
 
+#if SOUP_CHECK_VERSION(2, 67, 1)
     soup_cookie_jar_add_cookie_full(cookieStorage(), soupCookie.release(), uri.get(), firstPartyURI.get());
+#else
+    soup_cookie_jar_add_cookie_with_first_party(cookieStorage(), firstPartyURI.get(), soupCookie.release());
+    UNUSED_PARAM(uri);
+#endif
 
     return true;
 }
@@ -491,9 +510,16 @@ bool NetworkStorageSession::setCookieFro
 void NetworkStorageSession::setCookies(const Vector<Cookie>& cookies, const URL& url, const URL& firstParty)
 {
     for (auto cookie : cookies) {
+#if SOUP_CHECK_VERSION(2, 67, 1)
         auto origin = urlToSoupURI(url);
         auto firstPartyURI = urlToSoupURI(firstParty);
+
         soup_cookie_jar_add_cookie_full(cookieStorage(), cookie.toSoupCookie(), origin.get(), firstPartyURI.get());
+#else
+        UNUSED_PARAM(url);
+        UNUSED_PARAM(firstParty);
+        soup_cookie_jar_add_cookie(cookieStorage(), cookie.toSoupCookie());
+#endif
     }
 }
 
@@ -669,6 +695,7 @@ static std::optional<CookieList> lookupC
     if (!uri)
         return std::nullopt;
 
+#if SOUP_CHECK_VERSION(2, 69, 90)
     auto firstPartyURI = urlToSoupURI(firstParty);
     if (!firstPartyURI)
         return std::nullopt;
@@ -676,6 +703,9 @@ static std::optional<CookieList> lookupC
     auto cookieURI = sameSiteInfo.isSameSite ? urlToSoupURI(url) : nullptr;
     CookieList cookies(soup_cookie_jar_get_cookie_list_with_same_site_info(session.cookieStorage(), uri.get(), firstPartyURI.get(), cookieURI.get(), forHTTPHeader == ForHTTPHeader::Yes,
         sameSiteInfo.isSafeHTTPMethod, sameSiteInfo.isTopSite));
+#else
+    CookieList cookies(soup_cookie_jar_get_cookie_list(session.cookieStorage(), uri.get(), forHTTPHeader == ForHTTPHeader::Yes));
+#endif
     if (!cookies)
         return nullptr;
 
diff -urpN webkitgtk-2.51.90.orig/Source/WebCore/platform/network/soup/ResourceErrorSoup.cpp webkitgtk-2.51.90/Source/WebCore/platform/network/soup/ResourceErrorSoup.cpp
--- webkitgtk-2.51.90.orig/Source/WebCore/platform/network/soup/ResourceErrorSoup.cpp	2026-01-23 02:35:25.971680900 -0600
+++ webkitgtk-2.51.90/Source/WebCore/platform/network/soup/ResourceErrorSoup.cpp	2026-01-24 09:48:37.066663744 -0600
@@ -36,6 +36,12 @@
 
 namespace WebCore {
 
+#if USE(SOUP2)
+#define SOUP_HTTP_ERROR_DOMAIN SOUP_HTTP_ERROR
+#else
+#define SOUP_HTTP_ERROR_DOMAIN SOUP_SESSION_ERROR
+#endif
+
 ResourceError::ResourceError(const String& domain, int errorCode, const URL& failingURL, const String& localizedDescription, Type type, IsSanitized isSanitized)
     : ResourceErrorBase(domain, errorCode, failingURL, localizedDescription, type, isSanitized)
 {
@@ -77,20 +83,29 @@ auto ResourceError::ipcData() const -> s
 
 ResourceError ResourceError::transportError(const URL& failingURL, int statusCode, const String& reasonPhrase)
 {
-    return ResourceError(String::fromLatin1(g_quark_to_string(SOUP_SESSION_ERROR)), statusCode, failingURL, reasonPhrase);
+    return ResourceError(String::fromLatin1(g_quark_to_string(SOUP_HTTP_ERROR_DOMAIN)), statusCode, failingURL, reasonPhrase);
 }
 
 ResourceError ResourceError::httpError(SoupMessage* message, GError* error)
 {
     ASSERT(message);
+#if USE(SOUP2)
+    if (SOUP_STATUS_IS_TRANSPORT_ERROR(message->status_code))
+        return transportError(soupURIToURL(soup_message_get_uri(message)), message->status_code, String::fromUTF8(message->reason_phrase));
+#endif
     return genericGError(soupURIToURL(soup_message_get_uri(message)), error);
 }
 
 ResourceError ResourceError::authenticationError(SoupMessage* message)
 {
     ASSERT(message);
+#if USE(SOUP2)
+    return ResourceError(String::fromLatin1(g_quark_to_string(SOUP_HTTP_ERROR_DOMAIN)), message->status_code,
+        soupURIToURL(soup_message_get_uri(message)), String::fromUTF8(message->reason_phrase));
+#else
     return ResourceError(String::fromLatin1(g_quark_to_string(SOUP_SESSION_ERROR)), soup_message_get_status(message),
         soup_message_get_uri(message), String::fromUTF8(soup_message_get_reason_phrase(message)));
+#endif
 }
 
 ResourceError ResourceError::genericGError(const URL& failingURL, GError* error)
diff -urpN webkitgtk-2.51.90.orig/Source/WebCore/platform/network/soup/ResourceRequest.h webkitgtk-2.51.90/Source/WebCore/platform/network/soup/ResourceRequest.h
--- webkitgtk-2.51.90.orig/Source/WebCore/platform/network/soup/ResourceRequest.h	2026-01-23 02:35:25.971680900 -0600
+++ webkitgtk-2.51.90/Source/WebCore/platform/network/soup/ResourceRequest.h	2026-01-24 09:48:37.066761860 -0600
@@ -101,7 +101,11 @@ public:
 private:
     friend class ResourceRequestBase;
 
+#if USE(SOUP2)
+    GUniquePtr<SoupURI> createSoupURI() const;
+#else
     GRefPtr<GUri> createSoupURI() const;
+#endif
 
     void doUpdatePlatformRequest() { }
     void doUpdateResourceRequest() { }
diff -urpN webkitgtk-2.51.90.orig/Source/WebCore/platform/network/soup/ResourceRequestSoup.cpp webkitgtk-2.51.90/Source/WebCore/platform/network/soup/ResourceRequestSoup.cpp
--- webkitgtk-2.51.90.orig/Source/WebCore/platform/network/soup/ResourceRequestSoup.cpp	2026-01-23 02:35:25.971680900 -0600
+++ webkitgtk-2.51.90/Source/WebCore/platform/network/soup/ResourceRequestSoup.cpp	2026-01-24 10:06:39.916093604 -0600
@@ -29,6 +29,7 @@
 #include "MIMETypeRegistry.h"
 #include "RegistrableDomain.h"
 #include "SharedBuffer.h"
+#include "SoupVersioning.h"
 #include "URLSoup.h"
 #include "WebKitFormDataInputStream.h"
 #include <wtf/text/CString.h>
@@ -71,6 +72,7 @@ GRefPtr<SoupMessage> ResourceRequest::cr
             soup_message_set_first_party(soupMessage.get(), firstParty.get());
     }
 
+#if SOUP_CHECK_VERSION(2, 69, 90)
     if (!isSameSiteUnspecified()) {
         if (isSameSite()) {
             auto siteForCookies = urlToSoupURI(m_requestData.m_url);
@@ -78,6 +80,7 @@ GRefPtr<SoupMessage> ResourceRequest::cr
         }
         soup_message_set_is_top_level_navigation(soupMessage.get(), isTopSite());
     }
+#endif
 
     if (!acceptEncoding())
         soup_message_disable_feature(soupMessage.get(), SOUP_TYPE_CONTENT_DECODER);
@@ -99,8 +102,12 @@ void ResourceRequest::updateSoupMessageB
     auto& elements = formData->elements();
     if (elements.size() == 1 && !formData->alwaysStream()) {
         if (auto* vector = std::get_if<Vector<uint8_t>>(&elements[0].data)) {
+#if USE(SOUP2)
+            soup_message_body_append(soupMessage->request_body, SOUP_MEMORY_TEMPORARY, vector->span().data(), vector->size());
+#else
             GRefPtr<GBytes> bytes = adoptGRef(g_bytes_new_static(vector->span().data(), vector->size()));
             soup_message_set_request_body_from_bytes(soupMessage, nullptr, bytes.get());
+#endif
             return;
         }
     }
@@ -118,7 +125,18 @@ void ResourceRequest::updateSoupMessageB
         return;
 
     GRefPtr<GInputStream> stream = webkitFormDataInputStreamNew(WTF::move(resolvedFormData));
+#if USE(SOUP2)
+    if (GBytes* data = webkitFormDataInputStreamReadAll(WEBKIT_FORM_DATA_INPUT_STREAM(stream.get()))) {
+        soup_message_body_set_accumulate(soupMessage->request_body, FALSE);
+        auto* soupBuffer = soup_buffer_new_with_owner(g_bytes_get_data(data, nullptr),
+            g_bytes_get_size(data), data, reinterpret_cast<GDestroyNotify>(g_bytes_unref));
+        soup_message_body_append_buffer(soupMessage->request_body, soupBuffer);
+        soup_buffer_free(soupBuffer);
+    }
+    ASSERT(length == static_cast<uint64_t>(soupMessage->request_body->length));
+#else
     soup_message_set_request_body(soupMessage, nullptr, stream.get(), length);
+#endif
 }
 
 GRefPtr<GInputStream> ResourceRequest::createBodyStream() const
@@ -164,10 +182,39 @@ unsigned initializeMaximumHTTPConnection
     return 10000;
 }
 
+#if USE(SOUP2)
+GUniquePtr<SoupURI> ResourceRequest::createSoupURI() const
+{
+    // WebKit does not support fragment identifiers in data URLs, but soup does.
+    // Before passing the URL to soup, we should make sure to urlencode any '#'
+    // characters, so that soup does not interpret them as fragment identifiers.
+    // See http://wkbug.com/68089
+    if (m_requestData.m_url.protocolIsData()) {
+        String urlString = makeStringByReplacingAll(m_requestData.m_url.string(), '#', "%23"_s);
+        return GUniquePtr<SoupURI>(soup_uri_new(urlString.utf8().data()));
+    }
+
+    GUniquePtr<SoupURI> soupURI = urlToSoupURI(m_requestData.m_url);
+
+    // Versions of libsoup prior to 2.42 have a soup_uri_new that will convert empty passwords that are not
+    // prefixed by a colon into null. Some parts of soup like the SoupAuthenticationManager will only be active
+    // when both the username and password are non-null. When we have credentials, empty usernames and passwords
+    // should be empty strings instead of null.
+    String urlUser = m_requestData.m_url.user();
+    String urlPass = m_requestData.m_url.password();
+    if (!urlUser.isEmpty() || !urlPass.isEmpty()) {
+        soup_uri_set_user(soupURI.get(), urlUser.utf8().data());
+        soup_uri_set_password(soupURI.get(), urlPass.utf8().data());
+    }
+
+    return soupURI;
+}
+#else
 GRefPtr<GUri> ResourceRequest::createSoupURI() const
 {
     return m_requestData.m_url.createGUri();
 }
+#endif
 
 void ResourceRequest::updateFromDelegatePreservingOldProperties(const ResourceRequest& delegateProvidedRequest)
 {
diff -urpN webkitgtk-2.51.90.orig/Source/WebCore/platform/network/soup/ResourceResponseSoup.cpp webkitgtk-2.51.90/Source/WebCore/platform/network/soup/ResourceResponseSoup.cpp
--- webkitgtk-2.51.90.orig/Source/WebCore/platform/network/soup/ResourceResponseSoup.cpp	2026-01-23 02:35:25.971680900 -0600
+++ webkitgtk-2.51.90/Source/WebCore/platform/network/soup/ResourceResponseSoup.cpp	2026-01-24 09:48:37.067159193 -0600
@@ -28,6 +28,7 @@
 #include "HTTPHeaderNames.h"
 #include "HTTPParsers.h"
 #include "MIMETypeRegistry.h"
+#include "SoupVersioning.h"
 #include "URLSoup.h"
 #include <unicode/uset.h>
 #include <wtf/text/CString.h>
@@ -46,9 +47,11 @@ ResourceResponse::ResourceResponse(SoupM
     case SOUP_HTTP_1_1:
         m_httpVersion = "HTTP/1.1"_s;
         break;
+#if SOUP_CHECK_VERSION(2, 99, 3)
     case SOUP_HTTP_2_0:
         m_httpVersion = "HTTP/2"_s;
         break;
+#endif
     }
 
     m_httpStatusCode = soup_message_get_status(soupMessage);
diff -urpN webkitgtk-2.51.90.orig/Source/WebCore/platform/network/soup/SoupNetworkSession.cpp webkitgtk-2.51.90/Source/WebCore/platform/network/soup/SoupNetworkSession.cpp
--- webkitgtk-2.51.90.orig/Source/WebCore/platform/network/soup/SoupNetworkSession.cpp	2026-01-23 02:35:25.971680900 -0600
+++ webkitgtk-2.51.90/Source/WebCore/platform/network/soup/SoupNetworkSession.cpp	2026-01-24 09:48:37.067279190 -0600
@@ -32,6 +32,7 @@
 #include "AuthenticationChallenge.h"
 #include "GUniquePtrSoup.h"
 #include "Logging.h"
+#include "SoupVersioning.h"
 #include "WebKitAutoconfigProxyResolver.h"
 #include <glib/gstdio.h>
 #include <libsoup/soup.h>
@@ -111,8 +112,12 @@ SoupNetworkSession::SoupNetworkSession(P
 
     soup_session_add_feature_by_type(m_soupSession.get(), SOUP_TYPE_CONTENT_SNIFFER);
     soup_session_add_feature_by_type(m_soupSession.get(), SOUP_TYPE_AUTH_NTLM);
+#if SOUP_CHECK_VERSION(2, 67, 1)
     soup_session_add_feature_by_type(m_soupSession.get(), SOUP_TYPE_HSTS_ENFORCER);
+#endif
+#if SOUP_CHECK_VERSION(2, 67, 90)
     soup_session_add_feature_by_type(m_soupSession.get(), SOUP_TYPE_WEBSOCKET_EXTENSION_MANAGER);
+#endif
 
     if (!initialAcceptLanguages().isNull())
         setAcceptLanguages(initialAcceptLanguages());
@@ -149,7 +154,11 @@ void SoupNetworkSession::setupLogger()
     if (LogNetwork.state != WTFLogChannelState::On || soup_session_get_feature(m_soupSession.get(), SOUP_TYPE_LOGGER))
         return;
 
+#if USE(SOUP2)
+    GRefPtr<SoupLogger> logger = adoptGRef(soup_logger_new(SOUP_LOGGER_LOG_BODY, -1));
+#else
     GRefPtr<SoupLogger> logger = adoptGRef(soup_logger_new(SOUP_LOGGER_LOG_BODY));
+#endif
     soup_session_add_feature(m_soupSession.get(), SOUP_SESSION_FEATURE(logger.get()));
     soup_logger_set_printer(logger.get(), soupLogPrinter, nullptr, nullptr);
 #endif
@@ -172,6 +181,7 @@ void SoupNetworkSession::setHSTSPersiste
     if (m_sessionID.isEphemeral())
         return;
 
+#if SOUP_CHECK_VERSION(2, 67, 1)
     if (!FileSystem::makeAllDirectories(directory)) {
         RELEASE_LOG_ERROR(Network, "Unable to create the HSTS storage directory \"%s\". Using a memory enforcer instead.", directory.utf8().data());
         return;
@@ -182,10 +192,14 @@ void SoupNetworkSession::setHSTSPersiste
     GRefPtr<SoupHSTSEnforcer> enforcer = adoptGRef(soup_hsts_enforcer_db_new(dbFilename.get()));
     soup_session_remove_feature_by_type(m_soupSession.get(), SOUP_TYPE_HSTS_ENFORCER);
     soup_session_add_feature(m_soupSession.get(), SOUP_SESSION_FEATURE(enforcer.get()));
+#else
+    UNUSED_PARAM(directory);
+#endif
 }
 
 void SoupNetworkSession::getHostNamesWithHSTSCache(HashSet<String>& hostNames)
 {
+#if SOUP_CHECK_VERSION(2, 67, 91)
     auto* enforcer = SOUP_HSTS_ENFORCER(soup_session_get_feature(m_soupSession.get(), SOUP_TYPE_HSTS_ENFORCER));
     ASSERT(enforcer);
 
@@ -194,10 +208,14 @@ void SoupNetworkSession::getHostNamesWit
         GUniquePtr<gchar> domain(static_cast<gchar*>(iter->data));
         hostNames.add(String::fromUTF8(domain.get()));
     }
+#else
+    UNUSED_PARAM(hostNames);
+#endif
 }
 
 void SoupNetworkSession::deleteHSTSCacheForHostNames(const Vector<String>& hostNames)
 {
+#if SOUP_CHECK_VERSION(2, 67, 1)
     auto* enforcer = SOUP_HSTS_ENFORCER(soup_session_get_feature(m_soupSession.get(), SOUP_TYPE_HSTS_ENFORCER));
     ASSERT(enforcer);
 
@@ -205,22 +223,33 @@ void SoupNetworkSession::deleteHSTSCache
         GUniquePtr<SoupHSTSPolicy> policy(soup_hsts_policy_new(hostName.utf8().data(), SOUP_HSTS_POLICY_MAX_AGE_PAST, FALSE));
         soup_hsts_enforcer_set_policy(enforcer, policy.get());
     }
+#else
+    UNUSED_PARAM(hostNames);
+#endif
 }
 
 void SoupNetworkSession::clearHSTSCache(WallTime modifiedSince)
 {
+#if SOUP_CHECK_VERSION(2, 67, 91)
     auto* enforcer = SOUP_HSTS_ENFORCER(soup_session_get_feature(m_soupSession.get(), SOUP_TYPE_HSTS_ENFORCER));
     ASSERT(enforcer);
 
     GUniquePtr<GList> policies(soup_hsts_enforcer_get_policies(enforcer, FALSE));
     for (GList* iter = policies.get(); iter != nullptr; iter = iter->next) {
         GUniquePtr<SoupHSTSPolicy> policy(static_cast<SoupHSTSPolicy*>(iter->data));
+#if USE(SOUP2)
+        auto modified = soup_date_to_time_t(policy.get()->expires) - policy.get()->max_age;
+#else
         auto modified = g_date_time_to_unix(soup_hsts_policy_get_expires(policy.get())) - soup_hsts_policy_get_max_age(policy.get());
+#endif
         if (modified >= modifiedSince.secondsSinceEpoch().seconds()) {
             GUniquePtr<SoupHSTSPolicy> newPolicy(soup_hsts_policy_new(soup_hsts_policy_get_domain(policy.get()), SOUP_HSTS_POLICY_MAX_AGE_PAST, FALSE));
             soup_hsts_enforcer_set_policy(enforcer, newPolicy.get());
         }
     }
+#else
+    UNUSED_PARAM(modifiedSince);
+#endif
 }
 
 static inline bool stringIsNumeric(const std::string_view& str)
diff -urpN webkitgtk-2.51.90.orig/Source/WebCore/platform/network/soup/SoupVersioning.h webkitgtk-2.51.90/Source/WebCore/platform/network/soup/SoupVersioning.h
--- webkitgtk-2.51.90.orig/Source/WebCore/platform/network/soup/SoupVersioning.h	1969-12-31 18:00:00.000000000 -0600
+++ webkitgtk-2.51.90/Source/WebCore/platform/network/soup/SoupVersioning.h	2026-01-24 09:48:37.067500780 -0600
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2021 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#include <libsoup/soup.h>
+
+#if USE(SOUP2)
+
+static inline const char*
+soup_message_get_method(SoupMessage* message)
+{
+    g_return_val_if_fail(SOUP_IS_MESSAGE(message), nullptr);
+    return message->method;
+}
+
+static inline const char*
+soup_server_message_get_method(SoupMessage* message)
+{
+    return soup_message_get_method(message);
+}
+
+static inline SoupStatus
+soup_message_get_status(SoupMessage* message)
+{
+    g_return_val_if_fail(SOUP_IS_MESSAGE(message), SOUP_STATUS_NONE);
+    return static_cast<SoupStatus>(message->status_code);
+}
+
+static inline void
+soup_server_message_set_status(SoupMessage* message, unsigned statusCode, const char* reasonPhrase)
+{
+    if (reasonPhrase)
+        soup_message_set_status_full(message, statusCode, reasonPhrase);
+    else
+        soup_message_set_status(message, statusCode);
+}
+
+static inline const char*
+soup_message_get_reason_phrase(SoupMessage* message)
+{
+    g_return_val_if_fail(SOUP_IS_MESSAGE(message), nullptr);
+    return message->reason_phrase;
+}
+
+static inline SoupMessageHeaders*
+soup_message_get_request_headers(SoupMessage* message)
+{
+    g_return_val_if_fail(SOUP_IS_MESSAGE(message), nullptr);
+    return message->request_headers;
+}
+
+static inline SoupMessageHeaders*
+soup_server_message_get_request_headers(SoupMessage* message)
+{
+    return soup_message_get_request_headers(message);
+}
+
+static inline SoupMessageHeaders*
+soup_message_get_response_headers(SoupMessage* message)
+{
+    g_return_val_if_fail(SOUP_IS_MESSAGE(message), nullptr);
+    return message->response_headers;
+}
+
+static inline SoupMessageHeaders*
+soup_server_message_get_response_headers(SoupMessage* message)
+{
+    return soup_message_get_response_headers(message);
+}
+
+static inline SoupMessageBody*
+soup_server_message_get_response_body(SoupMessage* message)
+{
+    g_return_val_if_fail(SOUP_IS_MESSAGE(message), nullptr);
+    return message->response_body;
+}
+
+static inline void
+soup_server_message_set_response(SoupMessage* message, const char* contentType, SoupMemoryUse memoryUse, const char* responseBody, gsize length)
+{
+    return soup_message_set_response(message, contentType, memoryUse, responseBody, length);
+}
+
+static inline SoupURI*
+soup_server_message_get_uri(SoupMessage* message)
+{
+    return soup_message_get_uri(message);
+}
+
+static inline GTlsCertificate*
+soup_message_get_tls_peer_certificate(SoupMessage* message)
+{
+    g_return_val_if_fail(SOUP_IS_MESSAGE(message), nullptr);
+    GTlsCertificate* certificate = nullptr;
+    soup_message_get_https_status(message, &certificate, nullptr);
+    return certificate;
+}
+
+static inline GTlsCertificateFlags
+soup_message_get_tls_peer_certificate_errors(SoupMessage* message)
+{
+    g_return_val_if_fail(SOUP_IS_MESSAGE(message), static_cast<GTlsCertificateFlags>(0));
+    GTlsCertificateFlags flags = static_cast<GTlsCertificateFlags>(0);
+    soup_message_get_https_status(message, nullptr, &flags);
+    return flags;
+}
+
+static inline void
+soup_session_send_async(SoupSession* session, SoupMessage* message, int, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
+{
+    soup_session_send_async(session, message, cancellable, callback, userData);
+}
+
+static inline void
+soup_session_websocket_connect_async(SoupSession* session, SoupMessage* message, const char* origin, char** protocols, int, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
+{
+    soup_session_websocket_connect_async(session, message, origin, protocols, cancellable, callback, userData);
+}
+
+static inline void
+soup_auth_cancel(SoupAuth*)
+{
+}
+
+static inline void
+soup_session_set_proxy_resolver(SoupSession* session, GProxyResolver* resolver)
+{
+    g_object_set(session, "proxy-resolver", resolver, nullptr);
+}
+
+static inline GProxyResolver*
+soup_session_get_proxy_resolver(SoupSession* session)
+{
+    GRefPtr<GProxyResolver> resolver;
+    g_object_get(session, "proxy-resolver", &resolver.outPtr(), nullptr);
+    return resolver.get();
+}
+
+static inline void
+soup_session_set_accept_language(SoupSession* session, const char* acceptLanguage)
+{
+    g_object_set(session, "accept-language", acceptLanguage, nullptr);
+}
+
+static inline void
+soup_session_set_tls_database(SoupSession *session, GTlsDatabase *tls_database)
+{
+    g_object_set(session, "tls-database", tls_database, NULL);
+}
+
+#endif // USE(SOUP2)
diff -urpN webkitgtk-2.51.90.orig/Source/WebCore/platform/network/soup/URLSoup.cpp webkitgtk-2.51.90/Source/WebCore/platform/network/soup/URLSoup.cpp
--- webkitgtk-2.51.90.orig/Source/WebCore/platform/network/soup/URLSoup.cpp	2026-01-23 02:35:25.971680900 -0600
+++ webkitgtk-2.51.90/Source/WebCore/platform/network/soup/URLSoup.cpp	2026-01-24 09:48:37.067662947 -0600
@@ -30,6 +30,37 @@
 
 namespace WebCore {
 
+#if USE(SOUP2)
+URL soupURIToURL(SoupURI* soupURI)
+{
+    if (!soupURI)
+        return URL();
+
+    GUniquePtr<gchar> urlString(soup_uri_to_string(soupURI, FALSE));
+    URL url { String::fromUTF8(urlString.get()) };
+    if (url.isValid()) {
+        // Motivated by https://bugs.webkit.org/show_bug.cgi?id=38956. libsoup
+        // does not add the password to the URL when calling
+        // soup_uri_to_string, and thus the requests are not properly
+        // built. Fixing soup_uri_to_string is a no-no as the maintainer does
+        // not want to break compatibility with previous implementations
+        if (soupURI->password)
+            url.setPassword(String::fromUTF8(soupURI->password));
+    }
+
+    return url;
+}
+
+GUniquePtr<SoupURI> urlToSoupURI(const URL& url)
+{
+    if (!url.isValid())
+        return nullptr;
+
+    return GUniquePtr<SoupURI>(soup_uri_new(url.string().utf8().data()));
+}
+
+#else // !USE(SOUP2)
+
 URL soupURIToURL(GUri* uri)
 {
     return uri;
@@ -39,5 +70,6 @@ GRefPtr<GUri> urlToSoupURI(const URL& ur
 {
     return url.createGUri();
 }
+#endif // USE(SOUP2)
 
 } // namespace WebCore
diff -urpN webkitgtk-2.51.90.orig/Source/WebCore/platform/network/soup/URLSoup.h webkitgtk-2.51.90/Source/WebCore/platform/network/soup/URLSoup.h
--- webkitgtk-2.51.90.orig/Source/WebCore/platform/network/soup/URLSoup.h	2026-01-23 02:35:25.971680900 -0600
+++ webkitgtk-2.51.90/Source/WebCore/platform/network/soup/URLSoup.h	2026-01-24 09:48:37.067755843 -0600
@@ -33,6 +33,11 @@ class URL;
 }
 
 namespace WebCore {
+#if USE(SOUP2)
+URL soupURIToURL(SoupURI*);
+GUniquePtr<SoupURI> urlToSoupURI(const URL&);
+#else
 URL soupURIToURL(GUri*);
 GRefPtr<GUri> urlToSoupURI(const URL&);
+#endif
 } // namespace WebCore
diff -urpN webkitgtk-2.51.90.orig/Source/WebCore/platform/Soup.cmake webkitgtk-2.51.90/Source/WebCore/platform/Soup.cmake
--- webkitgtk-2.51.90.orig/Source/WebCore/platform/Soup.cmake	2026-01-23 02:35:25.739458800 -0600
+++ webkitgtk-2.51.90/Source/WebCore/platform/Soup.cmake	2026-01-24 10:48:30.074067023 -0600
@@ -16,7 +16,14 @@ list(APPEND WebCore_PRIVATE_FRAMEWORK_HE
     platform/network/soup/ResourceResponse.h
     platform/network/soup/SoupNetworkProxySettings.h
     platform/network/soup/SoupNetworkSession.h
+    platform/network/soup/SoupVersioning.h
     platform/network/soup/URLSoup.h
 )
 
-list(APPEND WebCore_LIBRARIES Soup3::Soup3)
+list(APPEND WebCore_SYSTEM_INCLUDE_DIRECTORIES
+    ${LIBSOUP_INCLUDE_DIRS}
+)
+
+list(APPEND WebCore_LIBRARIES
+    ${LIBSOUP_LIBRARIES}
+)
diff -urpN webkitgtk-2.51.90.orig/Source/WebDriver/PlatformGTK.cmake webkitgtk-2.51.90/Source/WebDriver/PlatformGTK.cmake
--- webkitgtk-2.51.90.orig/Source/WebDriver/PlatformGTK.cmake	2026-01-23 02:35:26.158415800 -0600
+++ webkitgtk-2.51.90/Source/WebDriver/PlatformGTK.cmake	2026-01-24 11:10:46.440111444 -0600
@@ -2,6 +2,10 @@ set(WebDriver_OUTPUT_NAME WebKitWebDrive
 
 add_definitions(-DLIBEXECDIR="${CMAKE_INSTALL_FULL_LIBEXECDIR}")
 
+list(APPEND WebDriver_SYSTEM_INCLUDE_DIRECTORIES
+    "${LIBSOUP_INCLUDE_DIRS}"
+)
+
 list(APPEND WebDriver_SOURCES
     glib/SessionHostGlib.cpp
     glib/WebDriverServiceGLib.cpp
@@ -17,4 +21,6 @@ if (ENABLE_WEBDRIVER_BIDI)
     list(APPEND WebDriver_SOURCES soup/WebSocketServerSoup.cpp)
 endif ()
 
-list(APPEND WebDriver_LIBRARIES Soup3::Soup3)
+list(APPEND WebDriver_LIBRARIES
+    ${LIBSOUP_LIBRARIES}
+)
diff -urpN webkitgtk-2.51.90.orig/Source/WebDriver/soup/HTTPServerSoup.cpp webkitgtk-2.51.90/Source/WebDriver/soup/HTTPServerSoup.cpp
--- webkitgtk-2.51.90.orig/Source/WebDriver/soup/HTTPServerSoup.cpp	2026-01-23 02:35:26.160735400 -0600
+++ webkitgtk-2.51.90/Source/WebDriver/soup/HTTPServerSoup.cpp	2026-01-24 09:48:37.067979948 -0600
@@ -60,6 +60,25 @@ bool HTTPServer::listen(const std::optio
         return false;
     }
 
+#if USE(SOUP2)
+    soup_server_add_handler(m_soupServer.get(), nullptr, [](SoupServer* server, SoupMessage* message, const char* path, GHashTable*, SoupClientContext*, gpointer userData) {
+        auto* httpServer = static_cast<HTTPServer*>(userData);
+        GRefPtr<SoupMessage> protectedMessage = message;
+        soup_server_pause_message(server, message);
+        httpServer->m_requestHandler.handleRequest({ String::fromUTF8(message->method), String::fromUTF8(path), message->request_body->data, static_cast<size_t>(message->request_body->length) },
+            [server, message = WTF::Move(protectedMessage)](HTTPRequestHandler::Response&& response) {
+                soup_message_set_status(message.get(), response.statusCode);
+                if (!response.data.isNull()) {
+                    // ยง6.3 Processing Model.
+                    // https://w3c.github.io/webdriver/webdriver-spec.html#dfn-send-a-response
+                    soup_message_headers_append(message->response_headers, "Content-Type", response.contentType.utf8().data());
+                    soup_message_headers_append(message->response_headers, "Cache-Control", "no-cache");
+                    soup_message_body_append(message->response_body, SOUP_MEMORY_COPY, response.data.data(), response.data.length());
+                }
+                soup_server_unpause_message(server, message.get());
+        });
+    }, this, nullptr);
+#else
     soup_server_add_handler(m_soupServer.get(), nullptr, [](SoupServer* server, SoupServerMessage* message, const char* path, GHashTable*, gpointer userData) {
         auto& httpServer = *static_cast<HTTPServer*>(userData);
         GRefPtr<SoupServerMessage> protectedMessage = message;
@@ -86,6 +105,7 @@ bool HTTPServer::listen(const std::optio
                 soup_server_unpause_message(server, message.get());
         });
     }, this, nullptr);
+#endif
 
     return true;
 }
diff -urpN webkitgtk-2.51.90.orig/Source/WebDriver/soup/WebSocketServerSoup.cpp webkitgtk-2.51.90/Source/WebDriver/soup/WebSocketServerSoup.cpp
--- webkitgtk-2.51.90.orig/Source/WebDriver/soup/WebSocketServerSoup.cpp	2026-01-23 02:35:26.161816600 -0600
+++ webkitgtk-2.51.90/Source/WebDriver/soup/WebSocketServerSoup.cpp	2026-01-24 09:48:37.068120484 -0600
@@ -41,6 +41,8 @@
 
 namespace WebDriver {
 
+#if !USE(SOUP2)
+
 static bool soupServerListen(SoupServer* server, const String& host, unsigned port, GError** error)
 {
     static const auto options = static_cast<SoupServerListenOptions>(0);
@@ -134,9 +136,17 @@ static void handleWebSocketConnection(So
 
     g_signal_connect(connection, "message", G_CALLBACK(handleWebSocketMessage), webSocketServer);
 }
+#endif // !USE(SOUP2)
 
 std::optional<String> WebSocketServer::listen(const String& host, unsigned port)
 {
+#if USE(SOUP2)
+    UNUSED_PARAM(host);
+    UNUSED_PARAM(port);
+    RELEASE_LOG(WebDriverBiDi, "WebSockets support not implemented yet with libsoup2");
+    return std::nullopt;
+#else
+
     m_soupServer = adoptGRef(soup_server_new("server-header", "WebKitWebDriver-WSS", nullptr));
     GUniqueOutPtr<GError> error;
     if (!soupServerListen(m_soupServer.get(), host, port, &error.outPtr())) {
@@ -158,18 +168,28 @@ std::optional<String> WebSocketServer::l
         { "/session"_s }
     );
     return getWebSocketURL(m_listener, nullString());
+#endif
 }
 
 void WebSocketServer::sendMessage(WebSocketMessageHandler::Connection connection, const String& message)
 {
+#if USE(SOUP2)
+    UNUSED_PARAM(connection);
+    UNUSED_PARAM(message);
+    RELEASE_LOG(WebDriverBiDi, "WebSockets support not implemented yet with libsoup2");
+#else
     ASSERT(connection);
     RELEASE_LOG(WebDriverBiDi, "Sending message: %s", message.utf8().data());
     GRefPtr<GBytes> rawMessage = adoptGRef(g_bytes_new(message.utf8().data(), message.utf8().length()));
     soup_websocket_connection_send_message(connection.get(), SOUP_WEBSOCKET_DATA_TEXT, rawMessage.get());
+#endif
 }
 
 void WebSocketServer::disconnect()
 {
+#if USE(SOUP2)
+    RELEASE_LOG(WebDriverBiDi, "WebSockets support not implemented yet with libsoup2");
+#else
     if (!m_soupServer)
         return;
 
@@ -181,16 +201,22 @@ void WebSocketServer::disconnect()
 
     soup_server_disconnect(m_soupServer.get());
     m_soupServer = nullptr;
+#endif
 }
 
 void WebSocketServer::disconnectSession(const String& sessionId)
 {
+#if USE(SOUP2)
+    UNUSED_PARAM(sessionId);
+    RELEASE_LOG(WebDriverBiDi, "WebSockets support not implemented yet with libsoup2");
+#else
     auto connection = this->connection(sessionId);
     if (!connection || !connection->get())
         return;
 
     soup_websocket_connection_close(connection->get(), SOUP_WEBSOCKET_CLOSE_NORMAL, nullptr);
     g_signal_handlers_disconnect_by_data(connection->get(), this);
+#endif
 }
 
 } // namespace WebDriver
diff -urpN webkitgtk-2.51.90.orig/Source/WebKit/gtk/gtk3-webkitgtk.toml.in webkitgtk-2.51.90/Source/WebKit/gtk/gtk3-webkitgtk.toml.in
--- webkitgtk-2.51.90.orig/Source/WebKit/gtk/gtk3-webkitgtk.toml.in	2026-01-23 02:35:26.798896600 -0600
+++ webkitgtk-2.51.90/Source/WebKit/gtk/gtk3-webkitgtk.toml.in	2026-01-24 09:34:19.302780692 -0600
@@ -5,7 +5,7 @@ authors = "The WebKit GTK and WPE teams"
 version = "@PROJECT_VERSION@"
 repository_url = "https://github.com/WebKit/WebKit"
 website_url = "https://webkit.org"
-dependencies = ["GObject-2.0", "Gio-2.0", "Gtk-@GTK_API_VERSION@.0", "Soup-3.0"]
+dependencies = ["GObject-2.0", "Gio-2.0", "Gtk-@GTK_API_VERSION@.0", "Soup-@SOUP_API_VERSION@"]
 devhelp = true
 search_index = true
 
@@ -24,10 +24,10 @@ name = "Gtk"
 description = "The GTK widget toolkit"
 docs_url = "https://docs.gtk.org/gtk@GTK_API_VERSION@/"
 
-[dependencies."Soup-3.0"]
+[dependencies."Soup-@SOUP_API_VERSION@"]
 name = "Soup"
 description = "HTTP client/server library"
-docs_url = "https://gnome.pages.gitlab.gnome.org/libsoup/libsoup-3.0"
+docs_url = "https://gnome.pages.gitlab.gnome.org/libsoup/libsoup-@SOUP_API_VERSION@"
 
 [theme]
 name = "basic"
diff -urpN webkitgtk-2.51.90.orig/Source/WebKit/gtk/gtk4-webkitgtk.toml.in webkitgtk-2.51.90/Source/WebKit/gtk/gtk4-webkitgtk.toml.in
--- webkitgtk-2.51.90.orig/Source/WebKit/gtk/gtk4-webkitgtk.toml.in	2026-01-23 02:35:26.798896600 -0600
+++ webkitgtk-2.51.90/Source/WebKit/gtk/gtk4-webkitgtk.toml.in	2026-01-24 09:34:19.304098353 -0600
@@ -5,7 +5,7 @@ authors = "The WebKit GTK and WPE teams"
 version = "@PROJECT_VERSION@"
 repository_url = "https://github.com/WebKit/WebKit"
 website_url = "https://webkit.org"
-dependencies = ["GObject-2.0", "Gio-2.0", "Gtk-@GTK_API_VERSION@.0", "Soup-3.0"]
+dependencies = ["GObject-2.0", "Gio-2.0", "Gtk-@GTK_API_VERSION@.0", "Soup-@SOUP_API_VERSION@"]
 devhelp = true
 search_index = true
 
@@ -24,10 +24,10 @@ name = "Gtk"
 description = "The GTK widget toolkit"
 docs_url = "https://docs.gtk.org/gtk@GTK_API_VERSION@/"
 
-[dependencies."Soup-3.0"]
+[dependencies."Soup-@SOUP_API_VERSION@"]
 name = "Soup"
 description = "HTTP client/server library"
-docs_url = "https://gnome.pages.gitlab.gnome.org/libsoup/libsoup-3.0"
+docs_url = "https://gnome.pages.gitlab.gnome.org/libsoup/libsoup-@SOUP_API_VERSION@"
 
 [theme]
 name = "basic"
diff -urpN webkitgtk-2.51.90.orig/Source/WebKit/gtk/webkitgtk.pc.in webkitgtk-2.51.90/Source/WebKit/gtk/webkitgtk.pc.in
--- webkitgtk-2.51.90.orig/Source/WebKit/gtk/webkitgtk.pc.in	2026-01-23 02:35:26.798896600 -0600
+++ webkitgtk-2.51.90/Source/WebKit/gtk/webkitgtk.pc.in	2026-01-24 09:34:19.304457855 -0600
@@ -8,6 +8,6 @@ Name: WebKitGTK
 Description: Web content engine for GTK
 URL: https://webkitgtk.org
 Version: @PROJECT_VERSION@
-Requires: glib-2.0 @GTK_PC_NAME@ libsoup-3.0 javascriptcoregtk-@WEBKITGTK_API_VERSION@
+Requires: glib-2.0 @GTK_PC_NAME@ libsoup-@SOUP_API_VERSION@ javascriptcoregtk-@WEBKITGTK_API_VERSION@
 Libs: -L${libdir} -lwebkit@WEBKITGTK_API_INFIX@gtk-@WEBKITGTK_API_VERSION@
 Cflags: -I${includedir}/webkitgtk-@WEBKITGTK_API_VERSION@
diff -urpN webkitgtk-2.51.90.orig/Source/WebKit/gtk/webkitgtk-web-process-extension.pc.in webkitgtk-2.51.90/Source/WebKit/gtk/webkitgtk-web-process-extension.pc.in
--- webkitgtk-2.51.90.orig/Source/WebKit/gtk/webkitgtk-web-process-extension.pc.in	2026-01-23 02:35:26.798896600 -0600
+++ webkitgtk-2.51.90/Source/WebKit/gtk/webkitgtk-web-process-extension.pc.in	2026-01-24 09:34:19.304218461 -0600
@@ -8,6 +8,6 @@ Name: WebKitGTK web process extensions
 Description: Web content engine for GTK - web process extensions
 URL: https://webkitgtk.org
 Version: @PROJECT_VERSION@
-Requires: glib-2.0 @GTK_PC_NAME@ libsoup-3.0 javascriptcoregtk-@WEBKITGTK_API_VERSION@
+Requires: glib-2.0 @GTK_PC_NAME@ libsoup-@SOUP_API_VERSION@ javascriptcoregtk-@WEBKITGTK_API_VERSION@
 Libs: -L${libdir} -lwebkit@WEBKITGTK_API_INFIX@gtk-@WEBKITGTK_API_VERSION@
 Cflags: -I${includedir}/webkitgtk-@WEBKITGTK_API_VERSION@
diff -urpN webkitgtk-2.51.90.orig/Source/WebKit/gtk/webkitgtk-web-process-extension.toml.in webkitgtk-2.51.90/Source/WebKit/gtk/webkitgtk-web-process-extension.toml.in
--- webkitgtk-2.51.90.orig/Source/WebKit/gtk/webkitgtk-web-process-extension.toml.in	2026-01-23 02:35:26.798896600 -0600
+++ webkitgtk-2.51.90/Source/WebKit/gtk/webkitgtk-web-process-extension.toml.in	2026-01-24 09:34:19.304340562 -0600
@@ -5,7 +5,7 @@ authors = "The WebKit GTK and WPE teams"
 version = "@PROJECT_VERSION@"
 repository_url = "https://github.com/WebKit/WebKit"
 website_url = "https://webkit.org"
-dependencies = ["GObject-2.0", "Gio-2.0", "Soup-3.0"]
+dependencies = ["GObject-2.0", "Gio-2.0", "Soup-@SOUP_API_VERSION@"]
 devhelp = true
 search_index = true
 
@@ -19,10 +19,10 @@ name = "Gio"
 description = "GObject Interfaces and Objects, Networking, IPC, and I/O"
 docs_url = "https://docs.gtk.org/gio/"
 
-[dependencies."Soup-3.0"]
+[dependencies."Soup-@SOUP_API_VERSION@"]
 name = "Soup"
 description = "HTTP client/server library"
-docs_url = "https://gnome.pages.gitlab.gnome.org/libsoup/libsoup-3.0"
+docs_url = "https://gnome.pages.gitlab.gnome.org/libsoup/libsoup-@SOUP_API_VERSION@"
 
 [theme]
 name = "basic"
diff -urpN webkitgtk-2.51.90.orig/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp webkitgtk-2.51.90/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp
--- webkitgtk-2.51.90.orig/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp	2026-01-23 02:35:26.334077800 -0600
+++ webkitgtk-2.51.90/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp	2026-01-24 10:31:25.881576337 -0600
@@ -44,6 +44,7 @@
 #include <WebCore/SharedBuffer.h>
 #include <WebCore/ShouldRelaxThirdPartyCookieBlocking.h>
 #include <WebCore/SoupNetworkSession.h>
+#include <WebCore/SoupVersioning.h>
 #include <WebCore/TimingAllowOrigin.h>
 #include <pal/text/TextEncoding.h>
 #include <wtf/MainThread.h>
@@ -66,6 +67,10 @@ NetworkDataTaskSoup::NetworkDataTaskSoup
 {
     auto request = parameters.request;
     if (request.url().protocolIsInHTTPFamily()) {
+#if USE(SOUP2)
+        m_networkLoadMetrics.fetchStart = MonotonicTime::now();
+        m_networkLoadMetrics.redirectStart = m_networkLoadMetrics.fetchStart;
+#endif
         auto url = request.url();
         if (m_storedCredentialsPolicy == StoredCredentialsPolicy::Use) {
             m_user = url.user();
@@ -156,18 +161,28 @@ void NetworkDataTaskSoup::createRequest(
     }
 
     if (m_shouldPreconnectOnly == PreconnectOnly::Yes) {
+#if !USE(SOUP2)
         g_signal_connect(m_soupMessage.get(), "accept-certificate", G_CALLBACK(acceptCertificateCallback), this);
+#endif
         return;
     }
 
     m_networkLoadMetrics.redirectCount = m_currentRequest.redirectCount();
 
     unsigned messageFlags = SOUP_MESSAGE_NO_REDIRECT;
+#if !USE(SOUP2)
     messageFlags |= SOUP_MESSAGE_COLLECT_METRICS;
+#endif
     if (m_shouldContentSniff == ContentSniffingPolicy::DoNotSniffContent)
         soup_message_disable_feature(m_soupMessage.get(), SOUP_TYPE_CONTENT_SNIFFER);
     if (m_user.isEmpty() && m_password.isEmpty() && m_storedCredentialsPolicy == StoredCredentialsPolicy::DoNotUse) {
+#if SOUP_CHECK_VERSION(2, 57, 1)
         messageFlags |= SOUP_MESSAGE_DO_NOT_USE_AUTH_CACHE;
+#else
+        // In case credential is not available and credential storage should not to be used,
+        // disable authentication manager so that credentials stored in libsoup are not used.
+        soup_message_disable_feature(m_soupMessage.get(), SOUP_TYPE_AUTH_MANAGER);
+#endif
     }
     soup_message_set_flags(m_soupMessage.get(), static_cast<SoupMessageFlags>(soup_message_get_flags(m_soupMessage.get()) | messageFlags));
 
@@ -180,18 +195,37 @@ void NetworkDataTaskSoup::createRequest(
         soup_message_disable_feature(m_soupMessage.get(), SOUP_TYPE_COOKIE_JAR);
     m_isBlockingCookies = shouldBlockCookies;
 
+#if SOUP_CHECK_VERSION(2, 67, 1)
     if ((m_currentRequest.url().protocolIs("https"_s) && !shouldAllowHSTSPolicySetting()) || (m_currentRequest.url().protocolIs("http"_s) && !shouldAllowHSTSProtocolUpgrade()))
         soup_message_disable_feature(m_soupMessage.get(), SOUP_TYPE_HSTS_ENFORCER);
-    else
+    else {
+#if USE(SOUP2)
+        g_signal_connect(soup_session_get_feature(static_cast<NetworkSessionSoup&>(*m_session).soupSession(), SOUP_TYPE_HSTS_ENFORCER), "hsts-enforced", G_CALLBACK(hstsEnforced), this);
+#else
         g_signal_connect(m_soupMessage.get(), "hsts-enforced", G_CALLBACK(hstsEnforced), this);
+#endif
+    }
+#endif
 
     // Make sure we have an Accept header for subresources; some sites want this to serve some of their subresources.
     auto* requestHeaders = soup_message_get_request_headers(m_soupMessage.get());
     if (!soup_message_headers_get_one(requestHeaders, "Accept"))
         soup_message_headers_append(requestHeaders, "Accept", "*/*");
 
+#if USE(SOUP2)
+    // In the case of XHR .send() and .send("") explicitly tell libsoup to send a zero content-lenght header
+    // for consistency with other UA implementations like Firefox. It's done in the backend here instead of
+    // in XHR code since in XHR CORS checking prevents us from this kind of late header manipulation.
+    if ((m_soupMessage->method == SOUP_METHOD_POST || m_soupMessage->method == SOUP_METHOD_PUT) && !m_soupMessage->request_body->length)
+        soup_message_headers_set_content_length(m_soupMessage->request_headers, 0);
+#endif
+
     g_signal_connect(m_soupMessage.get(), "got-headers", G_CALLBACK(gotHeadersCallback), this);
     g_signal_connect(m_soupMessage.get(), "wrote-body-data", G_CALLBACK(wroteBodyDataCallback), this);
+#if USE(SOUP2)
+    g_signal_connect(static_cast<NetworkSessionSoup&>(*m_session).soupSession(), "authenticate",  G_CALLBACK(authenticateCallback), this);
+    g_signal_connect(m_soupMessage.get(), "network-event", G_CALLBACK(networkEventCallback), this);
+#else
     g_signal_connect(m_soupMessage.get(), "authenticate", G_CALLBACK(authenticateCallback), this);
     g_signal_connect(m_soupMessage.get(), "accept-certificate", G_CALLBACK(acceptCertificateCallback), this);
     g_signal_connect(m_soupMessage.get(), "got-body", G_CALLBACK(gotBodyCallback), this);
@@ -201,6 +235,7 @@ void NetworkDataTaskSoup::createRequest(
     }
     g_signal_connect(m_soupMessage.get(), "request-certificate", G_CALLBACK(requestCertificateCallback), this);
     g_signal_connect(m_soupMessage.get(), "request-certificate-password", G_CALLBACK(requestCertificatePasswordCallback), this);
+#endif
     g_signal_connect(m_soupMessage.get(), "restarted", G_CALLBACK(restartedCallback), this);
     g_signal_connect(m_soupMessage.get(), "starting", G_CALLBACK(startingCallback), this);
     if (m_shouldContentSniff == ContentSniffingPolicy::SniffContent)
@@ -226,14 +261,27 @@ void NetworkDataTaskSoup::clearRequest()
     m_isBlockingCookies = false;
     if (m_soupMessage) {
         g_signal_handlers_disconnect_matched(m_soupMessage.get(), G_SIGNAL_MATCH_DATA, 0, 0, nullptr, nullptr, this);
+#if USE(SOUP2)
+        if (m_session)
+            soup_session_cancel_message(static_cast<NetworkSessionSoup&>(*m_session).soupSession(), m_soupMessage.get(), SOUP_STATUS_CANCELLED);
+#else
         if (m_networkLoadMetrics.fetchStart && !m_networkLoadMetrics.responseEnd) {
             auto* metrics = soup_message_get_metrics(m_soupMessage.get());
             auto responseEnd = Seconds::fromMicroseconds(soup_message_metrics_get_response_end(metrics));
             m_networkLoadMetrics.responseEnd = MonotonicTime::fromRawSeconds(responseEnd.seconds());
             m_networkLoadMetrics.markComplete();
         }
+#endif
         m_soupMessage = nullptr;
     }
+    if (m_session) {
+#if USE(SOUP2)
+        g_signal_handlers_disconnect_matched(static_cast<NetworkSessionSoup&>(*m_session).soupSession(), G_SIGNAL_MATCH_DATA, 0, 0, nullptr, nullptr, this);
+#if SOUP_CHECK_VERSION(2, 67, 1)
+        g_signal_handlers_disconnect_by_data(soup_session_get_feature(static_cast<NetworkSessionSoup&>(*m_session).soupSession(), SOUP_TYPE_HSTS_ENFORCER), this);
+#endif
+#endif
+    }
 }
 
 void NetworkDataTaskSoup::resume()
@@ -250,8 +298,12 @@ void NetworkDataTaskSoup::resume()
     if (m_soupMessage && !m_cancellable) {
         m_cancellable = adoptGRef(g_cancellable_new());
         if (m_shouldPreconnectOnly == PreconnectOnly::Yes) {
+#if !USE(SOUP2)
             soup_session_preconnect_async(static_cast<NetworkSessionSoup&>(*m_session).soupSession(), m_soupMessage.get(), RunLoopSourcePriority::AsyncIONetwork, m_cancellable.get(),
                 reinterpret_cast<GAsyncReadyCallback>(preconnectCallback), protectedThis.leakRef());
+#else
+            RELEASE_ASSERT_NOT_REACHED();
+#endif
         } else {
             // We need to protect cancellable here, because soup_session_send_async uses it after emitting SoupSession::request-queued, and we
             // might cancel the operation in a feature callback emitted on request-queued, for example hsts-enforced.
@@ -259,8 +311,12 @@ void NetworkDataTaskSoup::resume()
             soup_session_send_async(static_cast<NetworkSessionSoup&>(*m_session).soupSession(), m_soupMessage.get(), RunLoopSourcePriority::AsyncIONetwork, m_cancellable.get(),
                 reinterpret_cast<GAsyncReadyCallback>(sendRequestCallback), new SendRequestData({ m_soupMessage, WTF::move(protectedThis) }));
             if (!g_cancellable_is_cancelled(protectCancellable.get()) && !m_networkLoadMetrics.fetchStart) {
+#if USE(SOUP2)
+                m_networkLoadMetrics.fetchStart = MonotonicTime::now();
+#else
                 auto* metrics = soup_message_get_metrics(m_soupMessage.get());
                 m_networkLoadMetrics.fetchStart = MonotonicTime::fromRawSeconds(Seconds::fromMicroseconds(soup_message_metrics_get_fetch_start(metrics)).seconds());
+#endif
                 if (!m_networkLoadMetrics.redirectStart)
                     m_networkLoadMetrics.redirectStart = m_networkLoadMetrics.fetchStart;
             }
@@ -302,6 +358,11 @@ void NetworkDataTaskSoup::cancel()
 
     m_state = State::Canceling;
 
+#if USE(SOUP2)
+    if (m_soupMessage)
+        soup_session_cancel_message(static_cast<NetworkSessionSoup&>(*m_session).soupSession(), m_soupMessage.get(), SOUP_STATUS_CANCELLED);
+#endif
+
     g_cancellable_cancel(m_cancellable.get());
 
     if (isDownload())
@@ -396,6 +457,10 @@ void NetworkDataTaskSoup::didSendRequest
     else
         m_inputStream = WTF::move(inputStream);
 
+#if USE(SOUP2)
+    m_networkLoadMetrics.responseStart = MonotonicTime::now();
+#endif
+
     dispatchDidReceiveResponse();
 }
 
@@ -440,6 +505,7 @@ void NetworkDataTaskSoup::dispatchDidRec
     });
 }
 
+#if !USE(SOUP2)
 void NetworkDataTaskSoup::preconnectCallback(SoupSession* session, GAsyncResult* result, NetworkDataTaskSoup* task)
 {
     RefPtr<NetworkDataTaskSoup> protectedThis = adoptRef(task);
@@ -455,12 +521,33 @@ void NetworkDataTaskSoup::preconnectCall
     task->clearRequest();
     task->dispatchDidCompleteWithError(resourceError);
 }
+#endif
 
 void NetworkDataTaskSoup::dispatchDidCompleteWithError(const ResourceError& error)
 {
+#if USE(SOUP2)
+    m_networkLoadMetrics.responseEnd = MonotonicTime::now();
+    m_networkLoadMetrics.markComplete();
+#endif
+
     m_client->didCompleteWithError(error, m_networkLoadMetrics);
 }
 
+#if USE(SOUP2)
+gboolean NetworkDataTaskSoup::tlsConnectionAcceptCertificateCallback(GTlsConnection* connection, GTlsCertificate* certificate, GTlsCertificateFlags errors, NetworkDataTaskSoup* task)
+{
+    if (task->state() == State::Canceling || task->state() == State::Completed || !task->m_client) {
+        task->clearRequest();
+        return FALSE;
+    }
+
+    auto* connectionMessage = g_object_get_data(G_OBJECT(connection), "wk-soup-message");
+    if (connectionMessage != task->m_soupMessage.get())
+        return FALSE;
+
+    return task->acceptCertificate(certificate, errors);
+}
+#else
 gboolean NetworkDataTaskSoup::acceptCertificateCallback(SoupMessage* message, GTlsCertificate* certificate, GTlsCertificateFlags errors, NetworkDataTaskSoup* task)
 {
     if (task->state() == State::Canceling || task->state() == State::Completed || !task->m_client)
@@ -470,6 +557,7 @@ gboolean NetworkDataTaskSoup::acceptCert
 
     return task->acceptCertificate(certificate, errors);
 }
+#endif
 
 bool NetworkDataTaskSoup::acceptCertificate(GTlsCertificate* certificate, GTlsCertificateFlags tlsErrors)
 {
@@ -534,6 +622,26 @@ void NetworkDataTaskSoup::applyAuthentic
     m_password = String();
 }
 
+#if USE(SOUP2)
+void NetworkDataTaskSoup::authenticateCallback(SoupSession* session, SoupMessage* soupMessage, SoupAuth* soupAuth, gboolean retrying, NetworkDataTaskSoup* task)
+{
+    ASSERT(session == static_cast<NetworkSessionSoup&>(*task->m_session).soupSession());
+
+    // We don't return early here in case the given soupMessage is different to m_soupMessage when
+    // it's proxy authentication and the request URL is HTTPS, because in that case libsoup uses a
+    // tunnel internally and the SoupMessage used for the authentication is the tunneling one.
+    // See https://bugs.webkit.org/show_bug.cgi?id=175378.
+    if (soupMessage != task->m_soupMessage.get() && (soupMessage->status_code != SOUP_STATUS_PROXY_AUTHENTICATION_REQUIRED || !task->m_currentRequest.url().protocolIs("https"_s)))
+        return;
+
+    if (task->state() == State::Canceling || task->state() == State::Completed || !task->m_client) {
+        task->clearRequest();
+        return;
+    }
+
+    task->authenticate(AuthenticationChallenge(soupMessage, soupAuth, retrying));
+}
+#else
 gboolean NetworkDataTaskSoup::authenticateCallback(SoupMessage* soupMessage, SoupAuth* soupAuth, gboolean retrying, NetworkDataTaskSoup* task)
 {
     if (task->state() == State::Canceling || task->state() == State::Completed || !task->m_client) {
@@ -545,6 +653,7 @@ gboolean NetworkDataTaskSoup::authentica
     task->authenticate(AuthenticationChallenge(soupMessage, soupAuth, retrying));
     return TRUE;
 }
+#endif
 
 static inline bool isAuthenticationFailureStatusCode(int httpStatusCode)
 {
@@ -564,13 +673,21 @@ void NetworkDataTaskSoup::completeAuthen
         soup_auth_authenticate(challenge.soupAuth(), credential.user().utf8().data(), credential.password().utf8().data());
         break;
     case ProtectionSpace::AuthenticationScheme::ClientCertificatePINRequested: {
+#if USE(SOUP2)
+        ASSERT_NOT_REACHED();
+#else
         CString password = credential.password().utf8();
         g_tls_password_set_value(challenge.tlsPassword(), reinterpret_cast<const unsigned char*>(password.data()), password.length());
         soup_message_tls_client_certificate_password_request_complete(m_soupMessage.get());
+#endif
         break;
     }
     case ProtectionSpace::AuthenticationScheme::ClientCertificateRequested:
+#if USE(SOUP2)
+        ASSERT_NOT_REACHED();
+#else
         soup_message_set_tls_client_certificate(m_soupMessage.get(), credential.certificate());
+#endif
         break;
     case ProtectionSpace::AuthenticationScheme::ServerTrustEvaluationRequested:
     case ProtectionSpace::AuthenticationScheme::Unknown:
@@ -591,10 +708,18 @@ void NetworkDataTaskSoup::cancelAuthenti
         soup_auth_cancel(challenge.soupAuth());
         break;
     case ProtectionSpace::AuthenticationScheme::ClientCertificatePINRequested:
+#if USE(SOUP2)
+        ASSERT_NOT_REACHED();
+#else
         soup_message_tls_client_certificate_password_request_complete(m_soupMessage.get());
+#endif
         break;
     case ProtectionSpace::AuthenticationScheme::ClientCertificateRequested:
+#if USE(SOUP2)
+        ASSERT_NOT_REACHED();
+#else
         soup_message_set_tls_client_certificate(m_soupMessage.get(), nullptr);
+#endif
         break;
     case ProtectionSpace::AuthenticationScheme::ServerTrustEvaluationRequested:
     case ProtectionSpace::AuthenticationScheme::Unknown:
@@ -629,6 +754,10 @@ void NetworkDataTaskSoup::authenticate(A
         }
     }
 
+#if USE(SOUP2)
+    soup_session_pause_message(static_cast<NetworkSessionSoup&>(*m_session).soupSession(), challenge.soupMessage());
+#endif
+
     // We could also do this before we even start the request, but that would be at the expense
     // of all request latency, versus a one-time latency for the small subset of requests that
     // use HTTP authentication. In the end, this doesn't matter much, because persistent credentials
@@ -683,6 +812,10 @@ void NetworkDataTaskSoup::continueAuthen
             completeAuthentication(challenge, credential);
         } else
             cancelAuthentication(challenge);
+
+#if USE(SOUP2)
+        soup_session_unpause_message(static_cast<NetworkSessionSoup&>(*m_session).soupSession(), challenge.soupMessage());
+#endif
     });
 }
 
@@ -769,7 +902,11 @@ void NetworkDataTaskSoup::continueHTTPRe
 
     static const unsigned maxRedirects = 20;
     if (m_currentRequest.redirectCount() > maxRedirects) {
+#if USE(SOUP2)
+        didFail(ResourceError::transportError(m_currentRequest.url(), SOUP_STATUS_TOO_MANY_REDIRECTS, "Too many redirects"_s));
+#else
         didFail(ResourceError(String::fromLatin1(g_quark_to_string(SOUP_SESSION_ERROR)), SOUP_SESSION_ERROR_TOO_MANY_REDIRECTS, m_currentRequest.url(), String::fromUTF8("Too many redirects")));
+#endif
         return;
     }
 
@@ -847,8 +984,10 @@ void NetworkDataTaskSoup::continueHTTPRe
         auto request = newRequest;
         if (request.url().protocolIsInHTTPFamily()) {
             m_networkLoadMetrics.fetchStart = { };
+#if !USE(SOUP2)
             m_networkLoadMetrics.responseEnd = { };
             m_networkLoadMetrics.complete = false;
+#endif
             applyAuthenticationToRequest(request);
 
             if (!request.hasHTTPHeaderField(HTTPHeaderName::UserAgent))
@@ -1022,13 +1161,16 @@ static AtomString soupHTTPVersionToStrin
         return "http/1.0"_s;
     case SOUP_HTTP_1_1:
         return "http/1.1"_s;
+#if SOUP_CHECK_VERSION(2, 99, 3)
     case SOUP_HTTP_2_0:
         return "h2"_s;
+#endif
     }
 
     return { };
 }
 
+#if !USE(SOUP2)
 static String tlsProtocolVersionToString(GTlsProtocolVersion version)
 {
     switch (version) {
@@ -1052,6 +1194,7 @@ static String tlsProtocolVersionToString
 
     return { };
 }
+#endif
 
 WebCore::AdditionalNetworkLoadMetricsForWebInspector& NetworkDataTaskSoup::additionalNetworkLoadMetricsForWebInspector()
 {
@@ -1060,6 +1203,15 @@ WebCore::AdditionalNetworkLoadMetricsFor
     return *m_networkLoadMetrics.additionalNetworkLoadMetricsForWebInspector;
 }
 
+#if USE(SOUP2)
+static void addHeaderSizes(const char *name, const char *value, gpointer pointer)
+{
+    uint64_t* size = static_cast<uint64_t*>(pointer);
+    // Each header is formatted as "<name>: <value>\r\n"
+    *size += strlen(name) + strlen(value) + 4;
+}
+#endif
+
 void NetworkDataTaskSoup::didGetHeaders()
 {
     // We are a bit more conservative with the persistent credential storage than the session store,
@@ -1073,6 +1225,7 @@ void NetworkDataTaskSoup::didGetHeaders(
         m_credentialForPersistentStorage = Credential();
     }
 
+#if !USE(SOUP2)
     auto* metrics = soup_message_get_metrics(m_soupMessage.get());
     auto responseStart = Seconds::fromMicroseconds(soup_message_metrics_get_response_start(metrics));
     auto responseStartTime = MonotonicTime::fromRawSeconds(responseStart.seconds());
@@ -1090,6 +1243,7 @@ void NetworkDataTaskSoup::didGetHeaders(
     }
 
     m_networkLoadMetrics.responseStart = responseStartTime;
+#endif
 
     // Soup adds more headers to the request after starting signal is emitted, and got-headers
     // is the first one we receive after starting, so we use it also to get information about the
@@ -1107,6 +1261,7 @@ void NetworkDataTaskSoup::didGetHeaders(
         additionalMetrics.requestHeaders = WTF::move(requestHeaders);
 
         additionalMetrics.priority = toNetworkLoadPriority(soup_message_get_priority(m_soupMessage.get()));
+#if !USE(SOUP2)
         additionalMetrics.connectionIdentifier = String::number(soup_message_get_connection_id(m_soupMessage.get()));
         auto* address = soup_message_get_remote_address(m_soupMessage.get());
         if (G_IS_INET_SOCKET_ADDRESS(address)) {
@@ -1116,11 +1271,27 @@ void NetworkDataTaskSoup::didGetHeaders(
         additionalMetrics.tlsProtocol = tlsProtocolVersionToString(soup_message_get_tls_protocol_version(m_soupMessage.get()));
         additionalMetrics.tlsCipher = String::fromUTF8(soup_message_get_tls_ciphersuite_name(m_soupMessage.get()));
         additionalMetrics.responseHeaderBytesReceived = soup_message_metrics_get_response_header_bytes_received(metrics);
+#else
+        {
+            auto* requestHeaders = soup_message_get_request_headers(m_soupMessage.get());
+            uint64_t requestHeadersSize = 0;
+            soup_message_headers_foreach(requestHeaders, addHeaderSizes, &requestHeadersSize);
+            additionalMetrics.requestHeaderBytesSent = requestHeadersSize;
+        }
+
+        {
+            auto* responseHeaders = soup_message_get_response_headers(m_soupMessage.get());
+            uint64_t responseHeadersSize = 0;
+            soup_message_headers_foreach(responseHeaders, addHeaderSizes, &responseHeadersSize);
+            additionalMetrics.responseHeaderBytesReceived = responseHeadersSize;
+        }
+#endif
     }
 
     m_networkLoadMetrics.protocol = soupHTTPVersionToString(soup_message_get_http_version(m_soupMessage.get()));
 }
 
+#if !USE(SOUP2)
 void NetworkDataTaskSoup::wroteHeadersCallback(SoupMessage* soupMessage, NetworkDataTaskSoup* task)
 {
     if (task->state() == State::Canceling || task->state() == State::Completed || !task->m_client) {
@@ -1176,22 +1347,35 @@ gboolean NetworkDataTaskSoup::requestCer
     task->authenticate(AuthenticationChallenge(soupMessage, tlsPassword));
     return TRUE;
 }
+#endif
 
+#if USE(SOUP2)
+void NetworkDataTaskSoup::wroteBodyDataCallback(SoupMessage* soupMessage, SoupBuffer* buffer, NetworkDataTaskSoup* task)
+#else
 void NetworkDataTaskSoup::wroteBodyDataCallback(SoupMessage* soupMessage, unsigned length, NetworkDataTaskSoup* task)
+#endif
 {
     if (task->state() == State::Canceling || task->state() == State::Completed || !task->m_client) {
         task->clearRequest();
         return;
     }
     ASSERT(task->m_soupMessage.get() == soupMessage);
+#if USE(SOUP2)
+    task->didWriteBodyData(buffer->length);
+#else
     task->didWriteBodyData(length);
+#endif
 }
 
 void NetworkDataTaskSoup::didWriteBodyData(uint64_t bytesSent)
 {
     RefPtr<NetworkDataTaskSoup> protectedThis(this);
     m_bodyDataTotalBytesSent += bytesSent;
+#if USE(SOUP2)
+    m_client->didSendData(m_bodyDataTotalBytesSent, m_soupMessage->request_body->length);
+#else
     m_client->didSendData(m_bodyDataTotalBytesSent, soup_message_headers_get_content_length(soup_message_get_request_headers(m_soupMessage.get())));
+#endif
 }
 
 void NetworkDataTaskSoup::download()
@@ -1334,6 +1518,62 @@ void NetworkDataTaskSoup::didFail(const
     dispatchDidCompleteWithError(error);
 }
 
+#if USE(SOUP2)
+void NetworkDataTaskSoup::networkEventCallback(SoupMessage* soupMessage, GSocketClientEvent event, GIOStream* stream, NetworkDataTaskSoup* task)
+{
+    if (task->state() == State::Canceling || task->state() == State::Completed || !task->m_client)
+        return;
+
+    ASSERT(task->m_soupMessage.get() == soupMessage);
+    task->networkEvent(event, stream);
+}
+
+void NetworkDataTaskSoup::networkEvent(GSocketClientEvent event, GIOStream* stream)
+{
+    auto time = MonotonicTime::now();
+    switch (event) {
+    case G_SOCKET_CLIENT_RESOLVING:
+        m_networkLoadMetrics.domainLookupStart = time;
+        break;
+    case G_SOCKET_CLIENT_RESOLVED:
+        m_networkLoadMetrics.domainLookupEnd = time;
+        break;
+    case G_SOCKET_CLIENT_CONNECTING:
+        m_networkLoadMetrics.connectStart = time;
+        break;
+    case G_SOCKET_CLIENT_CONNECTED:
+        if (shouldCaptureExtraNetworkLoadMetrics() && G_IS_SOCKET_CONNECTION(stream)) {
+            GRefPtr<GSocketAddress> address = adoptGRef(g_socket_connection_get_remote_address(G_SOCKET_CONNECTION(stream), nullptr));
+            if (G_IS_INET_SOCKET_ADDRESS(address.get())) {
+                GUniquePtr<char> ipAddress(g_inet_address_to_string(g_inet_socket_address_get_address(G_INET_SOCKET_ADDRESS(address.get()))));
+                additionalNetworkLoadMetricsForWebInspector().remoteAddress = makeString(unsafeSpan(ipAddress.get()), ':', g_inet_socket_address_get_port(G_INET_SOCKET_ADDRESS(address.get())));
+            }
+        }
+        // Web Timing considers that connection time involves dns, proxy & TLS negotiation...
+        // so we better pick G_SOCKET_CLIENT_COMPLETE for connectEnd.
+        break;
+    case G_SOCKET_CLIENT_PROXY_NEGOTIATING:
+        break;
+    case G_SOCKET_CLIENT_PROXY_NEGOTIATED:
+        break;
+    case G_SOCKET_CLIENT_TLS_HANDSHAKING:
+        m_networkLoadMetrics.secureConnectionStart = time;
+        RELEASE_ASSERT(G_IS_TLS_CONNECTION(stream));
+        g_object_set_data(G_OBJECT(stream), "wk-soup-message", m_soupMessage.get());
+        g_signal_connect(stream, "accept-certificate", G_CALLBACK(tlsConnectionAcceptCertificateCallback), this);
+        break;
+    case G_SOCKET_CLIENT_TLS_HANDSHAKED:
+        break;
+    case G_SOCKET_CLIENT_COMPLETE:
+        m_networkLoadMetrics.connectEnd = time;
+        break;
+    default:
+        ASSERT_NOT_REACHED();
+        break;
+    }
+}
+#endif
+
 void NetworkDataTaskSoup::startingCallback(SoupMessage* soupMessage, NetworkDataTaskSoup* task)
 {
     if (task->state() == State::Canceling || task->state() == State::Completed || !task->m_client)
@@ -1343,6 +1583,8 @@ void NetworkDataTaskSoup::startingCallba
     task->didStartRequest();
 }
 
+#if SOUP_CHECK_VERSION(2, 67, 1)
+
 bool NetworkDataTaskSoup::shouldAllowHSTSPolicySetting() const
 {
     // Follow Apple's HSTS abuse mitigation 1:
@@ -1366,7 +1608,11 @@ void NetworkDataTaskSoup::protocolUpgrad
     continueHTTPRedirection();
 }
 
+#if USE(SOUP2)
+void NetworkDataTaskSoup::hstsEnforced(SoupHSTSEnforcer*, SoupMessage* soupMessage, NetworkDataTaskSoup* task)
+#else
 void NetworkDataTaskSoup::hstsEnforced(SoupMessage* soupMessage, NetworkDataTaskSoup* task)
+#endif
 {
     if (task->state() == State::Canceling || task->state() == State::Completed || !task->m_client) {
         task->clearRequest();
@@ -1377,8 +1623,15 @@ void NetworkDataTaskSoup::hstsEnforced(S
         task->protocolUpgradedViaHSTS(soupMessage);
 }
 
+#endif
+
 void NetworkDataTaskSoup::didStartRequest()
 {
+#if USE(SOUP2)
+    m_networkLoadMetrics.requestStart = MonotonicTime::now();
+    if (!m_networkLoadMetrics.secureConnectionStart && m_currentRequest.url().protocolIs("https"_s))
+        m_networkLoadMetrics.secureConnectionStart = WebCore::reusedTLSConnectionSentinel;
+#else
     auto* metrics = soup_message_get_metrics(m_soupMessage.get());
     auto domainLookupStart = Seconds::fromMicroseconds(soup_message_metrics_get_dns_start(metrics));
     auto domainLookupEnd = Seconds::fromMicroseconds(soup_message_metrics_get_dns_end(metrics));
@@ -1396,6 +1649,7 @@ void NetworkDataTaskSoup::didStartReques
     else
         m_networkLoadMetrics.secureConnectionStart = MonotonicTime::fromRawSeconds(secureConnectionStart.seconds());
     m_networkLoadMetrics.requestStart = MonotonicTime::fromRawSeconds(requestStart.seconds());
+#endif
 }
 
 void NetworkDataTaskSoup::restartedCallback(SoupMessage* soupMessage, NetworkDataTaskSoup* task)
@@ -1412,9 +1666,13 @@ void NetworkDataTaskSoup::restartedCallb
 void NetworkDataTaskSoup::didRestart()
 {
     m_networkLoadMetrics = NetworkLoadMetrics::emptyMetrics();
+#if USE(SOUP2)
+    m_networkLoadMetrics.fetchStart = MonotonicTime::now();
+#else
     auto* metrics = soup_message_get_metrics(m_soupMessage.get());
     m_networkLoadMetrics.fetchStart = MonotonicTime::fromRawSeconds(Seconds::fromMicroseconds(soup_message_metrics_get_fetch_start(metrics)).seconds());
     m_currentRequest.updateSoupMessageBody(m_soupMessage.get(), m_session->blobRegistry());
+#endif
     m_networkLoadMetrics.redirectStart = m_networkLoadMetrics.fetchStart;
 }
 
diff -urpN webkitgtk-2.51.90.orig/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.h webkitgtk-2.51.90/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.h
--- webkitgtk-2.51.90.orig/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.h	2026-01-23 02:35:26.335345700 -0600
+++ webkitgtk-2.51.90/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.h	2026-01-24 09:48:37.069305410 -0600
@@ -79,9 +79,15 @@ private:
     void dispatchDidReceiveResponse();
     void dispatchDidCompleteWithError(const WebCore::ResourceError&);
 
+#if !USE(SOUP2)
     static void preconnectCallback(SoupSession*, GAsyncResult*, NetworkDataTaskSoup*);
+#endif
 
+#if USE(SOUP2)
+    static gboolean tlsConnectionAcceptCertificateCallback(GTlsConnection*, GTlsCertificate*, GTlsCertificateFlags, NetworkDataTaskSoup*);
+#else
     static gboolean acceptCertificateCallback(SoupMessage*, GTlsCertificate*, GTlsCertificateFlags, NetworkDataTaskSoup*);
+#endif
     bool acceptCertificate(GTlsCertificate*, GTlsCertificateFlags);
 
     static void didSniffContentCallback(SoupMessage*, const char* contentType, GHashTable* parameters, NetworkDataTaskSoup*);
@@ -89,7 +95,11 @@ private:
 
     bool persistentCredentialStorageEnabled() const;
     void applyAuthenticationToRequest(WebCore::ResourceRequest&);
+#if USE(SOUP2)
+    static void authenticateCallback(SoupSession*, SoupMessage*, SoupAuth*, gboolean retrying, NetworkDataTaskSoup*);
+#else
     static gboolean authenticateCallback(SoupMessage*, SoupAuth*, gboolean retrying, NetworkDataTaskSoup*);
+#endif
     void authenticate(WebCore::AuthenticationChallenge&&);
     void continueAuthenticate(WebCore::AuthenticationChallenge&&);
     void completeAuthentication(const WebCore::AuthenticationChallenge&, const WebCore::Credential&);
@@ -114,14 +124,20 @@ private:
     static void gotHeadersCallback(SoupMessage*, NetworkDataTaskSoup*);
     void didGetHeaders();
 
+#if USE(SOUP2)
+    static void wroteBodyDataCallback(SoupMessage*, SoupBuffer*, NetworkDataTaskSoup*);
+#else
     static void wroteBodyDataCallback(SoupMessage*, unsigned, NetworkDataTaskSoup*);
+#endif
     void didWriteBodyData(uint64_t bytesSent);
 
+#if !USE(SOUP2)
     static void wroteHeadersCallback(SoupMessage*, NetworkDataTaskSoup*);
     static void wroteBodyCallback(SoupMessage*, NetworkDataTaskSoup*);
     static void gotBodyCallback(SoupMessage*, NetworkDataTaskSoup*);
     static gboolean requestCertificateCallback(SoupMessage*, GTlsClientConnection*, NetworkDataTaskSoup*);
     static gboolean requestCertificatePasswordCallback(SoupMessage*, GTlsPassword*, NetworkDataTaskSoup*);
+#endif
 
     void download();
     static void writeDownloadCallback(GOutputStream*, GAsyncResult*, NetworkDataTaskSoup*);
@@ -133,11 +149,26 @@ private:
 
     void didFail(const WebCore::ResourceError&);
 
+#if USE(SOUP2)
+    static void networkEventCallback(SoupMessage*, GSocketClientEvent, GIOStream*, NetworkDataTaskSoup*);
+    void networkEvent(GSocketClientEvent, GIOStream*);
+#endif
+
+#if SOUP_CHECK_VERSION(2, 49, 91)
     static void startingCallback(SoupMessage*, NetworkDataTaskSoup*);
+#else
+    static void requestStartedCallback(SoupSession*, SoupMessage*, SoupSocket*, NetworkDataTaskSoup*);
+#endif
+#if SOUP_CHECK_VERSION(2, 67, 1)
     bool shouldAllowHSTSPolicySetting() const;
     bool shouldAllowHSTSProtocolUpgrade() const;
     void protocolUpgradedViaHSTS(SoupMessage*);
+#if USE(SOUP2)
+    static void hstsEnforced(SoupHSTSEnforcer*, SoupMessage*, NetworkDataTaskSoup*);
+#else
     static void hstsEnforced(SoupMessage*, NetworkDataTaskSoup*);
+#endif
+#endif
     void didStartRequest();
     static void restartedCallback(SoupMessage*, NetworkDataTaskSoup*);
     void didRestart();
diff -urpN webkitgtk-2.51.90.orig/Source/WebKit/NetworkProcess/soup/NetworkSessionSoup.cpp webkitgtk-2.51.90/Source/WebKit/NetworkProcess/soup/NetworkSessionSoup.cpp
--- webkitgtk-2.51.90.orig/Source/WebKit/NetworkProcess/soup/NetworkSessionSoup.cpp	2026-01-23 02:35:26.335345700 -0600
+++ webkitgtk-2.51.90/Source/WebKit/NetworkProcess/soup/NetworkSessionSoup.cpp	2026-01-24 09:48:37.069444864 -0600
@@ -95,9 +95,31 @@ void NetworkSessionSoup::setCookiePersis
 
 void NetworkSessionSoup::clearCredentials(WallTime)
 {
+#if SOUP_CHECK_VERSION(2, 57, 1)
     soup_auth_manager_clear_cached_credentials(SOUP_AUTH_MANAGER(soup_session_get_feature(soupSession(), SOUP_TYPE_AUTH_MANAGER)));
+#endif
 }
 
+#if USE(SOUP2)
+static gboolean webSocketAcceptCertificateCallback(GTlsConnection* connection, GTlsCertificate* certificate, GTlsCertificateFlags errors, NetworkSessionSoup* session)
+{
+    if (DeprecatedGlobalSettings::allowsAnySSLCertificate())
+        return TRUE;
+
+    auto* soupMessage = static_cast<SoupMessage*>(g_object_get_data(G_OBJECT(connection), "wk-soup-message"));
+    return !session->soupNetworkSession().checkTLSErrors(soupURIToURL(soup_message_get_uri(soupMessage)), certificate, errors);
+}
+
+static void webSocketMessageNetworkEventCallback(SoupMessage* soupMessage, GSocketClientEvent event, GIOStream* connection, NetworkSessionSoup* session)
+{
+    if (event != G_SOCKET_CLIENT_TLS_HANDSHAKING)
+        return;
+
+    g_object_set_data(G_OBJECT(connection), "wk-soup-message", soupMessage);
+    g_signal_connect(connection, "accept-certificate", G_CALLBACK(webSocketAcceptCertificateCallback), session);
+}
+#endif
+
 RefPtr<WebSocketTask> NetworkSessionSoup::createWebSocketTask(WebPageProxyIdentifier webPageProxyID, std::optional<FrameIdentifier> frameID, std::optional<PageIdentifier> pageID, NetworkSocketChannel& channel, const ResourceRequest& request, const String& protocol, const ClientOrigin&, bool, bool, OptionSet<WebCore::AdvancedPrivacyProtections>, StoredCredentialsPolicy)
 {
     GRefPtr<SoupMessage> soupMessage = request.createSoupMessage(blobRegistry());
@@ -105,12 +127,16 @@ RefPtr<WebSocketTask> NetworkSessionSoup
         return nullptr;
 
     if (request.url().protocolIs("wss"_s)) {
+#if USE(SOUP2)
+        g_signal_connect(soupMessage.get(), "network-event", G_CALLBACK(webSocketMessageNetworkEventCallback), this);
+#else
         g_signal_connect(soupMessage.get(), "accept-certificate", G_CALLBACK(+[](SoupMessage* message, GTlsCertificate* certificate, GTlsCertificateFlags errors,  NetworkSessionSoup* session) -> gboolean {
             if (DeprecatedGlobalSettings::allowsAnySSLCertificate())
                 return TRUE;
 
             return !session->soupNetworkSession().checkTLSErrors(soup_message_get_uri(message), certificate, errors);
         }), this);
+#endif
     }
 
     bool shouldBlockCookies = checkedNetworkStorageSession()->shouldBlockCookies(request, frameID, pageID, networkProcess().shouldRelaxThirdPartyCookieBlockingForPage(webPageProxyID), WebCore::IsKnownCrossSiteTracker::No);
diff -urpN webkitgtk-2.51.90.orig/Source/WebKit/NetworkProcess/soup/WebSocketTaskSoup.cpp webkitgtk-2.51.90/Source/WebKit/NetworkProcess/soup/WebSocketTaskSoup.cpp
--- webkitgtk-2.51.90.orig/Source/WebKit/NetworkProcess/soup/WebSocketTaskSoup.cpp	2026-01-23 02:35:26.336075800 -0600
+++ webkitgtk-2.51.90/Source/WebKit/NetworkProcess/soup/WebSocketTaskSoup.cpp	2026-01-24 10:35:34.670312389 -0600
@@ -33,6 +33,7 @@
 #include <WebCore/HTTPParsers.h>
 #include <WebCore/ResourceRequest.h>
 #include <WebCore/ResourceResponse.h>
+#include <WebCore/SoupVersioning.h>
 #include <WebCore/ThreadableWebSocketChannel.h>
 #include <wtf/RunLoop.h>
 #include <wtf/TZoneMallocInlines.h>
@@ -43,10 +44,17 @@
 
 namespace WebKit {
 
-static inline bool isConnectionError(GError* error)
+static inline bool isConnectionError(GError* error, SoupMessage* message)
 {
+#if USE(SOUP2)
+    return g_error_matches(error, SOUP_WEBSOCKET_ERROR, SOUP_WEBSOCKET_ERROR_NOT_WEBSOCKET)
+        && message
+        && (message->status_code == SOUP_STATUS_CANT_CONNECT || message->status_code == SOUP_STATUS_CANT_CONNECT_PROXY);
+#else
+    UNUSED_PARAM(message);
     // If not a SOUP_WEBSOCKET_ERROR_NOT_WEBSOCKET, then it's a connection error.
     return error && !g_error_matches(error, SOUP_WEBSOCKET_ERROR, SOUP_WEBSOCKET_ERROR_NOT_WEBSOCKET);
+#endif
 }
 
 WTF_MAKE_TZONE_ALLOCATED_IMPL(WebSocketTask);
@@ -73,6 +81,12 @@ WebSocketTask::WebSocketTask(NetworkSock
             protocolsSpan[i++] = g_strdup(subprotocol.trim(isASCIIWhitespaceWithoutFF<char16_t>).utf8().data());
     }
 
+#if USE(SOUP2)
+    // Ensure a new connection is used for WebSockets.
+    // FIXME: this is done by libsoup since 2.69.1 and 2.68.4, so it can be removed when bumping the libsoup requirement.
+    // See https://bugs.webkit.org/show_bug.cgi?id=203404
+    soup_message_set_flags(msg, static_cast<SoupMessageFlags>(soup_message_get_flags(msg) | SOUP_MESSAGE_NEW_CONNECTION));
+#else
     {
         // No need to subscribe to the "request-certificate" signal, just set the client certificate upfront.
         auto protectionSpace = WebCore::AuthenticationChallenge::protectionSpaceForClientCertificate(WebCore::soupURIToURL(soup_message_get_uri(msg)));
@@ -87,6 +101,7 @@ WebSocketTask::WebSocketTask(NetworkSock
         soup_message_tls_client_certificate_password_request_complete(msg);
         return TRUE;
     }), this);
+#endif
 
     soup_session_websocket_connect_async(session, msg, nullptr, protocols.get(), RunLoopSourcePriority::AsyncIONetwork, m_cancellable.get(),
         [] (GObject* session, GAsyncResult* result, gpointer userData) {
@@ -95,7 +110,7 @@ WebSocketTask::WebSocketTask(NetworkSock
             if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED))
                 return;
             auto* task = static_cast<WebSocketTask*>(userData);
-            if (isConnectionError(error.get())) {
+            if (isConnectionError(error.get(), task->m_handshakeMessage.get())) {
                 task->m_delayErrorMessage = String::fromUTF8(error->message);
                 task->m_delayFailTimer.startOneShot(NetworkProcess::randomClosedPortDelay());
                 return;
@@ -127,6 +142,7 @@ RefPtr<NetworkSocketChannel> WebSocketTa
 
 String WebSocketTask::acceptedExtensions() const
 {
+#if SOUP_CHECK_VERSION(2, 67, 90)
     StringBuilder result;
     GList* extensions = soup_websocket_connection_get_extensions(m_connection.get());
     for (auto* it = extensions; it; it = g_list_next(it)) {
@@ -141,15 +157,20 @@ String WebSocketTask::acceptedExtensions
             result.append(String::fromUTF8(params.get()));
     }
     return result.toStringPreserveCapacity();
+#else
+    return { };
+#endif
 }
 
 void WebSocketTask::didConnect(GRefPtr<SoupWebsocketConnection>&& connection)
 {
     m_connection = WTF::move(connection);
 
+#if SOUP_CHECK_VERSION(2, 56, 0)
     // Use the same maximum payload length as WebKit internal implementation for backwards compatibility.
     static const uint64_t maxPayloadLength = UINT64_C(0x7FFFFFFFFFFFFFFF);
     soup_websocket_connection_set_max_incoming_payload_size(m_connection.get(), maxPayloadLength);
+#endif
 
     g_signal_connect_swapped(m_connection.get(), "message", reinterpret_cast<GCallback>(didReceiveMessageCallback), this);
     g_signal_connect_swapped(m_connection.get(), "error", reinterpret_cast<GCallback>(didReceiveErrorCallback), this);
@@ -234,9 +255,13 @@ void WebSocketTask::didClose(unsigned sh
 void WebSocketTask::sendString(std::span<const uint8_t> utf8, CompletionHandler<void()>&& callback)
 {
     if (m_connection && soup_websocket_connection_get_state(m_connection.get()) == SOUP_WEBSOCKET_STATE_OPEN) {
+#if SOUP_CHECK_VERSION(2, 67, 3)
         // Soup is going to copy the data immediately, so we can use g_bytes_new_static() here to avoid more data copies.
         GRefPtr<GBytes> bytes = adoptGRef(g_bytes_new_static(utf8.data(), utf8.size()));
         soup_websocket_connection_send_message(m_connection.get(), SOUP_WEBSOCKET_DATA_TEXT, bytes.get());
+#else
+        soup_websocket_connection_send_text(m_connection.get(), CString(utf8).data());
+#endif
     }
     callback();
 }
@@ -259,8 +284,10 @@ void WebSocketTask::close(int32_t code,
         return;
     }
 
+#if SOUP_CHECK_VERSION(2, 67, 90)
     if (code == WebCore::ThreadableWebSocketChannel::CloseEventCodeNotSpecified)
         code = SOUP_WEBSOCKET_CLOSE_NO_STATUS;
+#endif
 
     if (soup_websocket_connection_get_state(m_connection.get()) == SOUP_WEBSOCKET_STATE_OPEN)
         soup_websocket_connection_close(m_connection.get(), code, reason.utf8().data());
diff -urpN webkitgtk-2.51.90.orig/Source/WebKit/PlatformGTK.cmake webkitgtk-2.51.90/Source/WebKit/PlatformGTK.cmake
--- webkitgtk-2.51.90.orig/Source/WebKit/PlatformGTK.cmake	2026-01-23 02:35:26.361826000 -0600
+++ webkitgtk-2.51.90/Source/WebKit/PlatformGTK.cmake	2026-01-24 14:29:58.236509857 -0600
@@ -341,6 +341,7 @@ list(APPEND WebKit_PRIVATE_INCLUDE_DIREC
 list(APPEND WebKit_SYSTEM_INCLUDE_DIRECTORIES
     ${GSTREAMER_INCLUDE_DIRS}
     ${GSTREAMER_PBUTILS_INCLUDE_DIRS}
+    ${LIBSOUP_INCLUDE_DIRS}
 )
 
 list(APPEND WebKit_INTERFACE_INCLUDE_DIRECTORIES
@@ -612,7 +613,7 @@ GI_INTROSPECT(WebKit${WEBKITGTK_API_INFI
     DEPENDENCIES
         JavaScriptCore
         Gtk-${GTK_API_VERSION}.0:${GTK_PKGCONFIG_PACKAGE}
-        Soup-3.0:libsoup-3.0
+        Soup-${SOUP_API_VERSION}:libsoup-${SOUP_API_VERSION}
     SOURCES
         ${WebKitGTK_INSTALLED_HEADERS}
         ${WEBKITGTK_SOURCES_FOR_INTROSPECTION}
@@ -648,7 +649,7 @@ GI_INTROSPECT(${WEBKITGTK_WEB_PROCESS_EX
     DEPENDENCIES
         JavaScriptCore
         Gtk-${GTK_API_VERSION}.0:${GTK_PKGCONFIG_PACKAGE}
-        Soup-3.0:libsoup-3.0
+        Soup-${SOUP_API_VERSION}:libsoup-${SOUP_API_VERSION}
     SOURCES
         ${WebKitDOM_SOURCES_FOR_INTROSPECTION}
         ${WebKitWebProcessExtension_INSTALLED_HEADERS}
diff -urpN webkitgtk-2.51.90.orig/Source/WebKit/UIProcess/Inspector/glib/RemoteInspectorHTTPServer.cpp webkitgtk-2.51.90/Source/WebKit/UIProcess/Inspector/glib/RemoteInspectorHTTPServer.cpp
--- webkitgtk-2.51.90.orig/Source/WebKit/UIProcess/Inspector/glib/RemoteInspectorHTTPServer.cpp	2026-01-23 02:35:26.582229400 -0600
+++ webkitgtk-2.51.90/Source/WebKit/UIProcess/Inspector/glib/RemoteInspectorHTTPServer.cpp	2026-01-24 09:48:41.118240148 -0600
@@ -29,6 +29,7 @@
 #if ENABLE(REMOTE_INSPECTOR)
 
 #include "RemoteInspectorClient.h"
+#include <WebCore/SoupVersioning.h>
 #include <wtf/FileSystem.h>
 #include <wtf/URL.h>
 #include <wtf/glib/GSpanExtras.h>
@@ -54,14 +55,22 @@ bool RemoteInspectorHTTPServer::start(GR
     }
 
     soup_server_add_handler(m_server.get(), nullptr,
+#if USE(SOUP2)
+        [](SoupServer*, SoupMessage* message, const char* path, GHashTable*, SoupClientContext*, gpointer userData) {
+#else
         [](SoupServer*, SoupServerMessage* message, const char* path, GHashTable*, gpointer userData) {
+#endif
             auto& httpServer = *static_cast<RemoteInspectorHTTPServer*>(userData);
             auto status = httpServer.handleRequest(path, soup_server_message_get_response_headers(message), soup_server_message_get_response_body(message));
             soup_server_message_set_status(message, status, nullptr);
         }, this, nullptr);
 
     soup_server_add_websocket_handler(m_server.get(), "/socket", nullptr, nullptr,
+#if USE(SOUP2)
+        [](SoupServer*, SoupWebsocketConnection* connection, const char* path, SoupClientContext*, gpointer userData) {
+#else
         [](SoupServer*, SoupServerMessage*, const char* path, SoupWebsocketConnection* connection, gpointer userData) {
+#endif
             auto& httpServer = *static_cast<RemoteInspectorHTTPServer*>(userData);
             httpServer.handleWebSocket(path, connection);
         }, this, nullptr);
@@ -144,8 +153,12 @@ void RemoteInspectorHTTPServer::sendMess
 
     auto utf8 = message.utf8();
     // Soup is going to copy the data immediately, so we can use g_bytes_new_static() here to avoid more data copies.
+#if SOUP_CHECK_VERSION(2, 67, 3)
     GRefPtr<GBytes> bytes = adoptGRef(g_bytes_new_static(utf8.data(), utf8.length()));
     soup_websocket_connection_send_message(webSocketConnection, SOUP_WEBSOCKET_DATA_TEXT, bytes.get());
+#else
+    soup_websocket_connection_send_text(webSocketConnection, CString(utf8).data());
+#endif
 }
 
 void RemoteInspectorHTTPServer::targetDidClose(uint64_t connectionID, uint64_t targetID)
diff -urpN webkitgtk-2.51.90.orig/Source/WebKit/WebProcess/InjectedBundle/API/gtk/DOM/WebKitDOMComment.cpp webkitgtk-2.51.90/Source/WebKit/WebProcess/InjectedBundle/API/gtk/DOM/WebKitDOMComment.cpp
--- webkitgtk-2.51.90.orig/Source/WebKit/WebProcess/InjectedBundle/API/gtk/DOM/WebKitDOMComment.cpp	2026-01-23 02:35:26.727445000 -0600
+++ webkitgtk-2.51.90/Source/WebKit/WebProcess/InjectedBundle/API/gtk/DOM/WebKitDOMComment.cpp	2026-01-24 09:48:41.118524206 -0600
@@ -24,7 +24,6 @@
 #include "DOMObjectCache.h"
 #include <WebCore/DOMException.h>
 #include <WebCore/Document.h>
-#include <WebCore/ShadowRoot.h>
 #include "GObjectEventListener.h"
 #include <WebCore/JSExecState.h>
 #include "WebKitDOMCommentPrivate.h"
diff -urpN webkitgtk-2.51.90.orig/Source/WebKit/WebProcess/InjectedBundle/API/gtk/DOM/WebKitDOMDocumentType.cpp webkitgtk-2.51.90/Source/WebKit/WebProcess/InjectedBundle/API/gtk/DOM/WebKitDOMDocumentType.cpp
--- webkitgtk-2.51.90.orig/Source/WebKit/WebProcess/InjectedBundle/API/gtk/DOM/WebKitDOMDocumentType.cpp	2026-01-23 02:35:26.727445000 -0600
+++ webkitgtk-2.51.90/Source/WebKit/WebProcess/InjectedBundle/API/gtk/DOM/WebKitDOMDocumentType.cpp	2026-01-24 09:48:41.118768489 -0600
@@ -24,7 +24,6 @@
 #include "DOMObjectCache.h"
 #include <WebCore/DOMException.h>
 #include <WebCore/Document.h>
-#include <WebCore/EventTargetInlines.h>
 #include "GObjectEventListener.h"
 #include <WebCore/JSExecState.h>
 #include "WebKitDOMDocumentTypePrivate.h"
diff -urpN webkitgtk-2.51.90.orig/Source/WTF/wtf/PlatformEnableGlib.h webkitgtk-2.51.90/Source/WTF/wtf/PlatformEnableGlib.h
--- webkitgtk-2.51.90.orig/Source/WTF/wtf/PlatformEnableGlib.h	2026-01-23 02:35:24.927470200 -0600
+++ webkitgtk-2.51.90/Source/WTF/wtf/PlatformEnableGlib.h	2026-01-24 09:48:37.065220930 -0600
@@ -55,10 +55,6 @@
 #define ENABLE_OPENTYPE_VERTICAL 1
 #endif
 
-#if !defined(ENABLE_SERVER_PRECONNECT)
-#define ENABLE_SERVER_PRECONNECT 1
-#endif
-
 #if !defined(ENABLE_SCROLLING_THREAD) && USE(COORDINATED_GRAPHICS)
 #define ENABLE_SCROLLING_THREAD 1
 #endif
diff -urpN webkitgtk-2.51.90.orig/Source/WTF/wtf/Platform.h webkitgtk-2.51.90/Source/WTF/wtf/Platform.h
--- webkitgtk-2.51.90.orig/Source/WTF/wtf/Platform.h	2026-01-23 02:35:24.927470200 -0600
+++ webkitgtk-2.51.90/Source/WTF/wtf/Platform.h	2026-01-24 09:48:37.064998258 -0600
@@ -104,8 +104,12 @@
 #endif
 
 #if USE(SOUP)
+#if USE(SOUP2)
+#define SOUP_VERSION_MIN_REQUIRED SOUP_VERSION_2_54
+#else
 #define SOUP_VERSION_MIN_REQUIRED SOUP_VERSION_3_0
 #endif
+#endif
 
 #if PLATFORM(COCOA)
 /* Cocoa defines a series of platform macros for debugging. */
diff -urpN webkitgtk-2.51.90.orig/Tools/MiniBrowser/gtk/CMakeLists.txt webkitgtk-2.51.90/Tools/MiniBrowser/gtk/CMakeLists.txt
--- webkitgtk-2.51.90.orig/Tools/MiniBrowser/gtk/CMakeLists.txt	2026-01-23 02:35:26.955072000 -0600
+++ webkitgtk-2.51.90/Tools/MiniBrowser/gtk/CMakeLists.txt	2026-01-24 17:29:47.909069023 -0600
@@ -26,8 +26,13 @@ set(MiniBrowser_PRIVATE_INCLUDE_DIRECTOR
     ${CMAKE_SOURCE_DIR}/Source
 )
 
+set(MiniBrowser_SYSTEM_INCLUDE_DIRECTORIES
+    ${LIBSOUP_INCLUDE_DIRS}
+)
+
 set(MiniBrowser_PRIVATE_LIBRARIES
     ${JavaScriptCore_LIBRARY_NAME}
+    ${LIBSOUP_LIBRARIES}
     GTK::GTK
     WebKit::WebKit
 )
openSUSE Build Service is sponsored by