Merge branch 'release-3.25'
diff --git a/.clang-tidy b/.clang-tidy
index a86f39a..1e9b78a 100644
--- a/.clang-tidy
+++ b/.clang-tidy
@@ -33,6 +33,7 @@
 -readability-redundant-member-init,\
 -readability-suspicious-call-argument,\
 -readability-uppercase-literal-suffix,\
+cmake-*,\
 "
 HeaderFilterRegex: 'Source/cm[^/]*\.(h|hxx|cxx)$'
 CheckOptions:
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 0e5824d..7f732a0 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1060,6 +1060,34 @@
         CMAKE_CI_BUILD_NAME: windows_clang13.0_gnu_nmake
         CMAKE_CI_JOB_NIGHTLY: "true"
 
+t:mingw_osdn_io-mingw_makefiles:
+    extends:
+        - .mingw_osdn_io_mingw_makefiles
+        - .cmake_test_windows_external
+        - .windows_tags_concurrent
+        - .cmake_junit_artifacts
+        - .run_dependent
+    dependencies:
+        - t:windows-vs2022-x64-ninja
+    needs:
+        - t:windows-vs2022-x64-ninja
+    variables:
+        CMAKE_CI_JOB_NIGHTLY: "true"
+
+t:mingw_osdn_io-msys_makefiles:
+    extends:
+        - .mingw_osdn_io_msys_makefiles
+        - .cmake_test_windows_external
+        - .windows_tags_concurrent
+        - .cmake_junit_artifacts
+        - .run_dependent
+    dependencies:
+        - t:windows-vs2022-x64-ninja
+    needs:
+        - t:windows-vs2022-x64-ninja
+    variables:
+        CMAKE_CI_JOB_NIGHTLY: "true"
+
 t:windows-msvc-v71-nmake:
     extends:
         - .windows_msvc_v71_nmake
diff --git a/.gitlab/.gitignore b/.gitlab/.gitignore
index d62e477..4988351 100644
--- a/.gitlab/.gitignore
+++ b/.gitlab/.gitignore
@@ -5,6 +5,7 @@
 /ispc*
 /jom
 /llvm*
+/mingw
 /msvc*
 /ninja*
 /open-watcom*
diff --git a/.gitlab/ci/configure_fedora36_tidy.cmake b/.gitlab/ci/configure_fedora36_tidy.cmake
index 38414d3..2d0eeeb 100644
--- a/.gitlab/ci/configure_fedora36_tidy.cmake
+++ b/.gitlab/ci/configure_fedora36_tidy.cmake
@@ -1,3 +1,5 @@
 set(CMake_RUN_CLANG_TIDY ON CACHE BOOL "")
+set(CMake_USE_CLANG_TIDY_MODULE ON CACHE BOOL "")
+set(CMake_CLANG_TIDY_MODULE "$ENV{CI_PROJECT_DIR}/Utilities/ClangTidyModule/build/libcmake-clang-tidy-module.so" CACHE FILEPATH "")
 
 include("${CMAKE_CURRENT_LIST_DIR}/configure_fedora36_common.cmake")
diff --git a/.gitlab/ci/configure_mingw_osdn_io_common.cmake b/.gitlab/ci/configure_mingw_osdn_io_common.cmake
new file mode 100644
index 0000000..55dce1d
--- /dev/null
+++ b/.gitlab/ci/configure_mingw_osdn_io_common.cmake
@@ -0,0 +1,5 @@
+set(CMake_TEST_Java OFF CACHE BOOL "")
+
+set(configure_no_sccache 1)
+
+include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")
diff --git a/.gitlab/ci/configure_mingw_osdn_io_mingw_makefiles.cmake b/.gitlab/ci/configure_mingw_osdn_io_mingw_makefiles.cmake
new file mode 100644
index 0000000..5ddd410
--- /dev/null
+++ b/.gitlab/ci/configure_mingw_osdn_io_mingw_makefiles.cmake
@@ -0,0 +1 @@
+include("${CMAKE_CURRENT_LIST_DIR}/configure_mingw_osdn_io_common.cmake")
diff --git a/.gitlab/ci/configure_mingw_osdn_io_msys_makefiles.cmake b/.gitlab/ci/configure_mingw_osdn_io_msys_makefiles.cmake
new file mode 100644
index 0000000..5ddd410
--- /dev/null
+++ b/.gitlab/ci/configure_mingw_osdn_io_msys_makefiles.cmake
@@ -0,0 +1 @@
+include("${CMAKE_CURRENT_LIST_DIR}/configure_mingw_osdn_io_common.cmake")
diff --git a/.gitlab/ci/env_fedora36_tidy.sh b/.gitlab/ci/env_fedora36_tidy.sh
new file mode 100644
index 0000000..f9f08a3
--- /dev/null
+++ b/.gitlab/ci/env_fedora36_tidy.sh
@@ -0,0 +1,7 @@
+cmake \
+  -S Utilities/ClangTidyModule \
+  -B Utilities/ClangTidyModule/build \
+  -DCMAKE_BUILD_TYPE=Release \
+  -DRUN_TESTS=ON
+cmake --build Utilities/ClangTidyModule/build
+ctest --test-dir Utilities/ClangTidyModule/build --output-on-failure
diff --git a/.gitlab/ci/env_mingw_osdn_io_mingw_makefiles.ps1 b/.gitlab/ci/env_mingw_osdn_io_mingw_makefiles.ps1
new file mode 100755
index 0000000..e2d573e
--- /dev/null
+++ b/.gitlab/ci/env_mingw_osdn_io_mingw_makefiles.ps1
@@ -0,0 +1,3 @@
+$pwdpath = $pwd.Path
+& "$pwsh" -File ".gitlab/ci/mingw.ps1"
+Set-Item -Force -Path "env:PATH" -Value "$pwdpath\.gitlab\mingw\bin;$env:PATH"
diff --git a/.gitlab/ci/env_mingw_osdn_io_msys_makefiles.ps1 b/.gitlab/ci/env_mingw_osdn_io_msys_makefiles.ps1
new file mode 100755
index 0000000..6eccb72
--- /dev/null
+++ b/.gitlab/ci/env_mingw_osdn_io_msys_makefiles.ps1
@@ -0,0 +1,5 @@
+$pwdpath = $pwd.Path
+& "$pwsh" -File ".gitlab/ci/mingw.ps1"
+Set-Item -Force -Path "env:PATH" -Value "$pwdpath\.gitlab\mingw\msys\1.0\bin;$pwdpath\.gitlab\mingw\bin;$env:PATH"
+$env:MSYSTEM = 'MINGW32'
+$env:MAKE_MODE = 'unix'
diff --git a/.gitlab/ci/mingw.ps1 b/.gitlab/ci/mingw.ps1
new file mode 100755
index 0000000..a1b5b11
--- /dev/null
+++ b/.gitlab/ci/mingw.ps1
@@ -0,0 +1,25 @@
+$erroractionpreference = "stop"
+
+if ("$env:CMAKE_CONFIGURATION".Contains("mingw_osdn_io")) {
+    $filename = "mingw.osdn.io-2022-10-03"
+    $sha256sum = "4DCB8C351D8D855F7D3DFC2863A235042BF3DB6E69EA0BAE51FF9378189345CD"
+} else {
+    throw ('unknown CMAKE_CONFIGURATION: ' + "$env:CMAKE_CONFIGURATION")
+}
+$tarball = "$filename.zip"
+
+$outdir = $pwd.Path
+$outdir = "$outdir\.gitlab"
+$ProgressPreference = 'SilentlyContinue'
+Invoke-WebRequest -Uri "https://cmake.org/files/dependencies/$tarball" -OutFile "$outdir\$tarball"
+$hash = Get-FileHash "$outdir\$tarball" -Algorithm SHA256
+if ($hash.Hash -ne $sha256sum) {
+    exit 1
+}
+
+Add-Type -AssemblyName System.IO.Compression.FileSystem
+[System.IO.Compression.ZipFile]::ExtractToDirectory("$outdir\$tarball", "$outdir")
+Move-Item -Path "$outdir\$filename" -Destination "$outdir\mingw"
+Remove-Item "$outdir\$tarball"
+
+"$outdir/mingw /mingw" -replace '\\', '/' | Out-File -FilePath "$outdir\mingw\msys\1.0\etc\fstab" -Encoding ASCII
diff --git a/.gitlab/os-windows.yml b/.gitlab/os-windows.yml
index 5c6be11..271610b 100644
--- a/.gitlab/os-windows.yml
+++ b/.gitlab/os-windows.yml
@@ -236,6 +236,29 @@
     variables:
         CMAKE_CONFIGURATION: windows_openwatcom1.9
 
+.mingw_osdn_io:
+    extends: .windows
+
+    variables:
+        # Place MinGW environment in a path without spaces.
+        GIT_CLONE_PATH: "$CI_BUILDS_DIR\\cmake-ci-ext\\$CI_CONCURRENT_ID"
+        CMAKE_CI_BUILD_TYPE: Debug
+        CMAKE_CI_NIGHTLY_IGNORE_DEPS: "true"
+
+.mingw_osdn_io_mingw_makefiles:
+    extends: .mingw_osdn_io
+
+    variables:
+        CMAKE_CONFIGURATION: mingw_osdn_io_mingw_makefiles
+        CMAKE_GENERATOR: "MinGW Makefiles"
+
+.mingw_osdn_io_msys_makefiles:
+    extends: .mingw_osdn_io
+
+    variables:
+        CMAKE_CONFIGURATION: mingw_osdn_io_msys_makefiles
+        CMAKE_GENERATOR: "MSYS Makefiles"
+
 ## Tags
 
 .windows_tags_nonconcurrent_vs2022:
diff --git a/Auxiliary/vim/syntax/cmake.vim b/Auxiliary/vim/syntax/cmake.vim
index 9eb993a..5e936c2 100644
--- a/Auxiliary/vim/syntax/cmake.vim
+++ b/Auxiliary/vim/syntax/cmake.vim
@@ -2013,6 +2013,7 @@
             \ IGNORED
             \ INACTIVITY_TIMEOUT
             \ INDEPENDENT_STEP_TARGETS
+            \ INSTALL_BYPRODUCTS
             \ INSTALL_COMMAND
             \ INSTALL_DIR
             \ JOB_POOLS
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2b9eb2d..73c2c2e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,14 +1,10 @@
 # Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
 # file Copyright.txt or https://cmake.org/licensing for details.
 
-cmake_minimum_required(VERSION 3.13...3.23 FATAL_ERROR)
+cmake_minimum_required(VERSION 3.13...3.24 FATAL_ERROR)
 set(CMAKE_USER_MAKE_RULES_OVERRIDE_C ${CMAKE_CURRENT_SOURCE_DIR}/Source/Modules/OverrideC.cmake)
 set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX ${CMAKE_CURRENT_SOURCE_DIR}/Source/Modules/OverrideCXX.cmake)
 
-if(POLICY CMP0129)
-  cmake_policy(SET CMP0129 NEW) # CMake 3.23
-endif()
-
 project(CMake)
 unset(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX)
 unset(CMAKE_USER_MAKE_RULES_OVERRIDE_C)
@@ -277,6 +273,16 @@
   endif()
   set(CMAKE_CXX_CLANG_TIDY "${CLANG_TIDY_COMMAND}")
 
+  option(CMake_USE_CLANG_TIDY_MODULE "Use CMake's clang-tidy module." OFF)
+  if(CMake_USE_CLANG_TIDY_MODULE)
+    find_library(CMake_CLANG_TIDY_MODULE NAMES cmake-clang-tidy-module DOC "Location of the clang-tidy module")
+    if(NOT CMake_CLANG_TIDY_MODULE)
+      message(FATAL_ERROR "CMake_USE_CLANG_TIDY_MODULE is ON but cmake-clang-tidy-module is not found!")
+    endif()
+    list(APPEND CMAKE_CXX_CLANG_TIDY "--load=${CMake_CLANG_TIDY_MODULE}")
+    set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${CMake_CLANG_TIDY_MODULE}")
+  endif()
+
   # Create a preprocessor definition that depends on .clang-tidy content so
   # the compile command will change when .clang-tidy changes.  This ensures
   # that a subsequent build re-runs clang-tidy on all sources even if they
@@ -286,6 +292,11 @@
   file(SHA1 ${CMAKE_CURRENT_SOURCE_DIR}/.clang-tidy clang_tidy_sha1)
   set(CLANG_TIDY_DEFINITIONS "CLANG_TIDY_SHA1=${clang_tidy_sha1}")
   unset(clang_tidy_sha1)
+  if(CMake_USE_CLANG_TIDY_MODULE)
+    file(SHA1 "${CMake_CLANG_TIDY_MODULE}" clang_tidy_module_sha1)
+    list(APPEND CLANG_TIDY_DEFINITIONS "CLANG_TIDY_MODULE_SHA1=${clang_tidy_module_sha1}")
+    unset(clang_tidy_module_sha1)
+  endif()
 
 endif()
 configure_file(.clang-tidy .clang-tidy COPYONLY)
diff --git a/Help/command/string.rst b/Help/command/string.rst
index 86cbd2e..217157c 100644
--- a/Help/command/string.rst
+++ b/Help/command/string.rst
@@ -522,6 +522,17 @@
 ``%Y``
   The current year.
 
+``%z``
+  .. versionadded:: 3.26
+
+  The offset of the time zone from UTC, in hours and minutes,
+  with format ``+hhmm`` or ``-hhmm``.
+
+``%Z``
+  .. versionadded:: 3.26
+
+  The time zone name.
+
 Unknown format specifiers will be ignored and copied to the output
 as-is.
 
diff --git a/Help/guide/tutorial/Adding Support for a Testing Dashboard.rst b/Help/guide/tutorial/Adding Support for a Testing Dashboard.rst
index 45d5976..787e777 100644
--- a/Help/guide/tutorial/Adding Support for a Testing Dashboard.rst
+++ b/Help/guide/tutorial/Adding Support for a Testing Dashboard.rst
@@ -4,33 +4,40 @@
 Adding support for submitting our test results to a dashboard is simple. We
 already defined a number of tests for our project in
 :ref:`Testing Support <Tutorial Testing Support>`. Now we just have to run
-those tests and submit them to a dashboard. To include support for dashboards
-we include the :module:`CTest` module in our top-level ``CMakeLists.txt``.
+those tests and submit them to CDash.
 
-Replace:
 
-.. literalinclude:: Step6/CMakeLists.txt
-  :caption: CMakeLists.txt
-  :name: CMakeLists.txt-enable_testing-remove
-  :language: cmake
-  :start-after: # enable testing
-  :end-before: # does the application run
+Exercise 1 - Send Results to a Testing Dashboard
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-With:
+Goal
+----
 
-.. literalinclude:: Step7/CMakeLists.txt
-  :caption: CMakeLists.txt
-  :name: CMakeLists.txt-include-CTest
-  :language: cmake
-  :start-after: # enable testing
-  :end-before: # does the application run
+Display our CTest results with CDash.
 
-The :module:`CTest` module will automatically call ``enable_testing()``, so we
-can remove it from our CMake files.
+Helpful Resources
+-----------------
+
+* :manual:`ctest(1)`
+* :command:`include`
+* :module:`CTest`
+
+Files to Edit
+-------------
+
+* ``CMakeLists.txt``
+
+Getting Started
+---------------
+
+For this exercise, complete ``TODO 1`` in the top-level ``CMakeLists.txt`` by
+including the :module:`CTest` module. This will enable testing with CTest as
+well as dashboard submissions to CDash, so we can safely remove the call to
+:command:`enable_testing`.
 
 We will also need to acquire a ``CTestConfig.cmake`` file to be placed in the
-top-level directory where we can specify information to CTest about the
-project. It contains:
+top-level directory. When run, the :manual:`ctest <ctest(1)>` executable will
+read this file to gather information about the testing dashboard. It contains:
 
 * The project name
 
@@ -41,9 +48,10 @@
 * The URL of the CDash instance where the submission's generated documents
   will be sent
 
-One has been provided for you in this directory.  It would normally be
-downloaded from the ``Settings`` page of the project on the CDash
-instance that will host and display the test results.  Once downloaded from
+For this tutorial, a public dashboard server is used and its corresponding
+``CTestConfig.cmake`` file is provided for you in this step's root directory.
+In practice, this file would be downloaded from a project's ``Settings`` page
+on the CDash instance intended to host the test results. Once downloaded from
 CDash, the file should not be modified locally.
 
 .. literalinclude:: Step7/CTestConfig.cmake
@@ -51,11 +59,16 @@
   :name: CTestConfig.cmake
   :language: cmake
 
-The :manual:`ctest <ctest(1)>` executable will read in this file when it runs.
-To create a simple dashboard you can run the :manual:`cmake <cmake(1)>`
-executable or the :manual:`cmake-gui <cmake-gui(1)>` to configure the project,
-but do not build it yet. Instead, change directory to the binary tree, and then
-run:
+
+Build and Run
+-------------
+
+Note that as part of the CDash submission some information about your
+development system (e.g. site name or full pathnames) may displayed publicly.
+
+To create a simple test dashboard, run the :manual:`cmake <cmake(1)>`
+executable or the :manual:`cmake-gui <cmake-gui(1)>` to configure the project
+but do not build it yet. Instead, navigate to the build directory and run:
 
 .. code-block:: console
 
@@ -70,6 +83,28 @@
 
 Or, from an IDE, build the ``Experimental`` target.
 
-The :manual:`ctest <ctest(1)>` executable will build and test the project and
-submit the results to Kitware's public dashboard:
+The :manual:`ctest <ctest(1)>` executable will build the project, run any
+tests, and submit the results to Kitware's public dashboard:
 https://my.cdash.org/index.php?project=CMakeTutorial.
+
+Solution
+--------
+
+The only CMake code changed needed in this step was to enable dashboard
+submissions to CDash by including the :module:`CTest` module in our top-level
+``CMakeLists.txt``:
+
+.. raw:: html
+
+  <details><summary>TODO 1: Click to show/hide answer</summary>
+
+.. literalinclude:: Step7/CMakeLists.txt
+  :caption: TODO 1: CMakeLists.txt
+  :name: CMakeLists.txt-include-CTest
+  :language: cmake
+  :start-after: # enable testing
+  :end-before: # does the application run
+
+.. raw:: html
+
+  </details>
diff --git a/Help/guide/tutorial/Adding System Introspection.rst b/Help/guide/tutorial/Adding System Introspection.rst
index ba91df4..b69abd2 100644
--- a/Help/guide/tutorial/Adding System Introspection.rst
+++ b/Help/guide/tutorial/Adding System Introspection.rst
@@ -7,53 +7,156 @@
 functions. Of course almost every platform has these functions but for this
 tutorial assume that they are not common.
 
-If the platform has ``log`` and ``exp`` then we will use them to compute the
-square root in the ``mysqrt`` function. We first test for the availability of
-these functions using the :module:`CheckCXXSourceCompiles` module in
+Exercise 1 - Assessing Dependency Availability
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Goal
+----
+
+Change implementation based on available system dependencies.
+
+Helpful Resources
+-----------------
+
+* :module:`CheckCXXSourceCompiles`
+* :command:`target_compile_definitions`
+
+Files to Edit
+-------------
+
+* ``MathFunctions/CMakeLists.txt``
+* ``MathFunctions/mysqrt.cxx``
+
+Getting Started
+---------------
+
+The starting source code is provided in the ``Step7`` directory. In this
+exercise, complete ``TODO 1`` through ``TODO 5``.
+
+Start by editing ``MathFunctions/CMakeLists.txt``. Include the
+:module:`CheckCXXSourceCompiles` module. Then, use
+``check_cxx_source_compiles`` to determine whether ``log`` and ``exp`` are
+available from ``cmath``. If they are available, use
+:command:`target_compile_definitions` to specify ``HAVE_LOG`` and ``HAVE_EXP``
+as compile definitions.
+
+In the ``MathFunctions/mysqrt.cxx``, include ``cmath``. Then, if the system has
+``log`` and ``exp``, use them to compute the square root.
+
+Build and Run
+-------------
+
+Make a new directory called ``Step7_build``. Run the
+:manual:`cmake  <cmake(1)>` executable or the
+:manual:`cmake-gui <cmake-gui(1)>` to configure the project and then build it
+with your chosen build tool and run the ``Tutorial`` executable.
+
+This can look like the following:
+
+.. code-block:: console
+
+  mkdir Step7_build
+  cd Step7_build
+  cmake ../Step7
+  cmake --build .
+
+Which function gives better results now, ``sqrt`` or ``mysqrt``?
+
+Solution
+--------
+
+In this exercise we will use functions from the
+:module:`CheckCXXSourceCompiles` module so first we must include it in
 ``MathFunctions/CMakeLists.txt``.
 
-Add the checks for ``log`` and ``exp`` to ``MathFunctions/CMakeLists.txt``,
-after the call to :command:`target_include_directories`:
+.. raw:: html
+
+  <details><summary>TODO 1: Click to show/hide answer</summary>
 
 .. literalinclude:: Step8/MathFunctions/CMakeLists.txt
-  :caption: MathFunctions/CMakeLists.txt
+  :caption: TODO 1: MathFunctions/CMakeLists.txt
+  :name: MathFunctions/CMakeLists.txt-include-check_cxx_source_compiles
+  :language: cmake
+  :start-after: # does this system provide the log and exp functions?
+  :end-before: check_cxx_source_compiles
+
+.. raw:: html
+
+  </details>
+
+Then test for the availability of
+``log`` and ``exp`` using ``check_cxx_compiles_source``. This function
+lets us try compiling simple code with the required dependency prior to
+the true source code compilation. The resulting variables ``HAVE_LOG``
+and ``HAVE_EXP`` represent whether those dependencies are available.
+
+.. raw:: html
+
+  <details><summary>TODO 2: Click to show/hide answer</summary>
+
+.. literalinclude:: Step8/MathFunctions/CMakeLists.txt
+  :caption: TODO 2: MathFunctions/CMakeLists.txt
   :name: MathFunctions/CMakeLists.txt-check_cxx_source_compiles
   :language: cmake
-  :start-after: # to find MathFunctions.h, while we don't.
+  :start-after: include(CheckCXXSourceCompiles)
   :end-before: # add compile definitions
 
-If available, use :command:`target_compile_definitions` to specify
+.. raw:: html
+
+  </details>
+
+Next, we need to pass these CMake variables to our source code. This way,
+our source code can tell what resources are available. If both ``log`` and
+``exp`` are available, use :command:`target_compile_definitions` to specify
 ``HAVE_LOG`` and ``HAVE_EXP`` as ``PRIVATE`` compile definitions.
 
+.. raw:: html
+
+  <details><summary>TODO 3: Click to show/hide answer</summary>
+
 .. literalinclude:: Step8/MathFunctions/CMakeLists.txt
-  :caption: MathFunctions/CMakeLists.txt
+  :caption: TODO 3: MathFunctions/CMakeLists.txt
   :name: MathFunctions/CMakeLists.txt-target_compile_definitions
   :language: cmake
   :start-after: # add compile definitions
   :end-before: # install libs
 
-If ``log`` and ``exp`` are available on the system, then we will use them to
-compute the square root in the ``mysqrt`` function. Add the following code to
-the ``mysqrt`` function in ``MathFunctions/mysqrt.cxx`` (don't forget the
-``#endif`` before returning the result!):
+.. raw:: html
+
+  </details>
+
+Since we may be using ``log`` and ``exp``, we need to modify
+``mysqrt.cxx`` to include ``cmath``.
+
+.. raw:: html
+
+  <details><summary>TODO 4: Click to show/hide answer</summary>
 
 .. literalinclude:: Step8/MathFunctions/mysqrt.cxx
-  :caption: MathFunctions/mysqrt.cxx
+  :caption: TODO 4: MathFunctions/mysqrt.cxx
+  :name: MathFunctions/mysqrt.cxx-include-cmath
+  :language: c++
+  :end-before: #include <iostream>
+
+.. raw:: html
+
+  </details>
+
+If ``log`` and ``exp`` are available on the system, then use them to
+compute the square root in the ``mysqrt`` function. The ``mysqrt`` function in
+``MathFunctions/mysqrt.cxx`` will look as follows:
+
+.. raw:: html
+
+  <details><summary>TODO 5: Click to show/hide answer</summary>
+
+.. literalinclude:: Step8/MathFunctions/mysqrt.cxx
+  :caption: TODO 5: MathFunctions/mysqrt.cxx
   :name: MathFunctions/mysqrt.cxx-ifdef
   :language: c++
   :start-after: // if we have both log and exp then use them
   :end-before: // do ten iterations
 
-We will also need to modify ``mysqrt.cxx`` to include ``cmath``.
+.. raw:: html
 
-.. literalinclude:: Step8/MathFunctions/mysqrt.cxx
-  :caption: MathFunctions/mysqrt.cxx
-  :name: MathFunctions/mysqrt.cxx-include-cmath
-  :language: c++
-  :end-before: #include <iostream>
-
-Run the :manual:`cmake  <cmake(1)>` executable or the
-:manual:`cmake-gui <cmake-gui(1)>` to configure the project and then build it
-with your chosen build tool and run the Tutorial executable.
-
-Which function gives better results now, ``sqrt`` or ``mysqrt``?
+  </details>
diff --git a/Help/guide/tutorial/Installing and Testing.rst b/Help/guide/tutorial/Installing and Testing.rst
index fa13040..c020264 100644
--- a/Help/guide/tutorial/Installing and Testing.rst
+++ b/Help/guide/tutorial/Installing and Testing.rst
@@ -145,7 +145,7 @@
   :name: TODO 3,4: CMakeLists.txt-install-TARGETS
   :language: cmake
   :start-after: # add the install targets
-  :end-before: # enable testing
+  :end-before: # TODO 1: Replace enable_testing() with include(CTest)
 
 .. raw:: html
 
diff --git a/Help/guide/tutorial/Step6/CMakeLists.txt b/Help/guide/tutorial/Step6/CMakeLists.txt
index da9e852..c11e307 100644
--- a/Help/guide/tutorial/Step6/CMakeLists.txt
+++ b/Help/guide/tutorial/Step6/CMakeLists.txt
@@ -45,6 +45,7 @@
   DESTINATION include
   )
 
+# TODO 1: Replace enable_testing() with include(CTest)
 # enable testing
 enable_testing()
 
diff --git a/Help/guide/tutorial/Step7/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step7/MathFunctions/CMakeLists.txt
index b4724c4..e5bdc4d 100644
--- a/Help/guide/tutorial/Step7/MathFunctions/CMakeLists.txt
+++ b/Help/guide/tutorial/Step7/MathFunctions/CMakeLists.txt
@@ -9,6 +9,26 @@
 # link our compiler flags interface library
 target_link_libraries(MathFunctions tutorial_compiler_flags)
 
+# TODO 1: Include CheckCXXSourceCompiles
+
+# TODO 2: Use check_cxx_source_compiles with simple C++ code to verify
+# availability of:
+# * std::log
+# * std::exp
+# Store the results in HAVE_LOG and HAVE_EXP respectively.
+
+# Hint: Sample C++ code which uses log:
+# #include <cmath>
+# int main() {
+#   std::log(1.0);
+#   return 0;
+# }
+
+# TODO 3: Conditionally on HAVE_LOG and HAVE_EXP, add private compile
+# definitions "HAVE_LOG" and "HAVE_EXP" to the MathFunctions target.
+
+#Hint: Use target_compile_definitions()
+
 # install libs
 set(installable_libs MathFunctions tutorial_compiler_flags)
 install(TARGETS ${installable_libs} DESTINATION lib)
diff --git a/Help/guide/tutorial/Step7/MathFunctions/mysqrt.cxx b/Help/guide/tutorial/Step7/MathFunctions/mysqrt.cxx
index abe767d..3d2492a 100644
--- a/Help/guide/tutorial/Step7/MathFunctions/mysqrt.cxx
+++ b/Help/guide/tutorial/Step7/MathFunctions/mysqrt.cxx
@@ -1,5 +1,6 @@
 #include <iostream>
 
+// TODO 4: include cmath
 #include "MathFunctions.h"
 
 // a hack square root calculation using simple operations
@@ -9,6 +10,14 @@
     return 0;
   }
 
+  // TODO 5: If both HAVE_LOG and HAVE_EXP are defined,  use the following:
+  //// double result = std::exp(std::log(x) * 0.5);
+  //// std::cout << "Computing sqrt of " << x << " to be " << result
+  ////        << " using log and exp" << std::endl;
+  // else, use the existing logic.
+
+  // Hint: Don't forget the #endif before returning the result!
+
   double result = x;
 
   // do ten iterations
@@ -20,5 +29,6 @@
     result = result + 0.5 * delta / result;
     std::cout << "Computing sqrt of " << x << " to be " << result << std::endl;
   }
+
   return result;
 }
diff --git a/Help/prop_tgt/COMMON_LANGUAGE_RUNTIME.rst b/Help/prop_tgt/COMMON_LANGUAGE_RUNTIME.rst
index adfa6f7..7ce0023 100644
--- a/Help/prop_tgt/COMMON_LANGUAGE_RUNTIME.rst
+++ b/Help/prop_tgt/COMMON_LANGUAGE_RUNTIME.rst
@@ -7,13 +7,30 @@
 ``C++/CLI`` support.
 
 The Visual Studio generator defines the ``clr`` parameter depending on
-the value of ``COMMON_LANGUAGE_RUNTIME``:
+the value of the ``COMMON_LANGUAGE_RUNTIME`` target property:
 
-* property not set: native C++ (i.e. default)
-* property set but empty: mixed unmanaged/managed C++
-* property set to any non empty value: managed C++
+Not Set (default)
 
-Supported values: ``""``, ``"pure"``, ``"safe"``
+  Native C++.
+
+``""`` (set but empty)
+
+  Mixed unmanaged/managed C++ using .NET Framework.
+
+``netcore``
+  .. versionadded:: 3.26
+
+  Mixed unmanaged/managed C++ using .NET Core.
+
+  This required VS 2019's v142 toolset or higher.
+
+``pure``
+
+  Managed C++.
+
+``safe``
+
+  Managed C++.
 
 This property is only evaluated :ref:`Visual Studio Generators` for
 VS 2010 and above.
diff --git a/Help/release/dev/0-sample-topic.rst b/Help/release/dev/0-sample-topic.rst
new file mode 100644
index 0000000..e4cc01e
--- /dev/null
+++ b/Help/release/dev/0-sample-topic.rst
@@ -0,0 +1,7 @@
+0-sample-topic
+--------------
+
+* This is a sample release note for the change in a topic.
+  Developers should add similar notes for each topic branch
+  making a noteworthy change.  Each document should be named
+  and titled to match the topic name to avoid merge conflicts.
diff --git a/Help/release/dev/ExternalProject-INSTALL_BYPRODUCTS.rst b/Help/release/dev/ExternalProject-INSTALL_BYPRODUCTS.rst
new file mode 100644
index 0000000..233596f
--- /dev/null
+++ b/Help/release/dev/ExternalProject-INSTALL_BYPRODUCTS.rst
@@ -0,0 +1,6 @@
+ExternalProject-INSTALL_BYPRODUCTS
+----------------------------------
+
+* The :module:`ExternalProject` module :command:`ExternalProject_Add` command
+  gained an ``INSTALL_BYPRODUCTS`` option to specify files generated by the
+  "install" step.
diff --git a/Help/release/dev/UseSWIG-perl5.rst b/Help/release/dev/UseSWIG-perl5.rst
new file mode 100644
index 0000000..67d4161
--- /dev/null
+++ b/Help/release/dev/UseSWIG-perl5.rst
@@ -0,0 +1,4 @@
+UseSWIG-perl5
+-------------
+
+* The :module:`UseSWIG` module gained the support of ``perl5`` language.
diff --git a/Help/release/dev/compile-commands-output-field.rst b/Help/release/dev/compile-commands-output-field.rst
new file mode 100644
index 0000000..110fd4e
--- /dev/null
+++ b/Help/release/dev/compile-commands-output-field.rst
@@ -0,0 +1,7 @@
+compile-commands-output-field
+-----------------------------
+
+* The :prop_tgt:`EXPORT_COMPILE_COMMANDS` target property will now have the
+  ``output`` field in the compile commands objects. This allows multi-config
+  generators (namely :generator:`Ninja Multi-Config` generator) to contain the
+  compile commands for all configurations.
diff --git a/Help/release/dev/timestamp-timezone.rst b/Help/release/dev/timestamp-timezone.rst
new file mode 100644
index 0000000..178fa9a
--- /dev/null
+++ b/Help/release/dev/timestamp-timezone.rst
@@ -0,0 +1,5 @@
+timestamp-timezone
+------------------
+
+* The :command:`string(TIMESTAMP)` and :command:`file(TIMESTAMP)` commands
+  now support the ``%z`` and ``%Z`` specifiers for the time zone.
diff --git a/Help/release/dev/trace-try_compile.rst b/Help/release/dev/trace-try_compile.rst
new file mode 100644
index 0000000..886aaad
--- /dev/null
+++ b/Help/release/dev/trace-try_compile.rst
@@ -0,0 +1,5 @@
+trace-try_compile
+-----------------
+
+* The :option:`cmake --trace` option now follows :command:`try_compile` and
+  :command:`try_run` invocations.
diff --git a/Help/release/index.rst b/Help/release/index.rst
index b6ecf7b..50e06bb 100644
--- a/Help/release/index.rst
+++ b/Help/release/index.rst
@@ -7,6 +7,8 @@
   This file should include the adjacent "dev.txt" file
   in development versions but not in release versions.
 
+.. include:: dev.txt
+
 Releases
 ========
 
diff --git a/Modules/CMakeSwiftInformation.cmake b/Modules/CMakeSwiftInformation.cmake
index 16726d2..62f7ef2 100644
--- a/Modules/CMakeSwiftInformation.cmake
+++ b/Modules/CMakeSwiftInformation.cmake
@@ -65,10 +65,22 @@
 set(CMAKE_Swift_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug -libc MTd)
 set(CMAKE_Swift_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL -libc MDd)
 
-set(CMAKE_Swift_FLAGS_DEBUG_INIT "-Onone -g")
-set(CMAKE_Swift_FLAGS_RELEASE_INIT "-O")
-set(CMAKE_Swift_FLAGS_RELWITHDEBINFO_INIT "-O -g")
-set(CMAKE_Swift_FLAGS_MINSIZEREL_INIT "-Osize")
+if(CMAKE_GENERATOR STREQUAL "Xcode")
+  # Xcode has a separate Xcode project option (SWIFT_COMPILATION_MODE) used to set
+  # whether compiling with whole-module optimizations or incrementally. Setting
+  # these options here will have no effect when compiling with the built-in driver,
+  # and will explode violently, leaving build products in the source directory, when
+  # using the old swift driver.
+  set(CMAKE_Swift_FLAGS_DEBUG_INIT "-Onone -g")
+  set(CMAKE_Swift_FLAGS_RELEASE_INIT "-O")
+  set(CMAKE_Swift_FLAGS_RELWITHDEBINFO_INIT "-O -g")
+  set(CMAKE_Swift_FLAGS_MINSIZEREL_INIT "-Osize")
+else()
+  set(CMAKE_Swift_FLAGS_DEBUG_INIT "-Onone -g -incremental")
+  set(CMAKE_Swift_FLAGS_RELEASE_INIT "-O -wmo")
+  set(CMAKE_Swift_FLAGS_RELWITHDEBINFO_INIT "-O -g -wmo")
+  set(CMAKE_Swift_FLAGS_MINSIZEREL_INIT "-Osize -wmo")
+endif()
 
 if(CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF")
   if(NOT DEFINED CMAKE_Swift_LINK_WHAT_YOU_USE_FLAG)
@@ -91,7 +103,7 @@
 endif()
 
 if(NOT CMAKE_Swift_CREATE_SHARED_LIBRARY)
-  set(CMAKE_Swift_CREATE_SHARED_LIBRARY "<CMAKE_Swift_COMPILER> -output-file-map <SWIFT_OUTPUT_FILE_MAP> -incremental -j ${CMAKE_Swift_NUM_THREADS} -emit-library -o <TARGET> -module-name <SWIFT_MODULE_NAME> -module-link-name <SWIFT_LIBRARY_NAME> -emit-module -emit-module-path <SWIFT_MODULE> -emit-dependencies <DEFINES> <FLAGS> <INCLUDES> <SWIFT_SOURCES> <LINK_FLAGS> <SONAME_FLAG> <TARGET_INSTALLNAME_DIR><TARGET_SONAME> ${CMAKE_Swift_IMPLIB_LINKER_FLAGS} <LINK_LIBRARIES>")
+  set(CMAKE_Swift_CREATE_SHARED_LIBRARY "<CMAKE_Swift_COMPILER> -j ${CMAKE_Swift_NUM_THREADS} -num-threads ${CMAKE_Swift_NUM_THREADS} -emit-library -o <TARGET> -module-name <SWIFT_MODULE_NAME> -module-link-name <SWIFT_LIBRARY_NAME> -emit-module -emit-module-path <SWIFT_MODULE> -emit-dependencies <DEFINES> <FLAGS> <INCLUDES> <SWIFT_SOURCES> <LINK_FLAGS> <SONAME_FLAG> <TARGET_INSTALLNAME_DIR><TARGET_SONAME> ${CMAKE_Swift_IMPLIB_LINKER_FLAGS} <LINK_LIBRARIES>")
 endif()
 
 if(NOT CMAKE_Swift_CREATE_SHARED_MODULE)
@@ -99,11 +111,11 @@
 endif()
 
 if(NOT CMAKE_Swift_LINK_EXECUTABLE)
-  set(CMAKE_Swift_LINK_EXECUTABLE "<CMAKE_Swift_COMPILER> -output-file-map <SWIFT_OUTPUT_FILE_MAP> -incremental -j ${CMAKE_Swift_NUM_THREADS} -emit-executable -o <TARGET> -emit-dependencies <DEFINES> <FLAGS> <INCLUDES> <SWIFT_SOURCES> <LINK_FLAGS> <LINK_LIBRARIES>")
+  set(CMAKE_Swift_LINK_EXECUTABLE "<CMAKE_Swift_COMPILER> -j ${CMAKE_Swift_NUM_THREADS} -num-threads ${CMAKE_Swift_NUM_THREADS} -emit-executable -o <TARGET> -emit-dependencies <DEFINES> <FLAGS> <INCLUDES> <SWIFT_SOURCES> <LINK_FLAGS> <LINK_LIBRARIES>")
 endif()
 
 if(NOT CMAKE_Swift_CREATE_STATIC_LIBRARY)
-  set(CMAKE_Swift_CREATE_STATIC_LIBRARY "<CMAKE_Swift_COMPILER> -output-file-map <SWIFT_OUTPUT_FILE_MAP> -incremental -j ${CMAKE_Swift_NUM_THREADS} -emit-library -static -o <TARGET> -module-name <SWIFT_MODULE_NAME> -module-link-name <SWIFT_LIBRARY_NAME> -emit-module -emit-module-path <SWIFT_MODULE> -emit-dependencies <DEFINES> <FLAGS> <INCLUDES> <SWIFT_SOURCES> <LINK_FLAGS> <LINK_LIBRARIES>")
+  set(CMAKE_Swift_CREATE_STATIC_LIBRARY "<CMAKE_Swift_COMPILER> -j ${CMAKE_Swift_NUM_THREADS} -num-threads ${CMAKE_Swift_NUM_THREADS} -emit-library -static -o <TARGET> -module-name <SWIFT_MODULE_NAME> -module-link-name <SWIFT_LIBRARY_NAME> -emit-module -emit-module-path <SWIFT_MODULE> -emit-dependencies <DEFINES> <FLAGS> <INCLUDES> <SWIFT_SOURCES> <LINK_FLAGS> <LINK_LIBRARIES>")
 
   set(CMAKE_Swift_ARCHIVE_CREATE "<CMAKE_AR> crs <TARGET> <OBJECTS>")
   set(CMAKE_Swift_ARCHIVE_FINISH "")
diff --git a/Modules/ExternalProject.cmake b/Modules/ExternalProject.cmake
index 22a25bd..9fecd8f 100644
--- a/Modules/ExternalProject.cmake
+++ b/Modules/ExternalProject.cmake
@@ -637,8 +637,11 @@
 
       Specifies files that will be generated by the build command but which
       might or might not have their modification time updated by subsequent
-      builds. These ultimately get passed through as ``BYPRODUCTS`` to the
-      build step's own underlying call to :command:`add_custom_command`.
+      builds. This may also be required to explicitly declare dependencies
+      when using the :generator:`Ninja` generator.
+      These ultimately get passed through as ``BYPRODUCTS`` to the
+      build step's own underlying call to :command:`add_custom_command`, which
+      has additional documentation.
 
   **Install Step Options:**
     If the configure step assumed the external project uses CMake as its build
@@ -661,6 +664,17 @@
       supported). Passing an empty string as the ``<cmd>`` makes the install
       step do nothing.
 
+    ``INSTALL_BYPRODUCTS <file>...``
+      .. versionadded:: 3.26
+
+      Specifies files that will be generated by the install command but which
+      might or might not have their modification time updated by subsequent
+      installs. This may also be required to explicitly declare dependencies
+      when using the :generator:`Ninja` generator.
+      These ultimately get passed through as ``BYPRODUCTS`` to the
+      install step's own underlying call to :command:`add_custom_command`, which
+      has additional documentation.
+
     .. note::
       If the :envvar:`CMAKE_INSTALL_MODE` environment variable is set when the
       main project is built, it will only have an effect if the following
@@ -943,9 +957,12 @@
     .. versionadded:: 3.2
 
     Files that will be generated by this custom step but which might or might
-    not have their modification time updated by subsequent builds. This list of
+    not have their modification time updated by subsequent builds.
+    This may also be required to explicitly declare dependencies
+    when using the :generator:`Ninja` generator. This list of
     files will ultimately be passed through as the ``BYPRODUCTS`` option to the
-    :command:`add_custom_command` used to implement the custom step internally.
+    :command:`add_custom_command` used to implement the custom step internally,
+    which has additional documentation.
 
   ``ALWAYS <bool>``
     When enabled, this option specifies that the custom step should always be
@@ -3642,7 +3659,7 @@
       )
     endif()
 
-    list(APPEND cmd "<SOURCE_DIR><SOURCE_SUBDIR>")
+    list(APPEND cmd -S "<SOURCE_DIR><SOURCE_SUBDIR>" -B "<BINARY_DIR>")
   endif()
 
   set("${var}" "${cmd}" PARENT_SCOPE)
@@ -3846,6 +3863,11 @@
     set(always 0)
   endif()
 
+  get_property(install_byproducts
+    TARGET ${name}
+    PROPERTY _EP_INSTALL_BYPRODUCTS
+  )
+
   set(__cmdQuoted)
   foreach(__item IN LISTS cmd)
     string(APPEND __cmdQuoted " [==[${__item}]==]")
@@ -3854,6 +3876,7 @@
     ExternalProject_Add_Step(${name} install
       INDEPENDENT FALSE
       COMMAND ${__cmdQuoted}
+      BYPRODUCTS \${install_byproducts}
       WORKING_DIRECTORY \${binary_dir}
       DEPENDEES build
       ALWAYS \${always}
@@ -4081,6 +4104,7 @@
     # Install step options
     #
     INSTALL_COMMAND
+    INSTALL_BYPRODUCTS
     #
     # Test step options
     #
diff --git a/Modules/FindZLIB.cmake b/Modules/FindZLIB.cmake
index be5c775..cfe6715 100644
--- a/Modules/FindZLIB.cmake
+++ b/Modules/FindZLIB.cmake
@@ -60,6 +60,14 @@
 
 #]=======================================================================]
 
+if(ZLIB_FIND_COMPONENTS AND NOT ZLIB_FIND_QUIETLY)
+  message(AUTHOR_WARNING
+    "ZLIB does not provide any COMPONENTS.  Calling\n"
+    "  find_package(ZLIB COMPONENTS ...)\n"
+    "will always fail."
+    )
+endif()
+
 set(_ZLIB_SEARCHES)
 
 # Search ZLIB_ROOT first if it is set.
@@ -164,7 +172,8 @@
 
 include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
 FIND_PACKAGE_HANDLE_STANDARD_ARGS(ZLIB REQUIRED_VARS ZLIB_LIBRARY ZLIB_INCLUDE_DIR
-                                       VERSION_VAR ZLIB_VERSION_STRING)
+                                       VERSION_VAR ZLIB_VERSION_STRING
+                                       HANDLE_COMPONENTS)
 
 if(ZLIB_FOUND)
     set(ZLIB_INCLUDE_DIRS ${ZLIB_INCLUDE_DIR})
diff --git a/Modules/Internal/CheckFlagCommonConfig.cmake b/Modules/Internal/CheckFlagCommonConfig.cmake
index c011c24..f8481cd 100644
--- a/Modules/Internal/CheckFlagCommonConfig.cmake
+++ b/Modules/Internal/CheckFlagCommonConfig.cmake
@@ -48,6 +48,8 @@
       FAIL_REGEX "argument unused during compilation: .*") # Clang
   elseif("${_LANG}" STREQUAL "ISPC")
     set(${_SRC} "float func(uniform int32, float a) { return a / 2.25; }")
+  elseif("${_LANG}" STREQUAL "Swift")
+    set(${_SRC} "func blarpy() { }")
   else()
     message (SEND_ERROR "${_FUNC}: ${_LANG}: unknown language.")
     return()
diff --git a/Modules/Internal/CheckSourceCompiles.cmake b/Modules/Internal/CheckSourceCompiles.cmake
index eadf3da..bf5a82d 100644
--- a/Modules/Internal/CheckSourceCompiles.cmake
+++ b/Modules/Internal/CheckSourceCompiles.cmake
@@ -9,7 +9,7 @@
 
 function(CMAKE_CHECK_SOURCE_COMPILES _lang _source _var)
   if(NOT DEFINED "${_var}")
-
+    set(_lang_filename "src")
     if(_lang STREQUAL "C")
       set(_lang_textual "C")
       set(_lang_ext "c")
@@ -34,6 +34,13 @@
     elseif(_lang STREQUAL "OBJCXX")
       set(_lang_textual "Objective-C++")
       set(_lang_ext "mm")
+    elseif(_lang STREQUAL "Swift")
+      set(_lang_textual "Swift")
+      set(_lang_ext "swift")
+      if (NOT DEFINED CMAKE_TRY_COMPILE_TARGET_TYPE
+          OR CMAKE_TRY_COMPILE_TARGET_TYPE STREQUAL "EXECUTABLE")
+        set(_lang_filename "main")
+      endif()
     else()
       message (SEND_ERROR "check_source_compiles: ${_lang}: unknown language.")
       return()
@@ -92,7 +99,7 @@
     endif()
     string(APPEND _source "\n")
     try_compile(${_var}
-      SOURCE_FROM_VAR "src.${_SRC_EXT}" _source
+      SOURCE_FROM_VAR "${_lang_filename}.${_SRC_EXT}" _source
       COMPILE_DEFINITIONS -D${_var} ${CMAKE_REQUIRED_DEFINITIONS}
       ${CHECK_${LANG}_SOURCE_COMPILES_ADD_LINK_OPTIONS}
       ${CHECK_${LANG}_SOURCE_COMPILES_ADD_LIBRARIES}
diff --git a/Modules/UseSWIG.cmake b/Modules/UseSWIG.cmake
index fd6596b..e0e01f5 100644
--- a/Modules/UseSWIG.cmake
+++ b/Modules/UseSWIG.cmake
@@ -378,6 +378,7 @@
 set(SWIG_JAVA_EXTRA_FILE_EXTENSIONS ".java" "JNI.java")
 set(SWIG_CSHARP_EXTRA_FILE_EXTENSIONS ".cs" "PINVOKE.cs")
 set(SWIG_PERL_EXTRA_FILE_EXTENSIONS ".pm")
+set(SWIG_PERL5_EXTRA_FILE_EXTENSIONS ".pm")
 
 set(SWIG_MANAGE_SUPPORT_FILES_SCRIPT "${CMAKE_CURRENT_LIST_DIR}/UseSWIG/ManageSupportFiles.cmake")
 
@@ -414,8 +415,8 @@
   endif()
   if(SWIG_MODULE_${name}_LANGUAGE STREQUAL "UNKNOWN")
     message(FATAL_ERROR "SWIG Error: Language \"${language}\" not found")
-  elseif(SWIG_MODULE_${name}_LANGUAGE STREQUAL "PERL" AND
-         NOT "-shadow" IN_LIST SWIG_MODULE_${name}_EXTRA_FLAGS)
+  elseif((SWIG_MODULE_${name}_LANGUAGE STREQUAL "PERL" OR SWIG_MODULE_${name}_LANGUAGE STREQUAL "PERL5")
+      AND NOT "-shadow" IN_LIST SWIG_MODULE_${name}_EXTRA_FLAGS)
     list(APPEND SWIG_MODULE_${name}_EXTRA_FLAGS "-shadow")
   endif()
 endmacro()
@@ -971,7 +972,7 @@
     if (APPLE)
       set_target_properties (${target_name} PROPERTIES SUFFIX ".bundle")
     endif ()
-  elseif (swig_lowercase_language STREQUAL "perl")
+  elseif (swig_lowercase_language STREQUAL "perl" OR swig_lowercase_language STREQUAL "perl5")
     # assume empty prefix because we expect the module to be dynamically loaded
     set_target_properties (${target_name} PROPERTIES PREFIX "")
     if (APPLE)
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 0ce096d..5e7896f 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,8 +1,8 @@
 # CMake version number components.
 set(CMake_VERSION_MAJOR 3)
 set(CMake_VERSION_MINOR 25)
-set(CMake_VERSION_PATCH 0)
-set(CMake_VERSION_RC 3)
+set(CMake_VERSION_PATCH 20221108)
+#set(CMake_VERSION_RC 0)
 set(CMake_VERSION_IS_DIRTY 0)
 
 # Start with the full version number used in tags.  It has no dev info.
diff --git a/Source/CursesDialog/ccmake.cxx b/Source/CursesDialog/ccmake.cxx
index 1f7776c..70ed648 100644
--- a/Source/CursesDialog/ccmake.cxx
+++ b/Source/CursesDialog/ccmake.cxx
@@ -77,7 +77,7 @@
   cmDocumentation doc;
   doc.addCMakeStandardDocSections();
   if (doc.CheckOptions(argc, argv)) {
-    cmake hcm(cmake::RoleInternal, cmState::Unknown);
+    cmake hcm(cmake::RoleInternal, cmState::Help);
     hcm.SetHomeDirectory("");
     hcm.SetHomeOutputDirectory("");
     hcm.AddCMakePaths();
diff --git a/Source/QtDialog/CMakeSetup.cxx b/Source/QtDialog/CMakeSetup.cxx
index fb12b7d..591b793 100644
--- a/Source/QtDialog/CMakeSetup.cxx
+++ b/Source/QtDialog/CMakeSetup.cxx
@@ -79,7 +79,7 @@
   doc.addCMakeStandardDocSections();
   if (argc2 > 1 && doc.CheckOptions(argc2, argv2)) {
     // Construct and print requested documentation.
-    cmake hcm(cmake::RoleInternal, cmState::Unknown);
+    cmake hcm(cmake::RoleInternal, cmState::Help);
     hcm.SetHomeDirectory("");
     hcm.SetHomeOutputDirectory("");
     hcm.AddCMakePaths();
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
index 50bc78c..2c61163 100644
--- a/Source/cmExportFileGenerator.cxx
+++ b/Source/cmExportFileGenerator.cxx
@@ -939,13 +939,13 @@
 
   // Isolate the file policy level.
   // Support CMake versions as far back as 2.6 but also support using NEW
-  // policy settings for up to CMake 3.23 (this upper limit may be reviewed
+  // policy settings for up to CMake 3.24 (this upper limit may be reviewed
   // and increased from time to time). This reduces the opportunity for CMake
   // warnings when an older export file is later used with newer CMake
   // versions.
   /* clang-format off */
   os << "cmake_policy(PUSH)\n"
-     << "cmake_policy(VERSION 2.8.3...3.23)\n";
+     << "cmake_policy(VERSION 2.8.3...3.24)\n";
   /* clang-format on */
 }
 
diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx
index 3f8378b..60b0a7b 100644
--- a/Source/cmFindPackageCommand.cxx
+++ b/Source/cmFindPackageCommand.cxx
@@ -377,6 +377,8 @@
 #  pragma diag_suppress 1222 // invalid error number (3288, but works anyway)
 #  define CM_LCC_DIAG_SUPPRESS_3288
 #  pragma diag_suppress 3288 // parameter was declared but never referenced
+#  define CM_LCC_DIAG_SUPPRESS_3301
+#  pragma diag_suppress 3301 // parameter was declared but never referenced
 #endif
 
 void ResetGenerator()
@@ -421,6 +423,11 @@
   return false;
 }
 
+#ifdef CM_LCC_DIAG_SUPPRESS_3301
+#  undef CM_LCC_DIAG_SUPPRESS_3301
+#  pragma diag_default 3301
+#endif
+
 #ifdef CM_LCC_DIAG_SUPPRESS_3288
 #  undef CM_LCC_DIAG_SUPPRESS_3288
 #  pragma diag_default 3288
diff --git a/Source/cmGeneratedFileStream.cxx b/Source/cmGeneratedFileStream.cxx
index c72d6a7..133bf5f 100644
--- a/Source/cmGeneratedFileStream.cxx
+++ b/Source/cmGeneratedFileStream.cxx
@@ -27,7 +27,7 @@
 cmGeneratedFileStream::cmGeneratedFileStream(std::string const& name,
                                              bool quiet, Encoding encoding)
   : cmGeneratedFileStreamBase(name)
-  , Stream(this->TempName.c_str())
+  , Stream(this->TempName.c_str()) // NOLINT(cmake-use-cmsys-fstream)
 {
   // Check if the file opened.
   if (!*this && !quiet) {
@@ -67,10 +67,11 @@
 
   // Open the temporary output file.
   if (binaryFlag) {
-    this->Stream::open(this->TempName.c_str(),
-                       std::ios::out | std::ios::binary);
+    this->Stream::open( // NOLINT(cmake-use-cmsys-fstream)
+      this->TempName.c_str(), std::ios::out | std::ios::binary);
   } else {
-    this->Stream::open(this->TempName.c_str());
+    this->Stream::open( // NOLINT(cmake-use-cmsys-fstream)
+      this->TempName.c_str());
   }
 
   // Check if the file opened.
@@ -87,7 +88,7 @@
   this->Okay = !this->fail();
 
   // Close the temporary output file.
-  this->Stream::close();
+  this->Stream::close(); // NOLINT(cmake-use-cmsys-fstream)
 
   // Remove the temporary file (possibly by renaming to the real file).
   return this->cmGeneratedFileStreamBase::Close();
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 6195d1f..8fd7321 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -5532,7 +5532,7 @@
       } else if (cmHasLiteralPrefix(*location, "Resources/")) {
         flags.Type = cmGeneratorTarget::SourceFileTypeDeepResource;
         if (stripResources) {
-          flags.MacFolder += strlen("Resources/");
+          flags.MacFolder += cmStrLen("Resources/");
         }
       } else {
         flags.Type = cmGeneratorTarget::SourceFileTypeMacContent;
@@ -8515,9 +8515,14 @@
   //                            lib
   // 2. empty propval:          add /clr as flag, mixed unmanaged/managed
   //                            target, has import lib
-  // 3. any value (safe,pure):  add /clr:[propval] as flag, target with
+  // 3. netcore propval:        add /clr:netcore as flag, mixed
+  //                            unmanaged/managed target, has import lib.
+  // 4. any value (safe,pure):  add /clr:[propval] as flag, target with
   //                            managed code only, no import lib
-  return propval.empty() ? ManagedType::Mixed : ManagedType::Managed;
+  if (propval.empty() || propval == "netcore") {
+    return ManagedType::Mixed;
+  }
+  return ManagedType::Managed;
 }
 
 cmGeneratorTarget::ManagedType cmGeneratorTarget::GetManagedType(
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index 077de42..395372b 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -1171,7 +1171,8 @@
 }
 
 void cmGlobalNinjaGenerator::AddCXXCompileCommand(
-  const std::string& commandLine, const std::string& sourceFile)
+  const std::string& commandLine, const std::string& sourceFile,
+  const std::string& objPath)
 {
   // Compute Ninja's build file path.
   std::string buildFileDir =
@@ -1205,7 +1206,9 @@
      << R"(  "command": ")"
      << cmGlobalGenerator::EscapeJSON(commandLine) << "\",\n"
      << R"(  "file": ")"
-     << cmGlobalGenerator::EscapeJSON(sourceFileName) << "\"\n"
+     << cmGlobalGenerator::EscapeJSON(sourceFileName) << "\",\n"
+     << R"(  "output": ")"
+     << cmGlobalGenerator::EscapeJSON(objPath) << "\"\n"
      << "}";
   /* clang-format on */
 }
diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h
index defa264..dac1c52 100644
--- a/Source/cmGlobalNinjaGenerator.h
+++ b/Source/cmGlobalNinjaGenerator.h
@@ -292,7 +292,8 @@
   }
 
   void AddCXXCompileCommand(const std::string& commandLine,
-                            const std::string& sourceFile);
+                            const std::string& sourceFile,
+                            const std::string& objPath);
 
   /**
    * Add a rule to the generated build system.
diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx
index 21aa89c..bf9e40e 100644
--- a/Source/cmGlobalUnixMakefileGenerator3.cxx
+++ b/Source/cmGlobalUnixMakefileGenerator3.cxx
@@ -143,7 +143,7 @@
 
 void cmGlobalUnixMakefileGenerator3::AddCXXCompileCommand(
   const std::string& sourceFile, const std::string& workingDirectory,
-  const std::string& compileCommand)
+  const std::string& compileCommand, const std::string& objPath)
 {
   if (!this->CommandDatabase) {
     std::string commandDatabaseName =
@@ -164,7 +164,9 @@
                          << "\",\n"
                          << R"(  "file": ")"
                          << cmGlobalGenerator::EscapeJSON(sourceFile)
-                         << "\"\n}";
+                         << "\",\n"
+                         << R"(  "output": ")"
+                         << cmGlobalGenerator::EscapeJSON(objPath) << "\"\n}";
 }
 
 void cmGlobalUnixMakefileGenerator3::WriteMainMakefile2()
diff --git a/Source/cmGlobalUnixMakefileGenerator3.h b/Source/cmGlobalUnixMakefileGenerator3.h
index b9d333e..92e567a 100644
--- a/Source/cmGlobalUnixMakefileGenerator3.h
+++ b/Source/cmGlobalUnixMakefileGenerator3.h
@@ -174,7 +174,8 @@
 
   void AddCXXCompileCommand(const std::string& sourceFile,
                             const std::string& workingDirectory,
-                            const std::string& compileCommand);
+                            const std::string& compileCommand,
+                            const std::string& objPath);
 
   /** Does the make tool tolerate .NOTPARALLEL? */
   virtual bool AllowNotParallel() const { return true; }
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index 0658021..62e5a1e 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -4412,12 +4412,20 @@
     buildSettings->AddAttribute("CODE_SIGNING_ALLOWED",
                                 this->CreateString("NO"));
   }
+  auto debugConfigs = this->GetCMakeInstance()->GetDebugConfigs();
+  std::set<std::string> debugConfigSet(debugConfigs.begin(),
+                                       debugConfigs.end());
 
   for (auto& config : configs) {
     CreateGlobalXCConfigSettings(root, config.second, config.first);
 
     cmXCodeObject* buildSettingsForCfg = this->CreateFlatClone(buildSettings);
 
+    if (debugConfigSet.count(cmSystemTools::UpperCase(config.first)) == 0) {
+      buildSettingsForCfg->AddAttribute("SWIFT_COMPILATION_MODE",
+                                        this->CreateString("wholemodule"));
+    }
+
     // Put this last so it can override existing settings
     // Convert "CMAKE_XCODE_ATTRIBUTE_*" variables directly.
     for (const auto& var : this->CurrentMakefile->GetDefinitions()) {
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 6e0d704..2091f27 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -375,19 +375,15 @@
     ++this->Makefile->RecursionDepth;
     this->Makefile->ExecutionStatusStack.push_back(&status);
 #if !defined(CMAKE_BOOTSTRAP)
-    if (this->Makefile->GetCMakeInstance()->IsProfilingEnabled()) {
-      this->Makefile->GetCMakeInstance()->GetProfilingOutput().StartEntry(lff,
-                                                                          lfc);
-    }
+    this->ProfilingDataRAII =
+      this->Makefile->GetCMakeInstance()->CreateProfilingEntry(lff, lfc);
 #endif
   }
 
   ~cmMakefileCall()
   {
 #if !defined(CMAKE_BOOTSTRAP)
-    if (this->Makefile->GetCMakeInstance()->IsProfilingEnabled()) {
-      this->Makefile->GetCMakeInstance()->GetProfilingOutput().StopEntry();
-    }
+    this->ProfilingDataRAII.reset();
 #endif
     this->Makefile->ExecutionStatusStack.pop_back();
     --this->Makefile->RecursionDepth;
@@ -399,6 +395,9 @@
 
 private:
   cmMakefile* Makefile;
+#if !defined(CMAKE_BOOTSTRAP)
+  cm::optional<cmMakefileProfilingData::RAII> ProfilingDataRAII;
+#endif
 };
 
 void cmMakefile::OnExecuteCommand(std::function<void()> callback)
@@ -3584,6 +3583,9 @@
   gg->RecursionDepth = this->RecursionDepth;
   cm.SetGlobalGenerator(std::move(gg));
 
+  // copy trace state
+  cm.SetTraceRedirect(this->GetCMakeInstance());
+
   // do a configure
   cm.SetHomeDirectory(srcdir);
   cm.SetHomeOutputDirectory(bindir);
@@ -4470,12 +4472,12 @@
   }
 
   // Deprecate old policies.
-  if (status == cmPolicies::OLD && id <= cmPolicies::CMP0102 &&
+  if (status == cmPolicies::OLD && id <= cmPolicies::CMP0108 &&
       !(this->GetCMakeInstance()->GetIsInTryCompile() &&
         (
           // Policies set by cmCoreTryCompile::TryCompileCode.
           id == cmPolicies::CMP0065 || id == cmPolicies::CMP0083 ||
-          id == cmPolicies::CMP0091)) &&
+          id == cmPolicies::CMP0091 || id == cmPolicies::CMP0104)) &&
       (!this->IsSet("CMAKE_WARN_DEPRECATED") ||
        this->IsOn("CMAKE_WARN_DEPRECATED"))) {
     this->IssueMessage(MessageType::DEPRECATION_WARNING,
diff --git a/Source/cmMakefileProfilingData.cxx b/Source/cmMakefileProfilingData.cxx
index 1cd97c9..e4844f3 100644
--- a/Source/cmMakefileProfilingData.cxx
+++ b/Source/cmMakefileProfilingData.cxx
@@ -4,8 +4,12 @@
 
 #include <chrono>
 #include <stdexcept>
+#include <type_traits>
+#include <utility>
 #include <vector>
 
+#include <cm/utility>
+
 #include <cm3p/json/value.h>
 #include <cm3p/json/writer.h>
 
@@ -46,6 +50,23 @@
 void cmMakefileProfilingData::StartEntry(const cmListFileFunction& lff,
                                          cmListFileContext const& lfc)
 {
+  cm::optional<Json::Value> argsValue(cm::in_place, Json::objectValue);
+  if (!lff.Arguments().empty()) {
+    std::string args;
+    for (auto const& a : lff.Arguments()) {
+      args = cmStrCat(args, args.empty() ? "" : " ", a.Value);
+    }
+    (*argsValue)["functionArgs"] = args;
+  }
+  (*argsValue)["location"] =
+    cmStrCat(lfc.FilePath, ':', std::to_string(lfc.Line));
+  this->StartEntry("script", lff.LowerCaseName(), std::move(argsValue));
+}
+
+void cmMakefileProfilingData::StartEntry(const std::string& category,
+                                         const std::string& name,
+                                         cm::optional<Json::Value> args)
+{
   /* Do not try again if we previously failed to write to output. */
   if (!this->ProfileStream.good()) {
     return;
@@ -58,24 +79,17 @@
     cmsys::SystemInformation info;
     Json::Value v;
     v["ph"] = "B";
-    v["name"] = lff.LowerCaseName();
-    v["cat"] = "cmake";
+    v["name"] = name;
+    v["cat"] = category;
     v["ts"] = static_cast<Json::Value::UInt64>(
       std::chrono::duration_cast<std::chrono::microseconds>(
         std::chrono::steady_clock::now().time_since_epoch())
         .count());
     v["pid"] = static_cast<int>(info.GetProcessId());
     v["tid"] = 0;
-    Json::Value argsValue;
-    if (!lff.Arguments().empty()) {
-      std::string args;
-      for (auto const& a : lff.Arguments()) {
-        args += (args.empty() ? "" : " ") + a.Value;
-      }
-      argsValue["functionArgs"] = args;
+    if (args) {
+      v["args"] = *std::move(args);
     }
-    argsValue["location"] = lfc.FilePath + ":" + std::to_string(lfc.Line);
-    v["args"] = argsValue;
 
     this->JsonWriter->write(v, &this->ProfileStream);
   } catch (std::ios_base::failure& fail) {
@@ -112,3 +126,27 @@
     cmSystemTools::Error("Error writing profiling output!");
   }
 }
+
+cmMakefileProfilingData::RAII::RAII(RAII&& other) noexcept
+  : Data(other.Data)
+{
+  other.Data = nullptr;
+}
+
+cmMakefileProfilingData::RAII::~RAII()
+{
+  if (this->Data) {
+    this->Data->StopEntry();
+  }
+}
+
+cmMakefileProfilingData::RAII& cmMakefileProfilingData::RAII::operator=(
+  RAII&& other) noexcept
+{
+  if (this->Data) {
+    this->Data->StopEntry();
+  }
+  this->Data = other.Data;
+  other.Data = nullptr;
+  return *this;
+}
diff --git a/Source/cmMakefileProfilingData.h b/Source/cmMakefileProfilingData.h
index a86764a..e8d7dfa 100644
--- a/Source/cmMakefileProfilingData.h
+++ b/Source/cmMakefileProfilingData.h
@@ -3,6 +3,11 @@
 #pragma once
 #include <memory>
 #include <string>
+#include <utility>
+
+#include <cm/optional>
+
+#include <cm3p/json/value.h> // IWYU pragma: keep
 
 #include "cmsys/FStream.hxx"
 
@@ -19,8 +24,33 @@
   cmMakefileProfilingData(const std::string&);
   ~cmMakefileProfilingData() noexcept;
   void StartEntry(const cmListFileFunction& lff, cmListFileContext const& lfc);
+  void StartEntry(const std::string& category, const std::string& name,
+                  cm::optional<Json::Value> args = cm::nullopt);
   void StopEntry();
 
+  class RAII
+  {
+  public:
+    RAII() = delete;
+    RAII(const RAII&) = delete;
+    RAII(RAII&&) noexcept;
+
+    template <typename... Args>
+    RAII(cmMakefileProfilingData& data, Args&&... args)
+      : Data(&data)
+    {
+      this->Data->StartEntry(std::forward<Args>(args)...);
+    }
+
+    ~RAII();
+
+    RAII& operator=(const RAII&) = delete;
+    RAII& operator=(RAII&&) noexcept;
+
+  private:
+    cmMakefileProfilingData* Data = nullptr;
+  };
+
 private:
   cmsys::ofstream ProfileStream;
   std::unique_ptr<Json::StreamWriter> JsonWriter;
diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx
index d19bbb9..c5c5490 100644
--- a/Source/cmMakefileTargetGenerator.cxx
+++ b/Source/cmMakefileTargetGenerator.cxx
@@ -1031,7 +1031,7 @@
       }
 
       this->GlobalGenerator->AddCXXCompileCommand(
-        source.GetFullPath(), workingDirectory, compileCommand);
+        source.GetFullPath(), workingDirectory, compileCommand, relativeObj);
     }
 
     // See if we need to use a compiler launcher like ccache or distcc
diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx
index bda8a5f..895a4c3 100644
--- a/Source/cmNinjaNormalTargetGenerator.cxx
+++ b/Source/cmNinjaNormalTargetGenerator.cxx
@@ -372,7 +372,6 @@
       vars.SwiftLibraryName = "$SWIFT_LIBRARY_NAME";
       vars.SwiftModule = "$SWIFT_MODULE";
       vars.SwiftModuleName = "$SWIFT_MODULE_NAME";
-      vars.SwiftOutputFileMap = "$SWIFT_OUTPUT_FILE_MAP";
       vars.SwiftSources = "$SWIFT_SOURCES";
 
       vars.Defines = "$DEFINES";
@@ -1072,12 +1071,6 @@
         cmOutputConverter::SHELL);
     }(vars["SWIFT_MODULE_NAME"]);
 
-    const std::string map = cmStrCat(gt->GetSupportDirectory(), '/', config,
-                                     '/', "output-file-map.json");
-    vars["SWIFT_OUTPUT_FILE_MAP"] =
-      this->GetLocalGenerator()->ConvertToOutputFormat(
-        this->ConvertToNinjaPath(map), cmOutputConverter::SHELL);
-
     vars["SWIFT_SOURCES"] = [this, config]() -> std::string {
       std::vector<cmSourceFile const*> sources;
       std::stringstream oss;
@@ -1101,6 +1094,7 @@
     vars["DEFINES"] = this->GetDefines("Swift", config);
     vars["FLAGS"] = this->GetFlags("Swift", config);
     vars["INCLUDES"] = this->GetIncludes("Swift", config);
+    this->GenerateSwiftOutputFileMap(config, vars["FLAGS"]);
   }
 
   // Compute specific libraries to link with.
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index e4427f5..fba0ff9 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -1177,30 +1177,42 @@
   }
 
   this->GetImplFileStream(fileConfig) << "\n";
+}
 
-  if (!this->Configs[config].SwiftOutputMap.empty()) {
-    std::string const mapFilePath =
-      cmStrCat(this->GeneratorTarget->GetSupportDirectory(), '/', config, '/',
-               "output-file-map.json");
-    std::string const targetSwiftDepsPath = [this, config]() -> std::string {
-      cmGeneratorTarget const* target = this->GeneratorTarget;
-      if (cmValue name = target->GetProperty("Swift_DEPENDENCIES_FILE")) {
-        return *name;
-      }
-      return this->ConvertToNinjaPath(
-        cmStrCat(target->GetSupportDirectory(), '/', config, '/',
-                 target->GetName(), ".swiftdeps"));
-    }();
-
-    // build the global target dependencies
-    // https://github.com/apple/swift/blob/master/docs/Driver.md#output-file-maps
-    Json::Value deps(Json::objectValue);
-    deps["swift-dependencies"] = targetSwiftDepsPath;
-    this->Configs[config].SwiftOutputMap[""] = deps;
-
-    cmGeneratedFileStream output(mapFilePath);
-    output << this->Configs[config].SwiftOutputMap;
+void cmNinjaTargetGenerator::GenerateSwiftOutputFileMap(
+  const std::string& config, std::string& flags)
+{
+  if (this->Configs[config].SwiftOutputMap.empty()) {
+    return;
   }
+
+  std::string const targetSwiftDepsPath = [this, config]() -> std::string {
+    cmGeneratorTarget const* target = this->GeneratorTarget;
+    if (cmValue name = target->GetProperty("Swift_DEPENDENCIES_FILE")) {
+      return *name;
+    }
+    return this->ConvertToNinjaPath(cmStrCat(target->GetSupportDirectory(),
+                                             '/', config, '/',
+                                             target->GetName(), ".swiftdeps"));
+  }();
+
+  std::string mapFilePath =
+    cmStrCat(this->GeneratorTarget->GetSupportDirectory(), '/', config, '/',
+             "output-file-map.json");
+
+  // build the global target dependencies
+  // https://github.com/apple/swift/blob/master/docs/Driver.md#output-file-maps
+  Json::Value deps(Json::objectValue);
+  deps["swift-dependencies"] = targetSwiftDepsPath;
+  this->Configs[config].SwiftOutputMap[""] = deps;
+
+  cmGeneratedFileStream output(mapFilePath);
+  output << this->Configs[config].SwiftOutputMap;
+
+  // Add flag
+  this->LocalGenerator->AppendFlags(flags, "-output-file-map");
+  this->LocalGenerator->AppendFlagEscape(flags,
+                                         ConvertToNinjaPath(mapFilePath));
 }
 
 namespace {
@@ -1998,7 +2010,8 @@
   std::string cmdLine = this->GetLocalGenerator()->BuildCommandLine(
     compileCmds, outputConfig, outputConfig);
 
-  this->GetGlobalGenerator()->AddCXXCompileCommand(cmdLine, sourceFileName);
+  this->GetGlobalGenerator()->AddCXXCompileCommand(cmdLine, sourceFileName,
+                                                   objectFileName);
 }
 
 void cmNinjaTargetGenerator::AdditionalCleanFiles(const std::string& config)
diff --git a/Source/cmNinjaTargetGenerator.h b/Source/cmNinjaTargetGenerator.h
index 4b4cf8d..c43b650 100644
--- a/Source/cmNinjaTargetGenerator.h
+++ b/Source/cmNinjaTargetGenerator.h
@@ -163,6 +163,9 @@
   void EmitSwiftDependencyInfo(cmSourceFile const* source,
                                const std::string& config);
 
+  void GenerateSwiftOutputFileMap(const std::string& config,
+                                  std::string& flags);
+
   void ExportObjectCompileCommand(
     std::string const& language, std::string const& sourceFileName,
     std::string const& objectDir, std::string const& objectFileName,
diff --git a/Source/cmRulePlaceholderExpander.cxx b/Source/cmRulePlaceholderExpander.cxx
index b63d11c..638bb42 100644
--- a/Source/cmRulePlaceholderExpander.cxx
+++ b/Source/cmRulePlaceholderExpander.cxx
@@ -119,11 +119,6 @@
       return this->ReplaceValues->SwiftModuleName;
     }
   }
-  if (this->ReplaceValues->SwiftOutputFileMap) {
-    if (variable == "SWIFT_OUTPUT_FILE_MAP") {
-      return this->ReplaceValues->SwiftOutputFileMap;
-    }
-  }
   if (this->ReplaceValues->SwiftSources) {
     if (variable == "SWIFT_SOURCES") {
       return this->ReplaceValues->SwiftSources;
diff --git a/Source/cmRulePlaceholderExpander.h b/Source/cmRulePlaceholderExpander.h
index 23ec405..5d1f199 100644
--- a/Source/cmRulePlaceholderExpander.h
+++ b/Source/cmRulePlaceholderExpander.h
@@ -64,7 +64,7 @@
     const char* SwiftLibraryName = nullptr;
     const char* SwiftModule = nullptr;
     const char* SwiftModuleName = nullptr;
-    const char* SwiftOutputFileMap = nullptr;
+    const char* SwiftOutputFileMapOption = nullptr;
     const char* SwiftSources = nullptr;
     const char* ISPCHeader = nullptr;
     const char* CudaCompileMode = nullptr;
diff --git a/Source/cmState.cxx b/Source/cmState.cxx
index e54ccfc..f12f91f 100644
--- a/Source/cmState.cxx
+++ b/Source/cmState.cxx
@@ -786,6 +786,8 @@
       return "CTEST";
     case CPack:
       return "CPACK";
+    case Help:
+      return "HELP";
     case Unknown:
       return "UNKNOWN";
   }
diff --git a/Source/cmState.h b/Source/cmState.h
index 2d0c521..9a17b22 100644
--- a/Source/cmState.h
+++ b/Source/cmState.h
@@ -53,6 +53,7 @@
     FindPackage,
     CTest,
     CPack,
+    Help
   };
 
   enum class ProjectKind
diff --git a/Source/cmTimestamp.cxx b/Source/cmTimestamp.cxx
index 677fdb6..7e47b4e 100644
--- a/Source/cmTimestamp.cxx
+++ b/Source/cmTimestamp.cxx
@@ -128,8 +128,8 @@
                                             : static_cast<char>(0);
 
     if (c1 == '%' && c2 != 0) {
-      result +=
-        this->AddTimestampComponent(c2, timeStruct, timeT, microseconds);
+      result += this->AddTimestampComponent(c2, timeStruct, timeT, utcFlag,
+                                            microseconds);
       ++i;
     } else {
       result += c1;
@@ -179,7 +179,7 @@
 }
 
 std::string cmTimestamp::AddTimestampComponent(
-  char flag, struct tm& timeStruct, const time_t timeT,
+  char flag, struct tm& timeStruct, const time_t timeT, const bool utcFlag,
   const uint32_t microseconds) const
 {
   std::string formatString = cmStrCat('%', flag);
@@ -203,6 +203,63 @@
     case 'Y':
     case '%':
       break;
+    case 'Z':
+#if defined(__GLIBC__)
+      // 'struct tm' has the time zone, so strftime can honor UTC.
+      static_cast<void>(utcFlag);
+#else
+      // 'struct tm' may not have the time zone, so strftime may
+      // use local time.  Hard-code the UTC result.
+      if (utcFlag) {
+        return std::string("GMT");
+      }
+#endif
+      break;
+    case 'z': {
+#if defined(__GLIBC__)
+      // 'struct tm' has the time zone, so strftime can honor UTC.
+      static_cast<void>(utcFlag);
+#else
+      // 'struct tm' may not have the time zone, so strftime may
+      // use local time.  Hard-code the UTC result.
+      if (utcFlag) {
+        return std::string("+0000");
+      }
+#endif
+#ifndef _AIX
+      break;
+#else
+      std::string xpg_sus_old;
+      bool const xpg_sus_was_set =
+        cmSystemTools::GetEnv("XPG_SUS_ENV", xpg_sus_old);
+      if (xpg_sus_was_set && xpg_sus_old == "ON") {
+        break;
+      }
+      xpg_sus_old = "XPG_SUS_ENV=" + xpg_sus_old;
+
+      // On AIX systems, %z requires XPG_SUS_ENV=ON to work as desired.
+      cmSystemTools::PutEnv("XPG_SUS_ENV=ON");
+      tzset();
+
+      char buffer[16];
+      size_t size = strftime(buffer, sizeof(buffer), "%z", &timeStruct);
+
+#  ifndef CMAKE_BOOTSTRAP
+      if (xpg_sus_was_set) {
+        cmSystemTools::PutEnv(xpg_sus_old);
+      } else {
+        cmSystemTools::UnsetEnv("XPG_SUS_ENV");
+      }
+#  else
+      // No UnsetEnv during bootstrap.  This is good enough for CMake itself.
+      cmSystemTools::PutEnv(xpg_sus_old);
+      static_cast<void>(xpg_sus_was_set);
+#  endif
+      tzset();
+
+      return std::string(buffer, size);
+#endif
+    }
     case 's': // Seconds since UNIX epoch (midnight 1-jan-1970)
     {
       // Build a time_t for UNIX epoch and subtract from the input "timeT":
diff --git a/Source/cmTimestamp.h b/Source/cmTimestamp.h
index ada5006..05c6342 100644
--- a/Source/cmTimestamp.h
+++ b/Source/cmTimestamp.h
@@ -32,6 +32,6 @@
   time_t CreateUtcTimeTFromTm(struct tm& timeStruct) const;
 
   std::string AddTimestampComponent(char flag, struct tm& timeStruct,
-                                    time_t timeT,
-                                    uint32_t microseconds = 0) const;
+                                    time_t timeT, bool utcFlag,
+                                    uint32_t microseconds) const;
 };
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index 4cfb561..c982713 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -3316,9 +3316,12 @@
     }
   }
 
-  if (this->ProjectType != VsProjectType::csproj && clOptions.IsManaged()) {
+  if (this->ProjectType != VsProjectType::csproj &&
+      (clOptions.IsManaged() || clOptions.HasFlag("CLRSupport"))) {
     this->Managed = true;
-    std::string managedType = clOptions.GetFlag("CompileAsManaged");
+    std::string managedType = clOptions.HasFlag("CompileAsManaged")
+      ? clOptions.GetFlag("CompileAsManaged")
+      : "Mixed";
     if (managedType == "Safe" || managedType == "Pure") {
       // force empty calling convention if safe clr is used
       clOptions.AddFlag("CallingConvention", "");
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index 013a87b..36c0089 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -196,7 +196,7 @@
     this->AddProjectCommands();
   }
 
-  if (mode == cmState::Project) {
+  if (mode == cmState::Project || mode == cmState::Help) {
     this->LoadEnvironmentPresets();
   }
 
@@ -1542,6 +1542,16 @@
   }
 }
 
+void cmake::SetTraceRedirect(cmake* other)
+{
+  this->Trace = other->Trace;
+  this->TraceExpand = other->TraceExpand;
+  this->TraceFormatVar = other->TraceFormatVar;
+  this->TraceOnlyThisSources = other->TraceOnlyThisSources;
+
+  this->TraceRedirect = other;
+}
+
 bool cmake::SetDirectoriesFromFile(const std::string& arg)
 {
   // Check if the argument refers to a CMakeCache.txt or
@@ -2060,6 +2070,10 @@
 
 int cmake::Configure()
 {
+#if !defined(CMAKE_BOOTSTRAP)
+  auto profilingRAII = this->CreateProfilingEntry("project", "configure");
+#endif
+
   DiagLevel diagLevel;
 
   if (this->DiagLevels.count("deprecated") == 1) {
@@ -2572,6 +2586,11 @@
   if (!this->GlobalGenerator) {
     return -1;
   }
+
+#if !defined(CMAKE_BOOTSTRAP)
+  auto profilingRAII = this->CreateProfilingEntry("project", "generate");
+#endif
+
   if (!this->GlobalGenerator->Compute()) {
     return -1;
   }
diff --git a/Source/cmake.h b/Source/cmake.h
index 3183577..2f7f7bd 100644
--- a/Source/cmake.h
+++ b/Source/cmake.h
@@ -33,6 +33,7 @@
 #  include <cm3p/json/value.h>
 
 #  include "cmCMakePresetsGraph.h"
+#  include "cmMakefileProfilingData.h"
 #endif
 
 class cmExternalMakefileProjectGeneratorFactory;
@@ -41,9 +42,6 @@
 class cmGlobalGenerator;
 class cmGlobalGeneratorFactory;
 class cmMakefile;
-#if !defined(CMAKE_BOOTSTRAP)
-class cmMakefileProfilingData;
-#endif
 class cmMessenger;
 class cmVariableWatch;
 struct cmBuildOptions;
@@ -513,10 +511,19 @@
   {
     return this->TraceOnlyThisSources;
   }
-  cmGeneratedFileStream& GetTraceFile() { return this->TraceFile; }
+  cmGeneratedFileStream& GetTraceFile()
+  {
+    if (this->TraceRedirect) {
+      return this->TraceRedirect->GetTraceFile();
+    }
+    return this->TraceFile;
+  }
   void SetTraceFile(std::string const& file);
   void PrintTraceFormatVersion();
 
+  //! Use trace from another ::cmake instance.
+  void SetTraceRedirect(cmake* other);
+
   bool GetWarnUninitialized() const { return this->WarnUninitialized; }
   void SetWarnUninitialized(bool b) { this->WarnUninitialized = b; }
   bool GetWarnUnusedCli() const { return this->WarnUnusedCli; }
@@ -630,6 +637,17 @@
 #if !defined(CMAKE_BOOTSTRAP)
   cmMakefileProfilingData& GetProfilingOutput();
   bool IsProfilingEnabled() const;
+
+  template <typename... Args>
+  cm::optional<cmMakefileProfilingData::RAII> CreateProfilingEntry(
+    Args&&... args)
+  {
+    if (this->IsProfilingEnabled()) {
+      return cm::make_optional<cmMakefileProfilingData::RAII>(
+        this->GetProfilingOutput(), std::forward<Args>(args)...);
+    }
+    return cm::nullopt;
+  }
 #endif
 
 protected:
@@ -688,6 +706,7 @@
   bool TraceExpand = false;
   TraceFormat TraceFormatVar = TRACE_HUMAN;
   cmGeneratedFileStream TraceFile;
+  cmake* TraceRedirect = nullptr;
   bool WarnUninitialized = false;
   bool WarnUnusedCli = true;
   bool CheckSystemVars = false;
diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx
index 723932e..43bebc1 100644
--- a/Source/cmakemain.cxx
+++ b/Source/cmakemain.cxx
@@ -208,7 +208,7 @@
   doc.addCMakeStandardDocSections();
   if (doc.CheckOptions(ac, av, "--")) {
     // Construct and print requested documentation.
-    cmake hcm(cmake::RoleInternal, cmState::Unknown);
+    cmake hcm(cmake::RoleInternal, cmState::Help);
     hcm.SetHomeDirectory("");
     hcm.SetHomeOutputDirectory("");
     hcm.AddCMakePaths();
diff --git a/Source/kwsys/ProcessUNIX.c b/Source/kwsys/ProcessUNIX.c
index 45a9e6f..b25b258 100644
--- a/Source/kwsys/ProcessUNIX.c
+++ b/Source/kwsys/ProcessUNIX.c
@@ -2011,6 +2011,14 @@
   return 0;
 }
 
+#if defined(__clang__) && defined(__has_warning)
+#  if __has_warning("-Wshorten-64-to-32")
+#    pragma clang diagnostic push
+#    pragma clang diagnostic ignored "-Wshorten-64-to-32"
+#    define KWSYSPE_CLANG_DIAG_WSHORTEN
+#  endif
+#endif
+
 /* Get the length of time before the given timeout time arrives.
    Returns 1 if the time has already arrived, and 0 otherwise.  */
 static int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime,
@@ -2061,6 +2069,11 @@
   return current;
 }
 
+#if defined(KWSYSPE_CLANG_DIAG_WSHORTEN)
+#  undef KWSYSPE_CLANG_DIAG_WSHORTEN
+#  pragma clang diagnostic pop
+#endif
+
 static double kwsysProcessTimeToDouble(kwsysProcessTime t)
 {
   return (double)t.tv_sec + (double)(t.tv_usec) * 0.000001;
diff --git a/Source/kwsys/Status.hxx.in b/Source/kwsys/Status.hxx.in
index 16efaef..7cef029 100644
--- a/Source/kwsys/Status.hxx.in
+++ b/Source/kwsys/Status.hxx.in
@@ -7,6 +7,16 @@
 
 #include <string>
 
+/*
+ * Detect a symbol collision with the name of this class. X11 headers use
+ * `#define Status int` instead of using `typedef` which poisons any other
+ * usage of this name.
+ */
+#if defined(Status) && defined(_X11_XLIB_H_)
+#  error                                                                      \
+    "Status.hxx must be included *before* any X11 headers to avoid a collision with the `Status` define that is made in its API."
+#endif
+
 namespace @KWSYS_NAMESPACE@ {
 
 /** \class Status
diff --git a/Source/kwsys/SystemInformation.cxx b/Source/kwsys/SystemInformation.cxx
index e6cc48f..20e2edb 100644
--- a/Source/kwsys/SystemInformation.cxx
+++ b/Source/kwsys/SystemInformation.cxx
@@ -482,7 +482,7 @@
                                        unsigned int); // For windows
 
   // For Linux and Cygwin, /proc/cpuinfo formats are slightly different
-  bool RetreiveInformationFromCpuInfoFile();
+  bool RetrieveInformationFromCpuInfoFile();
   std::string ExtractValueFromCpuInfoFile(std::string buffer, const char* word,
                                           size_t init = 0);
 
@@ -1520,7 +1520,7 @@
 #elif defined(__hpux)
   this->QueryHPUXProcessor();
 #elif defined(__linux) || defined(__CYGWIN__)
-  this->RetreiveInformationFromCpuInfoFile();
+  this->RetrieveInformationFromCpuInfoFile();
 #else
   this->QueryProcessor();
 #endif
@@ -3435,7 +3435,7 @@
 }
 
 /** Query for the cpu status */
-bool SystemInformationImplementation::RetreiveInformationFromCpuInfoFile()
+bool SystemInformationImplementation::RetrieveInformationFromCpuInfoFile()
 {
   this->NumberOfLogicalCPU = 0;
   this->NumberOfPhysicalCPU = 0;
diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx
index a20901c..fdd6b2d 100644
--- a/Source/kwsys/SystemTools.cxx
+++ b/Source/kwsys/SystemTools.cxx
@@ -36,6 +36,7 @@
 
 #ifdef _WIN32
 #  include <cwchar>
+#  include <unordered_map>
 #endif
 
 // Work-around CMake dependency scanning limitation.  This must
@@ -506,16 +507,39 @@
 };
 
 #ifdef _WIN32
-struct SystemToolsPathCaseCmp
+#  if defined(_WIN64)
+static constexpr size_t FNV_OFFSET_BASIS = 14695981039346656037ULL;
+static constexpr size_t FNV_PRIME = 1099511628211ULL;
+#  else
+static constexpr size_t FNV_OFFSET_BASIS = 2166136261U;
+static constexpr size_t FNV_PRIME = 16777619U;
+#  endif
+
+// Case insensitive Fnv1a hash
+struct SystemToolsPathCaseHash
+{
+  size_t operator()(std::string const& path) const
+  {
+    size_t hash = FNV_OFFSET_BASIS;
+    for (auto c : path) {
+      hash ^= static_cast<size_t>(std::tolower(c));
+      hash *= FNV_PRIME;
+    }
+
+    return hash;
+  }
+};
+
+struct SystemToolsPathCaseEqual
 {
   bool operator()(std::string const& l, std::string const& r) const
   {
 #  ifdef _MSC_VER
-    return _stricmp(l.c_str(), r.c_str()) < 0;
+    return _stricmp(l.c_str(), r.c_str()) == 0;
 #  elif defined(__GNUC__)
-    return strcasecmp(l.c_str(), r.c_str()) < 0;
+    return strcasecmp(l.c_str(), r.c_str()) == 0;
 #  else
-    return SystemTools::Strucmp(l.c_str(), r.c_str()) < 0;
+    return SystemTools::Strucmp(l.c_str(), r.c_str()) == 0;
 #  endif
   }
 };
@@ -540,8 +564,12 @@
                                      bool const cache);
   static std::string GetActualCaseForPathCached(std::string const& path);
   static const char* GetEnvBuffered(const char* key);
-  std::map<std::string, std::string, SystemToolsPathCaseCmp> FindFileMap;
-  std::map<std::string, std::string, SystemToolsPathCaseCmp> PathCaseMap;
+  std::unordered_map<std::string, std::string, SystemToolsPathCaseHash,
+                     SystemToolsPathCaseEqual>
+    FindFileMap;
+  std::unordered_map<std::string, std::string, SystemToolsPathCaseHash,
+                     SystemToolsPathCaseEqual>
+    PathCaseMap;
   std::map<std::string, std::string> EnvMap;
 #endif
 #ifdef __CYGWIN__
diff --git a/Templates/MSBuild/FlagTables/v142_CL.json b/Templates/MSBuild/FlagTables/v142_CL.json
index c76c040..4f2dce8 100644
--- a/Templates/MSBuild/FlagTables/v142_CL.json
+++ b/Templates/MSBuild/FlagTables/v142_CL.json
@@ -56,6 +56,13 @@
     "flags": []
   },
   {
+    "name": "CLRSupport",
+    "switch": "clr:netcore",
+    "comment": ".NET Core Runtime Support",
+    "value": "NetCore",
+    "flags": []
+  },
+  {
     "name": "WarningLevel",
     "switch": "W0",
     "comment": "Turn Off All Warnings",
diff --git a/Templates/MSBuild/FlagTables/v143_CL.json b/Templates/MSBuild/FlagTables/v143_CL.json
index 993fbf1..119e171 100644
--- a/Templates/MSBuild/FlagTables/v143_CL.json
+++ b/Templates/MSBuild/FlagTables/v143_CL.json
@@ -56,6 +56,13 @@
     "flags": []
   },
   {
+    "name": "CLRSupport",
+    "switch": "clr:netcore",
+    "comment": ".NET Core Runtime Support",
+    "value": "NetCore",
+    "flags": []
+  },
+  {
     "name": "WarningLevel",
     "switch": "W0",
     "comment": "Turn Off All Warnings",
diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt
index 6e35df9..112455b 100644
--- a/Tests/CMakeLists.txt
+++ b/Tests/CMakeLists.txt
@@ -271,14 +271,6 @@
     find_package(Qt5Widgets QUIET NO_MODULE)
   endif()
 
-  if(NOT CMake_TEST_EXTERNAL_CMAKE)
-    add_subdirectory(CMakeLib)
-  endif()
-  add_subdirectory(CMakeOnly)
-  add_subdirectory(RunCMake)
-
-  add_subdirectory(FindPackageModeMakefileTest)
-
   # Collect a list of all test build directories.
   set(TEST_BUILD_DIRS)
 
@@ -342,6 +334,27 @@
     endif()
   endif()
 
+  if(CMake_TEST_XCODE_VERSION AND CMAKE_OSX_SDKVERSION AND CMAKE_OSX_SDKPRODUCT)
+    if((NOT CMake_TEST_XCODE_VERSION VERSION_LESS 6.1) AND
+      ((NOT CMAKE_OSX_SDKPRODUCT STREQUAL "Mac OS X") OR
+      (NOT CMAKE_OSX_SDKVERSION VERSION_LESS 10.10)))
+      if(CMAKE_GENERATOR STREQUAL "Xcode")
+        set(CMake_TEST_XCODE_SWIFT 1)
+      endif()
+    endif()
+  endif()
+  if(NOT DEFINED CMake_TEST_Swift)
+    if(CMAKE_Swift_COMPILER OR CMake_TEST_XCODE_SWIFT)
+      set(CMake_TEST_Swift 1)
+    endif()
+  endif()
+
+  if(NOT DEFINED CMake_TEST_OBJC)
+    if(APPLE AND CMAKE_C_COMPILER_ID MATCHES "Clang|GNU")
+      set(CMake_TEST_OBJC 1)
+    endif()
+  endif()
+
   # Use 1500 or CTEST_TEST_TIMEOUT for long test timeout value,
   # whichever is greater.
   set(CMAKE_LONG_TEST_TIMEOUT 1500)
@@ -352,6 +365,14 @@
     set(CMAKE_LONG_TEST_TIMEOUT 1500)
   endif()
 
+  if(NOT CMake_TEST_EXTERNAL_CMAKE)
+    add_subdirectory(CMakeLib)
+  endif()
+  add_subdirectory(CMakeOnly)
+  add_subdirectory(RunCMake)
+
+  add_subdirectory(FindPackageModeMakefileTest)
+
   add_test(NAME CMake.Copyright
     COMMAND ${CMAKE_CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/CMakeCopyright.cmake)
 
@@ -380,16 +401,7 @@
   ADD_TEST_MACRO(MissingSourceFile MissingSourceFile)
   set_tests_properties(MissingSourceFile PROPERTIES
     PASS_REGULAR_EXPRESSION "CMake Error at CMakeLists.txt:3 \\(add_executable\\):[ \r\n]*Cannot find source file:[ \r\n]*DoesNotExist/MissingSourceFile.c")
-  if(CMake_TEST_XCODE_VERSION AND CMAKE_OSX_SDKVERSION AND CMAKE_OSX_SDKPRODUCT)
-    if((NOT CMake_TEST_XCODE_VERSION VERSION_LESS 6.1) AND
-       ((NOT CMAKE_OSX_SDKPRODUCT STREQUAL "Mac OS X") OR
-        (NOT CMAKE_OSX_SDKVERSION VERSION_LESS 10.10)))
-      if(CMAKE_GENERATOR STREQUAL "Xcode")
-        set(CMake_TEST_XCODE_SWIFT 1)
-      endif()
-    endif()
-  endif()
-  if(CMAKE_Swift_COMPILER OR CMake_TEST_XCODE_SWIFT)
+  if(CMake_TEST_Swift)
     ADD_TEST_MACRO(SwiftOnly SwiftOnly)
     if(CMake_TEST_XCODE_SWIFT)
       ADD_TEST_MACRO(SwiftMix SwiftMix)
@@ -432,6 +444,11 @@
     endif()
   endif()
 
+  if(CMake_TEST_OBJC)
+    add_subdirectory(ObjC)
+    add_subdirectory(ObjCXX)
+  endif()
+
   if(${CMAKE_GENERATOR} MATCHES "Visual Studio ([^9]|[9][0-9])")
     ADD_TEST_MACRO(CSharpOnly CSharpOnly)
     if(NOT CMAKE_VS_PLATFORM_NAME STREQUAL "ARM64")
@@ -2500,9 +2517,6 @@
         -Dgen=${CMAKE_GENERATOR}
         -P ${CMake_SOURCE_DIR}/Tests/CFBundleTest/VerifyResult.cmake)
       list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/CFBundleTest")
-
-      add_subdirectory(ObjC)
-      add_subdirectory(ObjCXX)
     endif()
   endif()
 
diff --git a/Tests/CMakeTests/String-TIMESTAMP-TimeZone.cmake b/Tests/CMakeTests/String-TIMESTAMP-TimeZone.cmake
new file mode 100644
index 0000000..eb2eb42
--- /dev/null
+++ b/Tests/CMakeTests/String-TIMESTAMP-TimeZone.cmake
@@ -0,0 +1,22 @@
+string(TIMESTAMP output "%z")
+
+STRING(LENGTH output output_length)
+
+message("~${output}~")
+
+set(expected_output_length 6)
+
+if(NOT(${output_length} EQUAL ${expected_output_length}))
+    message(FATAL_ERROR "expected ${expected_output_length} entries in output with all specifiers; found ${output_length}")
+endif()
+
+string(SUBSTRING ${output} 0 1 output0)
+string(SUBSTRING ${output} 4 1 output4)
+
+if(NOT((${output0} STREQUAL "-") OR (${output0} STREQUAL "+")))
+    message(FATAL_ERROR "expected output[0] equ '+' or '-'; found: '${output0}'")
+endif()
+
+if(NOT((${output4} STREQUAL "0") OR (${output4} STREQUAL "5")))
+    message(FATAL_ERROR "expected output[4] equ '0' or '5'; found: '${output4}'")
+endif()
diff --git a/Tests/CMakeTests/StringTest.cmake.in b/Tests/CMakeTests/StringTest.cmake.in
index 154afa7..5f8b111 100644
--- a/Tests/CMakeTests/StringTest.cmake.in
+++ b/Tests/CMakeTests/StringTest.cmake.in
@@ -44,6 +44,8 @@
 set(TIMESTAMP-IncompleteSpecifier-STDERR "~foobar%~")
 set(TIMESTAMP-AllSpecifiers-RESULT 0)
 set(TIMESTAMP-AllSpecifiers-STDERR "~[0-9]+(;[0-9]+)*~")
+set(TIMESTAMP-TimeZone-RESULT 0)
+set(TIMESTAMP-TimeZone-STDERR "~[-,+][0-9][0-9][0-9][0-9]~")
 set(TIMESTAMP-MonthWeekNames-RESULT 0)
 set(TIMESTAMP-MonthWeekNames-STDERR "~[^%]+;[^%]+~")
 set(TIMESTAMP-UnixTime-RESULT 0)
@@ -75,6 +77,7 @@
   TIMESTAMP-IncompleteSpecifier
   TIMESTAMP-AllSpecifiers
   TIMESTAMP-MonthWeekNames
+  TIMESTAMP-TimeZone
   TIMESTAMP-UnixTime
   )
 
diff --git a/Tests/CheckSourceTree/check.cmake b/Tests/CheckSourceTree/check.cmake
index c2e3529..6341bd6 100644
--- a/Tests/CheckSourceTree/check.cmake
+++ b/Tests/CheckSourceTree/check.cmake
@@ -3,6 +3,14 @@
   set(ENV{HOME} "$ENV{CTEST_REAL_HOME}")
 endif()
 
+file(GLOB known_files
+  "${CMake_SOURCE_DIR}/Tests/JavaExportImport/InstallExport/hs_err_pid*.log"
+  "${CMake_SOURCE_DIR}/Tests/JavaNativeHeaders/hs_err_pid*.log"
+  )
+if(known_files)
+  file(REMOVE ${known_files})
+endif()
+
 execute_process(
   COMMAND "${GIT_EXECUTABLE}" status
   WORKING_DIRECTORY "${CMake_SOURCE_DIR}"
diff --git a/Tests/CustomCommandByproducts/CMakeLists.txt b/Tests/CustomCommandByproducts/CMakeLists.txt
index 08c897c..e391a6f 100644
--- a/Tests/CustomCommandByproducts/CMakeLists.txt
+++ b/Tests/CustomCommandByproducts/CMakeLists.txt
@@ -149,6 +149,29 @@
   ${binary_dir}${cfg}/${CMAKE_STATIC_LIBRARY_PREFIX}ExternalLibrary${CMAKE_STATIC_LIBRARY_SUFFIX})
 add_dependencies(ExternalLibraryWithSubstitution ExtTargetSubst)
 
+# Generate the library file of an imported target as an install byproduct
+# of an external project. The byproduct uses <INSTALL_DIR> that is substituted
+# by the real install path
+if(_isMultiConfig)
+  set(cfg /${CMAKE_CFG_INTDIR})
+else()
+  set(cfg)
+endif()
+include(ExternalProject)
+ExternalProject_Add(ExtTargetInstallSubst
+  SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/External"
+  DOWNLOAD_COMMAND ""
+  INSTALL_COMMAND
+    "${CMAKE_COMMAND}" -E copy_directory "<BINARY_DIR>${cfg}" "<INSTALL_DIR>${cfg}"
+  BUILD_BYPRODUCTS "<BINARY_DIR>${cfg}/${CMAKE_STATIC_LIBRARY_PREFIX}ExternalLibrary${CMAKE_STATIC_LIBRARY_SUFFIX}"
+  INSTALL_BYPRODUCTS "<INSTALL_DIR>${cfg}/${CMAKE_STATIC_LIBRARY_PREFIX}ExternalLibrary${CMAKE_STATIC_LIBRARY_SUFFIX}"
+  )
+ExternalProject_Get_Property(ExtTargetInstallSubst install_dir)
+add_library(ExternalLibraryWithInstallDirSubstitution STATIC IMPORTED)
+set_property(TARGET ExternalLibraryWithInstallDirSubstitution PROPERTY IMPORTED_LOCATION
+  ${install_dir}${cfg}/${CMAKE_STATIC_LIBRARY_PREFIX}ExternalLibrary${CMAKE_STATIC_LIBRARY_SUFFIX})
+add_dependencies(ExternalLibraryWithInstallDirSubstitution ExtTargetInstallSubst)
+
 # Add an executable consuming all the byproducts.
 add_executable(CustomCommandByproducts
   CustomCommandByproducts.c
@@ -169,6 +192,18 @@
 
 target_link_libraries(CustomCommandByproducts ExternalLibrary)
 
+add_executable(ExternalLibraryByproducts ExternalLibraryByproducts.c)
+target_link_libraries(ExternalLibraryByproducts ExternalLibrary)
+
+add_executable(ExternalLibraryByproducts_WithSubstitution ExternalLibraryByproducts.c)
+target_link_libraries(ExternalLibraryByproducts_WithSubstitution ExternalLibraryWithSubstitution)
+
+add_executable(ExternalLibraryByproducts_WithInstallDirSubstitution ExternalLibraryByproducts.c)
+target_link_libraries(
+  ExternalLibraryByproducts_WithInstallDirSubstitution
+  ExternalLibraryWithInstallDirSubstitution
+)
+
 if(CMAKE_GENERATOR STREQUAL "Ninja")
   add_custom_target(CheckNinja ALL
     COMMENT "Checking build.ninja"
diff --git a/Tests/CustomCommandByproducts/ExternalLibraryByproducts.c b/Tests/CustomCommandByproducts/ExternalLibraryByproducts.c
new file mode 100644
index 0000000..3588e53
--- /dev/null
+++ b/Tests/CustomCommandByproducts/ExternalLibraryByproducts.c
@@ -0,0 +1,5 @@
+extern int ExternalLibrary(void);
+int main(void)
+{
+  return (ExternalLibrary() + 1);
+}
diff --git a/Tests/GeneratorExpression/CMakeLists.txt b/Tests/GeneratorExpression/CMakeLists.txt
index ebbe288..6187966 100644
--- a/Tests/GeneratorExpression/CMakeLists.txt
+++ b/Tests/GeneratorExpression/CMakeLists.txt
@@ -261,13 +261,24 @@
   set(test_shell_path2 /shell/path /another/path)
 endif()
 
+set(test_shell_path_genex "$<SHELL_PATH:${test_shell_path}>")
+set(test_shell_path2_genex "$<SHELL_PATH:${test_shell_path2}>")
+if(msys1_prefix)
+  # Add a prefix to the value produced by the genex so that the path does
+  # not look absolute, thus suppressing conversion by MSYS 1.0 bash.
+  set(test_shell_path_genex "${msys1_prefix}${test_shell_path_genex}")
+  # There is no way to suppress conversion of the second path in
+  # MSYS 1.0 bash, so do the comparison at generate time instead.
+  set(test_shell_path2_genex "$<STREQUAL:${test_shell_path2_genex},/c/shell/path:/d/another/path>")
+endif()
+
 add_custom_target(check-part4 ALL
   COMMAND ${msys2_no_conv} ${CMAKE_COMMAND}
     # Prefix path to bypass its further conversion when being processed by
     # CMake as command-line argument
     -Dmsys1_prefix=${msys1_prefix}
-    -Dtest_shell_path=${msys1_prefix}$<SHELL_PATH:${test_shell_path}>
-    "-Dtest_shell_path2=$<SHELL_PATH:${test_shell_path2}>"
+    "-Dtest_shell_path=${test_shell_path_genex}"
+    "-Dtest_shell_path2=${test_shell_path2_genex}"
     -Dif_1=$<IF:1,a,b>
     -Dif_2=$<IF:0,a,b>
     -Dif_3=$<IF:$<EQUAL:10,30>,a,b>
diff --git a/Tests/GeneratorExpression/check-part4.cmake b/Tests/GeneratorExpression/check-part4.cmake
index a7e0944..28f3699 100644
--- a/Tests/GeneratorExpression/check-part4.cmake
+++ b/Tests/GeneratorExpression/check-part4.cmake
@@ -16,8 +16,13 @@
   check(test_shell_path [[/shell/path]])
 endif()
 if(WIN32)
-  if(CMAKE_GENERATOR STREQUAL "MSYS Makefiles" AND NOT msys1_prefix)
-    check(test_shell_path2 [[/c/shell/path:/d/another/path]])
+  if(CMAKE_GENERATOR STREQUAL "MSYS Makefiles")
+    if(msys1_prefix)
+      # The comparison was done at generate time with the STREQUAL genex.
+      check(test_shell_path2 [[1]])
+    else()
+      check(test_shell_path2 [[/c/shell/path:/d/another/path]])
+    endif()
   elseif(CMAKE_GENERATOR STREQUAL "Unix Makefiles")
     check(test_shell_path2 [[c:/shell/path;d:/another/path]])
   else()
diff --git a/Tests/RunCMake/CMP0104/CMP0104-OLD-stderr.txt b/Tests/RunCMake/CMP0104/CMP0104-OLD-stderr.txt
new file mode 100644
index 0000000..66d3016
--- /dev/null
+++ b/Tests/RunCMake/CMP0104/CMP0104-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0104-OLD.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0104 will be removed from a future version
+  of CMake.
+
+  The cmake-policies\(7\) manual explains that the OLD behaviors of all
+  policies are deprecated and that a policy should be set to OLD only under
+  specific short-term circumstances.  Projects should be ported to the NEW
+  behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/CMP0106/CMP0106-OLD-stderr.txt b/Tests/RunCMake/CMP0106/CMP0106-OLD-stderr.txt
new file mode 100644
index 0000000..ef48d5c
--- /dev/null
+++ b/Tests/RunCMake/CMP0106/CMP0106-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0106-OLD.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0106 will be removed from a future version
+  of CMake.
+
+  The cmake-policies\(7\) manual explains that the OLD behaviors of all
+  policies are deprecated and that a policy should be set to OLD only under
+  specific short-term circumstances.  Projects should be ported to the NEW
+  behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index 3038ed8..ad5cbb2 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -299,8 +299,8 @@
   add_RunCMake_test(CompilerChange)
 endif()
 add_RunCMake_test(CompilerNotFound)
-if (APPLE AND CMAKE_C_COMPILER_ID MATCHES "Clang|GNU")
-  list(APPEND CompilerTest_ARGS -DCMake_TEST_OBJC=1)
+if(DEFINED CMake_TEST_OBJC)
+  list(APPEND CompilerTest_ARGS -DCMake_TEST_OBJC=${CMake_TEST_OBJC})
 endif()
 if(CMAKE_Fortran_COMPILER)
   list(APPEND CompilerTest_ARGS -DCMake_TEST_Fortran=1)
@@ -361,7 +361,7 @@
   set(GeneratorToolset_ARGS -DXCODE_VERSION=${XCODE_VERSION})
 endif()
 add_RunCMake_test(GeneratorToolset)
-add_RunCMake_test(GetPrerequisites)
+add_RunCMake_test(GetPrerequisites -DSAMPLE_EXE=$<TARGET_FILE:exit_code>)
 add_RunCMake_test(GNUInstallDirs -DSYSTEM_NAME=${CMAKE_SYSTEM_NAME})
 add_RunCMake_test(GoogleTest) # Note: does not actually depend on Google Test
 add_RunCMake_test(Graphviz)
@@ -502,64 +502,15 @@
 endif()
 
 function(add_RunCMake_test_try_compile)
-  if(CMAKE_VERSION VERSION_LESS 3.9.20170907 AND "x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC")
-    # Older CMake versions do not know about MSVC language standards.
-    # Approximate our logic from MSVC-CXX.cmake.
-    if ((NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.0.24215.1 AND
-         CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.10) OR
-         NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.10.25017)
-      set(CMAKE_CXX_STANDARD_DEFAULT 14)
-    elseif (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 16.0)
-      set(CMAKE_CXX_STANDARD_DEFAULT "")
-    else()
-      unset(CMAKE_CXX_STANDARD_DEFAULT)
-    endif()
-  endif()
-  if(CMAKE_VERSION VERSION_LESS 3.18.20200813 AND "x${CMAKE_C_COMPILER_ID}" STREQUAL "xMSVC")
-    # Older CMake versions do not know about MSVC language standards.
-    # Approximate our logic from MSVC-C.cmake.
-    if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 19.27)
-      set(CMAKE_C_STANDARD_DEFAULT 99)
-    else()
-      set(CMAKE_C_STANDARD_DEFAULT "")
-    endif()
-  endif()
-  if(CMAKE_VERSION VERSION_LESS 3.20.20210225 AND "x${CMAKE_C_COMPILER_ID}" STREQUAL "xClang")
-    # Older CMake versions do not know about Clang MSVC compatibility mode
-    # standards. Approximate the logic from Clang-C.cmake.
-    if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 11.0)
-      set(CMAKE_C_STANDARD_DEFAULT 17)
-    elseif(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 3.5.2)
-      set(CMAKE_C_STANDARD_DEFAULT 11)
-    endif()
-  endif()
-  if(CMAKE_VERSION VERSION_LESS 3.20.6 AND "x${CMAKE_C_COMPILER_ID}" STREQUAL "xIntelLLVM" AND "x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC")
-    # Older CMake versions accidentally set the default standards to empty when
-    # IntelLLVM targets the MSVC ABI, thus not activating standard selection.
-    # Approximate the logic from IntelLLVM-{C,CXX}.cmake.
-    if(DEFINED CMAKE_C_STANDARD_DEFAULT AND "${CMAKE_C_STANDARD_DEFAULT}" STREQUAL "")
-      set(CMAKE_C_STANDARD_DEFAULT 17)
-    endif()
-    if(DEFINED CMAKE_CXX_STANDARD_DEFAULT AND "${CMAKE_CXX_STANDARD_DEFAULT}" STREQUAL "")
-      set(CMAKE_CXX_STANDARD_DEFAULT 14)
-    endif()
-  endif()
   foreach(
     var
     IN ITEMS
       CMAKE_SYSTEM_NAME
-      CMAKE_C_COMPILER_ID
-      CMAKE_C_COMPILER_VERSION
-      CMAKE_C_STANDARD_DEFAULT
-      CMAKE_CXX_COMPILER_ID
-      CMAKE_CXX_COMPILER_VERSION
-      CMAKE_CXX_STANDARD_DEFAULT
       CMake_TEST_CUDA
       CMake_TEST_ISPC
       CMake_TEST_HIP
+      CMake_TEST_OBJC
       CMake_TEST_FILESYSTEM_1S
-      CMAKE_OBJC_STANDARD_DEFAULT
-      CMAKE_OBJCXX_STANDARD_DEFAULT
     )
     if(DEFINED ${var})
       list(APPEND try_compile_ARGS -D${var}=${${var}})
@@ -752,11 +703,13 @@
 add_RunCMake_test(CheckCompilerFlag   -DCMake_TEST_CUDA=${CMake_TEST_CUDA}
                                       -DCMake_TEST_ISPC=${CMake_TEST_ISPC}
                                       -DCMAKE_Fortran_COMPILER_ID=${CMAKE_Fortran_COMPILER_ID}
-                                      -DCMake_TEST_HIP=${CMake_TEST_HIP})
+                                      -DCMake_TEST_HIP=${CMake_TEST_HIP}
+                                      -DCMake_TEST_Swift=${CMake_TEST_Swift})
 add_RunCMake_test(CheckSourceCompiles -DCMake_TEST_CUDA=${CMake_TEST_CUDA}
                                       -DCMake_TEST_ISPC=${CMake_TEST_ISPC}
                                       -DCMAKE_Fortran_COMPILER_ID=${CMAKE_Fortran_COMPILER_ID}
-                                      -DCMake_TEST_HIP=${CMake_TEST_HIP})
+                                      -DCMake_TEST_HIP=${CMake_TEST_HIP}
+                                      -DCMake_TEST_Swift=${CMake_TEST_Swift})
 add_RunCMake_test(CheckSourceRuns     -DCMake_TEST_CUDA=${CMake_TEST_CUDA}
                                       -DCMAKE_Fortran_COMPILER_ID=${CMAKE_Fortran_COMPILER_ID}
                                       -DCMake_TEST_HIP=${CMake_TEST_HIP})
@@ -896,13 +849,13 @@
   if(DEFINED CMake_TEST_ISPC)
     list(APPEND CompilerLauncher_ARGS -DCMake_TEST_ISPC=${CMake_TEST_ISPC})
   endif()
+  if(DEFINED CMake_TEST_OBJC)
+    list(APPEND CompilerLauncher_ARGS -DCMake_TEST_OBJC=${CMake_TEST_OBJC})
+    list(APPEND LinkerLauncher_ARGS   -DCMake_TEST_OBJC=${CMake_TEST_OBJC})
+  endif()
   if(CMAKE_Fortran_COMPILER)
     list(APPEND CompilerLauncher_ARGS -DCMake_TEST_Fortran=1)
   endif()
-  if (APPLE AND CMAKE_C_COMPILER_ID MATCHES "Clang|GNU")
-    list(APPEND CompilerLauncher_ARGS -DCMake_TEST_OBJC=1)
-    list(APPEND LinkerLauncher_ARGS -DCMake_TEST_OBJC=1)
-  endif()
   add_RunCMake_test(CompilerLauncher)
   set_property(TEST RunCMake.CompilerLauncher APPEND
     PROPERTY LABELS "CUDA;HIP;ISPC")
diff --git a/Tests/RunCMake/CXXModules/RunCMakeTest.cmake b/Tests/RunCMake/CXXModules/RunCMakeTest.cmake
index 3f17c1f..921fabd 100644
--- a/Tests/RunCMake/CXXModules/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CXXModules/RunCMakeTest.cmake
@@ -120,7 +120,9 @@
   if (RunCMake_CXXModules_INSTALL)
     run_cmake_command("examples/${test_name}-install" "${CMAKE_COMMAND}" --build . --target install --config Debug)
   endif ()
-  run_cmake_command("examples/${test_name}-test" "${CMAKE_CTEST_COMMAND}" -C Debug --output-on-failure)
+  if (NOT RunCMake_CXXModules_NO_TEST)
+    run_cmake_command("examples/${test_name}-test" "${CMAKE_CTEST_COMMAND}" -C Debug --output-on-failure)
+  endif ()
 endfunction ()
 
 string(REPLACE "," ";" CMake_TEST_MODULE_COMPILATION "${CMake_TEST_MODULE_COMPILATION}")
@@ -132,6 +134,10 @@
   run_cxx_module_test(generated)
   run_cxx_module_test(public-req-private)
   run_cxx_module_test(deep-chain)
+  run_cxx_module_test(duplicate)
+  set(RunCMake_CXXModules_NO_TEST 1)
+  run_cxx_module_test(circular)
+  unset(RunCMake_CXXModules_NO_TEST)
 endif ()
 
 # Tests which use named modules in shared libraries.
diff --git a/Tests/RunCMake/CXXModules/examples/circular-build-result.txt b/Tests/RunCMake/CXXModules/examples/circular-build-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/circular-build-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CXXModules/examples/circular-build-stdout.txt b/Tests/RunCMake/CXXModules/examples/circular-build-stdout.txt
new file mode 100644
index 0000000..433b461
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/circular-build-stdout.txt
@@ -0,0 +1 @@
+(Ninja generators)?(build stopped: dependency cycle:)
diff --git a/Tests/RunCMake/CXXModules/examples/circular-stderr.txt b/Tests/RunCMake/CXXModules/examples/circular-stderr.txt
new file mode 100644
index 0000000..5e4392a
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/circular-stderr.txt
@@ -0,0 +1,9 @@
+CMake Warning \(dev\) at CMakeLists.txt:7 \(target_sources\):
+  CMake's C\+\+ module support is experimental.  It is meant only for
+  experimentation and feedback to CMake developers.
+This warning is for project developers.  Use -Wno-dev to suppress it.
+
+CMake Warning \(dev\):
+  C\+\+20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP is
+  experimental.  It is meant only for compiler developers to try.
+This warning is for project developers.  Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CXXModules/examples/circular/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/circular/CMakeLists.txt
new file mode 100644
index 0000000..4d1997c
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/circular/CMakeLists.txt
@@ -0,0 +1,15 @@
+cmake_minimum_required(VERSION 3.24)
+project(cxx_modules_circular CXX)
+
+include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake")
+
+add_library(circular STATIC)
+target_sources(circular
+  PUBLIC
+    FILE_SET CXX_MODULES
+      BASE_DIRS
+        "${CMAKE_CURRENT_SOURCE_DIR}"
+      FILES
+        circular-a.cppm
+        circular-b.cppm)
+target_compile_features(circular PUBLIC cxx_std_20)
diff --git a/Tests/RunCMake/CXXModules/examples/circular/circular-a.cppm b/Tests/RunCMake/CXXModules/examples/circular/circular-a.cppm
new file mode 100644
index 0000000..eea842b
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/circular/circular-a.cppm
@@ -0,0 +1,6 @@
+export module a;
+import b;
+
+export int a() {
+    return b();
+}
diff --git a/Tests/RunCMake/CXXModules/examples/circular/circular-b.cppm b/Tests/RunCMake/CXXModules/examples/circular/circular-b.cppm
new file mode 100644
index 0000000..fc6dc42
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/circular/circular-b.cppm
@@ -0,0 +1,6 @@
+export module b;
+import a;
+
+export int b() {
+    return a();
+}
diff --git a/Tests/RunCMake/CXXModules/examples/duplicate-stderr.txt b/Tests/RunCMake/CXXModules/examples/duplicate-stderr.txt
new file mode 100644
index 0000000..5e4392a
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/duplicate-stderr.txt
@@ -0,0 +1,9 @@
+CMake Warning \(dev\) at CMakeLists.txt:7 \(target_sources\):
+  CMake's C\+\+ module support is experimental.  It is meant only for
+  experimentation and feedback to CMake developers.
+This warning is for project developers.  Use -Wno-dev to suppress it.
+
+CMake Warning \(dev\):
+  C\+\+20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP is
+  experimental.  It is meant only for compiler developers to try.
+This warning is for project developers.  Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CXXModules/examples/duplicate/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/duplicate/CMakeLists.txt
new file mode 100644
index 0000000..27be7a8
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/duplicate/CMakeLists.txt
@@ -0,0 +1,39 @@
+cmake_minimum_required(VERSION 3.24)
+project(cxx_modules_duplicate CXX)
+
+include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake")
+
+add_executable(duplicate)
+target_sources(duplicate
+  PRIVATE
+    main.cxx
+  PRIVATE
+    FILE_SET CXX_MODULES
+      BASE_DIRS
+        "${CMAKE_CURRENT_SOURCE_DIR}"
+      FILES
+        duplicate.cxx)
+target_compile_features(duplicate PRIVATE cxx_std_20)
+target_compile_definitions(duplicate PRIVATE NDUPLICATE=1)
+
+add_executable(duplicate2)
+target_sources(duplicate2
+  PRIVATE
+    main.cxx
+  PRIVATE
+    FILE_SET CXX_MODULES
+      BASE_DIRS
+        "${CMAKE_CURRENT_SOURCE_DIR}"
+      FILES
+        duplicate.cxx)
+target_compile_features(duplicate2 PRIVATE cxx_std_20)
+target_compile_definitions(duplicate2 PRIVATE NDUPLICATE=2)
+
+add_test(NAME duplicate COMMAND duplicate)
+set_property(TEST duplicate
+  PROPERTY
+    PASS_REGULAR_EXPRESSION "From duplicate #1")
+add_test(NAME duplicate2 COMMAND duplicate2)
+set_property(TEST duplicate2
+  PROPERTY
+    PASS_REGULAR_EXPRESSION "From duplicate #2")
diff --git a/Tests/RunCMake/CXXModules/examples/duplicate/duplicate.cxx b/Tests/RunCMake/CXXModules/examples/duplicate/duplicate.cxx
new file mode 100644
index 0000000..c0c820b
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/duplicate/duplicate.cxx
@@ -0,0 +1,11 @@
+module;
+
+#include <iostream>
+
+export module duplicate;
+
+export int from_import()
+{
+  std::cerr << "From duplicate #" << NDUPLICATE << std::endl;
+  return 0;
+}
diff --git a/Tests/RunCMake/CXXModules/examples/duplicate/main.cxx b/Tests/RunCMake/CXXModules/examples/duplicate/main.cxx
new file mode 100644
index 0000000..c2c0636
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/duplicate/main.cxx
@@ -0,0 +1,6 @@
+import duplicate;
+
+int main(int argc, char* argv[])
+{
+  return from_import();
+}
diff --git a/Tests/RunCMake/CheckCompilerFlag/CheckCompilerFlagSwift.cmake b/Tests/RunCMake/CheckCompilerFlag/CheckCompilerFlagSwift.cmake
new file mode 100644
index 0000000..23b3006
--- /dev/null
+++ b/Tests/RunCMake/CheckCompilerFlag/CheckCompilerFlagSwift.cmake
@@ -0,0 +1,21 @@
+enable_language (Swift)
+include(CheckCompilerFlag)
+
+set(Swift 1)
+
+# test that the check uses an isolated locale
+set(_env_LC_ALL "${LC_ALL}")
+set(ENV{LC_ALL} "BAD")
+
+check_compiler_flag(Swift "-foo-as-blarpy" SHOULD_FAIL)
+if(SHOULD_FAIL)
+  message(SEND_ERROR "invalid Swift compile flag didn't fail.")
+endif()
+
+check_compiler_flag(Swift "-parseable-output" SHOULD_WORK)
+if(NOT SHOULD_WORK)
+  message(SEND_ERROR "Swift compiler flag '-parseable-output' check failed")
+endif()
+
+# Reset locale
+set(ENV{LC_ALL} ${_env_LC_ALL})
diff --git a/Tests/RunCMake/CheckCompilerFlag/RunCMakeTest.cmake b/Tests/RunCMake/CheckCompilerFlag/RunCMakeTest.cmake
index b0e025c..81429a6 100644
--- a/Tests/RunCMake/CheckCompilerFlag/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CheckCompilerFlag/RunCMakeTest.cmake
@@ -32,3 +32,7 @@
 if(APPLE)
   run_cmake(HeaderpadWorkaround)
 endif()
+
+if(CMake_TEST_Swift)
+  run_cmake(CheckCompilerFlagSwift)
+endif()
diff --git a/Tests/RunCMake/CheckSourceCompiles/CheckSourceCompilesSwift.cmake b/Tests/RunCMake/CheckSourceCompiles/CheckSourceCompilesSwift.cmake
new file mode 100644
index 0000000..767fa69
--- /dev/null
+++ b/Tests/RunCMake/CheckSourceCompiles/CheckSourceCompilesSwift.cmake
@@ -0,0 +1,15 @@
+enable_language(Swift)
+include(CheckSourceCompiles)
+
+set(Swift 1) # test that this is tolerated
+
+check_source_compiles(Swift "baz()" SHOULD_FAIL)
+
+if(SHOULD_FAIL)
+  message(SEND_ERROR "invalid Swift source didn't fail.")
+endif()
+
+check_source_compiles(Swift "print(\"Hello, CMake\")" SHOULD_BUILD)
+if(NOT SHOULD_BUILD)
+  message(SEND_ERROR "Test failed for valid Swift source.")
+endif()
diff --git a/Tests/RunCMake/CheckSourceCompiles/RunCMakeTest.cmake b/Tests/RunCMake/CheckSourceCompiles/RunCMakeTest.cmake
index df77d3d..2ed3e36 100644
--- a/Tests/RunCMake/CheckSourceCompiles/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CheckSourceCompiles/RunCMakeTest.cmake
@@ -31,3 +31,7 @@
 if(CMake_TEST_HIP)
   run_cmake(CheckSourceCompilesHIP)
 endif()
+
+if(CMake_TEST_Swift)
+  run_cmake(CheckSourceCompilesSwift)
+endif()
diff --git a/Tests/RunCMake/CommandLine/Envgen-bad-help-stderr.txt b/Tests/RunCMake/CommandLine/Envgen-bad-help-stderr.txt
new file mode 100644
index 0000000..cdfe857
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-bad-help-stderr.txt
@@ -0,0 +1 @@
+CMake Error: CMAKE_GENERATOR was set but the specified generator doesn't exist. Using CMake default.
diff --git a/Tests/RunCMake/CommandLine/Envgen-bad-help-stdout.txt b/Tests/RunCMake/CommandLine/Envgen-bad-help-stdout.txt
new file mode 100644
index 0000000..075c48c
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-bad-help-stdout.txt
@@ -0,0 +1,2 @@
+Generators.*
+\* (Unix Makefiles|Visual Studio).*
diff --git a/Tests/RunCMake/CommandLine/Envgen-ninja-multi-help-stdout.txt b/Tests/RunCMake/CommandLine/Envgen-ninja-multi-help-stdout.txt
new file mode 100644
index 0000000..ece6e5d
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-ninja-multi-help-stdout.txt
@@ -0,0 +1 @@
+\* Ninja Multi-Config[ ]+= Generates build-<Config>.ninja files.
diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
index a2eeddf..327b772 100644
--- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
@@ -349,6 +349,13 @@
   run_cmake_command(Envgen-bad ${CMAKE_COMMAND} -G)
   unset(ENV{CMAKE_GENERATOR})
 
+  # Honor CMAKE_GENERATOR env var in --help output
+  set(ENV{CMAKE_GENERATOR} "Ninja Multi-Config")
+  run_cmake_command(Envgen-ninja-multi-help ${CMAKE_COMMAND} --help)
+  set(ENV{CMAKE_GENERATOR} "NoSuchGenerator")
+  run_cmake_command(Envgen-bad-help ${CMAKE_COMMAND} --help)
+  unset(ENV{CMAKE_GENERATOR})
+
   if(RunCMake_GENERATOR MATCHES "Visual Studio.*")
     set(ENV{CMAKE_GENERATOR} "${RunCMake_GENERATOR}")
     run_cmake_command(Envgen ${CMAKE_COMMAND} ${source_dir})
@@ -940,6 +947,7 @@
 
 set(RunCMake_TEST_OPTIONS --trace)
 run_cmake(trace)
+run_cmake(trace-try_compile)
 unset(RunCMake_TEST_OPTIONS)
 
 set(RunCMake_TEST_OPTIONS --trace-expand)
@@ -952,6 +960,7 @@
 
 set(RunCMake_TEST_OPTIONS --trace-redirect=${RunCMake_BINARY_DIR}/redirected.trace)
 run_cmake(trace-redirect)
+run_cmake(trace-try_compile-redirect)
 unset(RunCMake_TEST_OPTIONS)
 
 set(RunCMake_TEST_OPTIONS --trace-redirect=/no/such/file.txt)
diff --git a/Tests/RunCMake/CommandLine/compare_files/.gitattributes b/Tests/RunCMake/CommandLine/compare_files/.gitattributes
index 91d5c10..d03da96 100644
--- a/Tests/RunCMake/CommandLine/compare_files/.gitattributes
+++ b/Tests/RunCMake/CommandLine/compare_files/.gitattributes
@@ -1,2 +1,2 @@
-crlf eol=crlf
-lf eol=lf
+crlf -text -whitespace
+lf   -text
diff --git a/Tests/RunCMake/CommandLine/compare_files/crlf b/Tests/RunCMake/CommandLine/compare_files/crlf
index a29bdeb..495181c 100644
--- a/Tests/RunCMake/CommandLine/compare_files/crlf
+++ b/Tests/RunCMake/CommandLine/compare_files/crlf
@@ -1 +1 @@
-line1
+line1

diff --git a/Tests/RunCMake/CommandLine/trace-try_compile-redirect-check.cmake b/Tests/RunCMake/CommandLine/trace-try_compile-redirect-check.cmake
new file mode 100644
index 0000000..94a7c95
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/trace-try_compile-redirect-check.cmake
@@ -0,0 +1,13 @@
+file(READ ${RunCMake_SOURCE_DIR}/trace-try_compile-stderr.txt expected_content)
+string(REGEX REPLACE "\n+$" "" expected_content "${expected_content}")
+
+file(READ ${RunCMake_BINARY_DIR}/redirected.trace actual_content)
+string(REGEX REPLACE "\r\n" "\n" actual_content "${actual_content}")
+string(REGEX REPLACE "\n+$" "" actual_content "${actual_content}")
+if(NOT "${actual_content}" MATCHES "${expected_content}")
+    set(RunCMake_TEST_FAILED
+        "Trace file content does not match that expected."
+        "Expected to match:\n${expected_content}\n"
+        "Actual content:\n${actual_content}\n"
+        )
+endif()
diff --git a/Tests/RunCMake/CommandLine/trace-try_compile-redirect.cmake b/Tests/RunCMake/CommandLine/trace-try_compile-redirect.cmake
new file mode 100644
index 0000000..982cb89
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/trace-try_compile-redirect.cmake
@@ -0,0 +1,2 @@
+cmake_minimum_required(VERSION 3.24)
+project(test C)
diff --git a/Tests/RunCMake/CommandLine/trace-try_compile-stderr.txt b/Tests/RunCMake/CommandLine/trace-try_compile-stderr.txt
new file mode 100644
index 0000000..1674b8f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/trace-try_compile-stderr.txt
@@ -0,0 +1,4 @@
+.*Modules/CMakeDetermineCompilerABI.cmake\([0-9]+\):  try_compile\([^)]+\)
+.*Tests/RunCMake/CommandLine/trace-try_compile(-redirect)?-build/CMakeFiles/CMakeScratch/TryCompile-[^/]+/CMakeLists.txt\([0-9]+\):  cmake_minimum_required.*
+.*Tests/RunCMake/CommandLine/trace-try_compile(-redirect)?-build/CMakeFiles/CMakeScratch/TryCompile-[^/]+/CMakeLists.txt\([0-9]+\):  project\(CMAKE_TRY_COMPILE.*
+.*Tests/RunCMake/CommandLine/trace-try_compile(-redirect)?-build/CMakeFiles/CMakeScratch/TryCompile-[^/]+/CMakeLists.txt\([0-9]+\):  add_executable\(cmTC_.*
diff --git a/Tests/RunCMake/CommandLine/trace-try_compile.cmake b/Tests/RunCMake/CommandLine/trace-try_compile.cmake
new file mode 100644
index 0000000..982cb89
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/trace-try_compile.cmake
@@ -0,0 +1,2 @@
+cmake_minimum_required(VERSION 3.24)
+project(test C)
diff --git a/Tests/RunCMake/FindPkgConfig/FindPkgConfig_IMPORTED_TARGET.cmake b/Tests/RunCMake/FindPkgConfig/FindPkgConfig_IMPORTED_TARGET.cmake
index f149d99..69ab4da 100644
--- a/Tests/RunCMake/FindPkgConfig/FindPkgConfig_IMPORTED_TARGET.cmake
+++ b/Tests/RunCMake/FindPkgConfig/FindPkgConfig_IMPORTED_TARGET.cmake
@@ -113,24 +113,34 @@
 if (NOT TARGET ${tgt})
   message(FATAL_ERROR "No import target for fake link options package")
 endif()
-get_target_property(link_options ${tgt} INTERFACE_LINK_OPTIONS)
-if (NOT link_options STREQUAL expected_link_options)
-  message(FATAL_ERROR
-    "Additional link options not present in INTERFACE_LINK_OPTIONS property\n"
-    "expected: \"${expected_link_options}\", but got \"${link_options}\""
-  )
+
+# Some versions of pkg-config on Windows don't parse the Libs and Cflags
+# correctly. The pkg-config that comes with Strawberry perl is one example.
+# It appears to treat the dummymain part of Libs as a library and only returns
+# -e. It also doesn't recognize "-isystem /other", presumably because it doesn't
+# support having a space between "-isystem" and the directory after it (it does
+# give us the "-isystem/more" flag). Since we can't reliably test for these,
+# we don't enable these checks on Windows.
+if(NOT WIN32)
+  get_target_property(link_options ${tgt} INTERFACE_LINK_OPTIONS)
+  if (NOT link_options STREQUAL expected_link_options)
+    message(FATAL_ERROR
+      "Additional link options not present in INTERFACE_LINK_OPTIONS property\n"
+      "expected: \"${expected_link_options}\", but got \"${link_options}\""
+    )
+  endif()
+
+  get_target_property(inc_dirs ${tgt} INTERFACE_INCLUDE_DIRECTORIES)
+  set(expected_inc_dirs "/special" "/other" "/more")
+
+  if (NOT inc_dirs STREQUAL expected_inc_dirs)
+    message(FATAL_ERROR
+      "Additional include directories not correctly present in INTERFACE_INCLUDE_DIRECTORIES property\n"
+      "expected: \"${expected_inc_dirs}\", got \"${inc_dirs}\""
+    )
+  endif ()
 endif()
 
-get_target_property(inc_dirs ${tgt} INTERFACE_INCLUDE_DIRECTORIES)
-set(expected_inc_dirs "/special" "/other" "/more")
-
-if (NOT inc_dirs STREQUAL expected_inc_dirs)
-  message(FATAL_ERROR
-    "Additional include directories not correctly present in INTERFACE_INCLUDE_DIRECTORIES property\n"
-    "expected: \"${expected_inc_dirs}\", got \"${inc_dirs}\""
-  )
-endif ()
-
 get_target_property(c_opts ${tgt} INTERFACE_COMPILE_OPTIONS)
 set(expected_c_opts "-DA-isystem/foo") # this is an invalid option, but a good testcase
 if (NOT c_opts STREQUAL expected_c_opts)
diff --git a/Tests/RunCMake/FindPkgConfig/FindPkgConfig_VERSION_OPERATORS.cmake b/Tests/RunCMake/FindPkgConfig/FindPkgConfig_VERSION_OPERATORS.cmake
index 2a505c6..f7a9815 100644
--- a/Tests/RunCMake/FindPkgConfig/FindPkgConfig_VERSION_OPERATORS.cmake
+++ b/Tests/RunCMake/FindPkgConfig/FindPkgConfig_VERSION_OPERATORS.cmake
@@ -20,14 +20,15 @@
 
 # Always find the .pc file in the calls further below so that we can test that
 # the import target find_library() calls handle the NO...PATH options correctly
-set(ENV{PKG_CONFIG_PATH} ${fakePkgDir}/lib/pkgconfig)
+cmake_path(CONVERT "${fakePkgDir}/lib/pkgconfig" TO_NATIVE_PATH_LIST confPath)
+set(ENV{PKG_CONFIG_PATH} "${confPath}")
 
-pkg_check_modules(FakePackageGE REQUIRED QUIET "cmakeinternalfakepackage >= 8")
+pkg_check_modules(FakePackageGE REQUIRED QUIET "cmakeinternalfakepackage>=8")
 if (NOT FakePackageGE_FOUND)
   message(FATAL_ERROR "fake package >= 8 not found")
 endif()
 
-pkg_check_modules(FakePackageGE_FAIL QUIET "cmakeinternalfakepackage >= 8.10")
+pkg_check_modules(FakePackageGE_FAIL QUIET "cmakeinternalfakepackage>=8.10")
 if (FakePackageGE_FAIL_FOUND)
   message(FATAL_ERROR "fake package >= 8.10 found")
 endif()
@@ -37,17 +38,17 @@
   message(FATAL_ERROR "fake package <= 9 not found")
 endif()
 
-pkg_check_modules(FakePackageLE_FAIL QUIET "cmakeinternalfakepackage <= 8.1")
+pkg_check_modules(FakePackageLE_FAIL QUIET "cmakeinternalfakepackage<=8.1")
 if (FakePackageLE_FAIL_FOUND)
   message(FATAL_ERROR "fake package <= 8.1 found")
 endif()
 
-pkg_check_modules(FakePackageGT REQUIRED QUIET "cmakeinternalfakepackage > 8")
+pkg_check_modules(FakePackageGT REQUIRED QUIET "cmakeinternalfakepackage>8")
 if (NOT FakePackageGT_FOUND)
   message(FATAL_ERROR "fake package > 8 not found")
 endif()
 
-pkg_check_modules(FakePackageGT_FAIL QUIET "cmakeinternalfakepackage > 8.9")
+pkg_check_modules(FakePackageGT_FAIL QUIET "cmakeinternalfakepackage>8.9")
 if (FakePackageGT_FAIL_FOUND)
   message(FATAL_ERROR "fake package > 8.9 found")
 endif()
@@ -57,7 +58,7 @@
   message(FATAL_ERROR "fake package < 9 not found")
 endif()
 
-pkg_check_modules(FakePackageLT_FAIL QUIET "cmakeinternalfakepackage < 8.9")
+pkg_check_modules(FakePackageLT_FAIL QUIET "cmakeinternalfakepackage<8.9")
 if (FakePackageLT_FAIL_FOUND)
   message(FATAL_ERROR "fake package < 8.9 found")
 endif()
@@ -67,17 +68,17 @@
   message(FATAL_ERROR "fake package = 8.9 not found")
 endif()
 
-pkg_check_modules(FakePackageEQ_FAIL QUIET "cmakeinternalfakepackage = 8.8")
+pkg_check_modules(FakePackageEQ_FAIL QUIET "cmakeinternalfakepackage=8.8")
 if (FakePackageEQ_FAIL_FOUND)
   message(FATAL_ERROR "fake package = 8.8 found")
 endif()
 
-pkg_check_modules(FakePackageEQ_INV QUIET "cmakeinternalfakepackage == 8.9")
+pkg_check_modules(FakePackageEQ_INV QUIET "cmakeinternalfakepackage==8.9")
 if (FakePackageEQ_FAIL_FOUND)
   message(FATAL_ERROR "fake package == 8.9 found")
 endif()
 
-pkg_check_modules(FakePackageLLT_INV QUIET "cmakeinternalfakepackage <<= 9")
+pkg_check_modules(FakePackageLLT_INV QUIET "cmakeinternalfakepackage<<=9")
 if (FakePackageLLT_FAIL_FOUND)
   message(FATAL_ERROR "fake package <<= 9 found")
 endif()
diff --git a/Tests/RunCMake/FindPkgConfig/RunCMakeTest.cmake b/Tests/RunCMake/FindPkgConfig/RunCMakeTest.cmake
index 661ae3f..6b8e884 100644
--- a/Tests/RunCMake/FindPkgConfig/RunCMakeTest.cmake
+++ b/Tests/RunCMake/FindPkgConfig/RunCMakeTest.cmake
@@ -7,13 +7,18 @@
 
 run_cmake(PkgConfigDoesNotExist)
 
-run_cmake(FindPkgConfig_CMP0126_NEW)
-run_cmake(FindPkgConfig_NO_PKGCONFIG_PATH)
-run_cmake(FindPkgConfig_PKGCONFIG_PATH)
-run_cmake(FindPkgConfig_PKGCONFIG_PATH_NO_CMAKE_PATH)
-run_cmake(FindPkgConfig_PKGCONFIG_PATH_NO_CMAKE_ENVIRONMENT_PATH)
+if(NOT WIN32)
+  # FIXME: The Windows implementation of these tests do not work.
+  #        They are disabled until they can be updated to a working state.
+  run_cmake(FindPkgConfig_CMP0126_NEW)
+  run_cmake(FindPkgConfig_NO_PKGCONFIG_PATH)
+  run_cmake(FindPkgConfig_PKGCONFIG_PATH)
+  run_cmake(FindPkgConfig_PKGCONFIG_PATH_NO_CMAKE_PATH)
+  run_cmake(FindPkgConfig_PKGCONFIG_PATH_NO_CMAKE_ENVIRONMENT_PATH)
+  run_cmake(FindPkgConfig_GET_MATCHING_ARGN)
+endif()
+
 run_cmake(FindPkgConfig_extract_frameworks)
-run_cmake(FindPkgConfig_GET_MATCHING_ARGN)
 
 if(APPLE)
   run_cmake(FindPkgConfig_extract_frameworks_target)
diff --git a/Tests/RunCMake/GetPrerequisites/ExecutableScripts.cmake b/Tests/RunCMake/GetPrerequisites/ExecutableScripts.cmake
index d1bc9b1..9cc05d0 100644
--- a/Tests/RunCMake/GetPrerequisites/ExecutableScripts.cmake
+++ b/Tests/RunCMake/GetPrerequisites/ExecutableScripts.cmake
@@ -10,7 +10,9 @@
 
 # Should not throw any errors
 # Regular executable
-get_prerequisites(${CMAKE_COMMAND} cmake_prereqs 1 1 "" "")
+if(SAMPLE_EXE)
+  get_prerequisites("${SAMPLE_EXE}" cmake_prereqs 1 1 "" "")
+endif()
 # Shell script
 check_script(${CMAKE_CURRENT_LIST_DIR}/script.sh)
 # Batch script
diff --git a/Tests/RunCMake/GetPrerequisites/RunCMakeTest.cmake b/Tests/RunCMake/GetPrerequisites/RunCMakeTest.cmake
index a635e38..5550c02 100644
--- a/Tests/RunCMake/GetPrerequisites/RunCMakeTest.cmake
+++ b/Tests/RunCMake/GetPrerequisites/RunCMakeTest.cmake
@@ -1,4 +1,4 @@
 include(RunCMake)
 
 run_cmake_command(TargetMissing ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/TargetMissing.cmake)
-run_cmake_command(ExecutableScripts ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/ExecutableScripts.cmake)
+run_cmake_command(ExecutableScripts ${CMAKE_COMMAND} -DSAMPLE_EXE=${SAMPLE_EXE} -P ${RunCMake_SOURCE_DIR}/ExecutableScripts.cmake)
diff --git a/Tests/RunCMake/NinjaMultiConfig/CompileCommands-check.cmake b/Tests/RunCMake/NinjaMultiConfig/CompileCommands-check.cmake
index a1ae6ac..30b24bf 100644
--- a/Tests/RunCMake/NinjaMultiConfig/CompileCommands-check.cmake
+++ b/Tests/RunCMake/NinjaMultiConfig/CompileCommands-check.cmake
@@ -7,7 +7,8 @@
 ]*Debug[^
 ]*",
   "file": "[^
-]*(/Tests/RunCMake/NinjaMultiConfig/main\.c|\\\\Tests\\\\RunCMake\\\\NinjaMultiConfig\\\\main\.c)"
+]*(/Tests/RunCMake/NinjaMultiConfig/main\.c|\\\\Tests\\\\RunCMake\\\\NinjaMultiConfig\\\\main\.c)",
+  "output": "(CMakeFiles/exe\.dir/Debug/main\.c\.o|CMakeFiles\\\\exe\.dir\\\\Debug\\\\main\.c\.obj)"
 },
 {
   "directory": "[^
@@ -16,7 +17,8 @@
 ]*Release[^
 ]*",
   "file": "[^
-]*(/Tests/RunCMake/NinjaMultiConfig/main\.c|\\\\Tests\\\\RunCMake\\\\NinjaMultiConfig\\\\main\.c)"
+]*(/Tests/RunCMake/NinjaMultiConfig/main\.c|\\\\Tests\\\\RunCMake\\\\NinjaMultiConfig\\\\main\.c)",
+  "output": "(CMakeFiles/exe\.dir/Release/main\.c\.o|CMakeFiles\\\\exe\.dir\\\\Release\\\\main\.c\.obj)"
 }
 ]$]==])
 
diff --git a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
index f027e94..ed74896 100644
--- a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
+++ b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
@@ -89,3 +89,10 @@
 run_cmake(VsDotnetTargetFrameworkVersion)
 run_cmake(VsNoCompileBatching)
 run_cmake(DebugInformationFormat)
+run_cmake(VsCLREmpty)
+run_cmake(VsCLRPure)
+run_cmake(VsCLRSafe)
+
+if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 19.20)
+  run_cmake(VsCLRNetcore)
+endif()
diff --git a/Tests/RunCMake/VS10Project/VsCLREmpty-check.cmake b/Tests/RunCMake/VS10Project/VsCLREmpty-check.cmake
new file mode 100644
index 0000000..990da46
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsCLREmpty-check.cmake
@@ -0,0 +1,24 @@
+set(vcProjectFile "${RunCMake_TEST_BINARY_DIR}/foo.vcxproj")
+if(NOT EXISTS "${vcProjectFile}")
+  set(RunCMake_TEST_FAILED "Project file ${vcProjectFile} does not exist.")
+  return()
+endif()
+
+set(propertyFound FALSE)
+file(STRINGS "${vcProjectFile}" lines)
+foreach(line IN LISTS lines)
+  if(line MATCHES "^ *<CompileAsManaged>(.*)</CompileAsManaged>$")
+    set(propertyFound TRUE)
+    set(expectedValue "true")
+    set(actualValue ${CMAKE_MATCH_1})
+    if(NOT (${actualValue} STREQUAL ${expectedValue}))
+      set(RunCMake_TEST_FAILED "CompileAsManaged \"${actualValue}\" differs from expected value \"${expectedValue}\".")
+      return()
+    endif()
+  endif()
+endforeach()
+
+if(NOT propertyFound)
+  set(RunCMake_TEST_FAILED "Property CompileAsManaged not found in project file.")
+  return()
+endif()
diff --git a/Tests/RunCMake/VS10Project/VsCLREmpty.cmake b/Tests/RunCMake/VS10Project/VsCLREmpty.cmake
new file mode 100644
index 0000000..a622f26
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsCLREmpty.cmake
@@ -0,0 +1,6 @@
+enable_language(CXX)
+
+add_library(foo foo.cpp)
+
+set_target_properties(foo PROPERTIES
+  COMMON_LANGUAGE_RUNTIME "")
diff --git a/Tests/RunCMake/VS10Project/VsCLRNetcore-check.cmake b/Tests/RunCMake/VS10Project/VsCLRNetcore-check.cmake
new file mode 100644
index 0000000..a5058d7
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsCLRNetcore-check.cmake
@@ -0,0 +1,24 @@
+set(vcProjectFile "${RunCMake_TEST_BINARY_DIR}/foo.vcxproj")
+if(NOT EXISTS "${vcProjectFile}")
+  set(RunCMake_TEST_FAILED "Project file ${vcProjectFile} does not exist.")
+  return()
+endif()
+
+set(propertyFound FALSE)
+file(STRINGS "${vcProjectFile}" lines)
+foreach(line IN LISTS lines)
+  if(line MATCHES "^ *<CLRSupport>(.*)</CLRSupport>$")
+    set(propertyFound TRUE)
+    set(expectedValue "NetCore")
+    set(actualValue ${CMAKE_MATCH_1})
+    if(NOT (${actualValue} STREQUAL ${expectedValue}))
+      set(RunCMake_TEST_FAILED "CLRSupport \"${actualValue}\" differs from expected value \"${expectedValue}\".")
+      return()
+    endif()
+  endif()
+endforeach()
+
+if(NOT propertyFound)
+  set(RunCMake_TEST_FAILED "Property CLRSupport not found in project file.")
+  return()
+endif()
diff --git a/Tests/RunCMake/VS10Project/VsCLRNetcore.cmake b/Tests/RunCMake/VS10Project/VsCLRNetcore.cmake
new file mode 100644
index 0000000..c5ec2bc
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsCLRNetcore.cmake
@@ -0,0 +1,6 @@
+enable_language(CXX)
+
+add_library(foo foo.cpp)
+
+set_target_properties(foo PROPERTIES
+  COMMON_LANGUAGE_RUNTIME "netcore")
diff --git a/Tests/RunCMake/VS10Project/VsCLRPure-check.cmake b/Tests/RunCMake/VS10Project/VsCLRPure-check.cmake
new file mode 100644
index 0000000..8ae73eb
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsCLRPure-check.cmake
@@ -0,0 +1,24 @@
+set(vcProjectFile "${RunCMake_TEST_BINARY_DIR}/foo.vcxproj")
+if(NOT EXISTS "${vcProjectFile}")
+  set(RunCMake_TEST_FAILED "Project file ${vcProjectFile} does not exist.")
+  return()
+endif()
+
+set(propertyFound FALSE)
+file(STRINGS "${vcProjectFile}" lines)
+foreach(line IN LISTS lines)
+  if(line MATCHES "^ *<CompileAsManaged>(.*)</CompileAsManaged>$")
+    set(propertyFound TRUE)
+    set(expectedValue "Pure")
+    set(actualValue ${CMAKE_MATCH_1})
+    if(NOT (${actualValue} STREQUAL ${expectedValue}))
+      set(RunCMake_TEST_FAILED "CompileAsManaged \"${actualValue}\" differs from expected value \"${expectedValue}\".")
+      return()
+    endif()
+  endif()
+endforeach()
+
+if(NOT propertyFound)
+  set(RunCMake_TEST_FAILED "Property CompileAsManaged not found in project file.")
+  return()
+endif()
diff --git a/Tests/RunCMake/VS10Project/VsCLRPure.cmake b/Tests/RunCMake/VS10Project/VsCLRPure.cmake
new file mode 100644
index 0000000..f919a1c
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsCLRPure.cmake
@@ -0,0 +1,6 @@
+enable_language(CXX)
+
+add_library(foo foo.cpp)
+
+set_target_properties(foo PROPERTIES
+  COMMON_LANGUAGE_RUNTIME "pure")
diff --git a/Tests/RunCMake/VS10Project/VsCLRSafe-check.cmake b/Tests/RunCMake/VS10Project/VsCLRSafe-check.cmake
new file mode 100644
index 0000000..ebb1f71
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsCLRSafe-check.cmake
@@ -0,0 +1,24 @@
+set(vcProjectFile "${RunCMake_TEST_BINARY_DIR}/foo.vcxproj")
+if(NOT EXISTS "${vcProjectFile}")
+  set(RunCMake_TEST_FAILED "Project file ${vcProjectFile} does not exist.")
+  return()
+endif()
+
+set(propertyFound FALSE)
+file(STRINGS "${vcProjectFile}" lines)
+foreach(line IN LISTS lines)
+  if(line MATCHES "^ *<CompileAsManaged>(.*)</CompileAsManaged>$")
+    set(propertyFound TRUE)
+    set(expectedValue "Safe")
+    set(actualValue ${CMAKE_MATCH_1})
+    if(NOT (${actualValue} STREQUAL ${expectedValue}))
+      set(RunCMake_TEST_FAILED "CompileAsManaged \"${actualValue}\" differs from expected value \"${expectedValue}\".")
+      return()
+    endif()
+  endif()
+endforeach()
+
+if(NOT propertyFound)
+  set(RunCMake_TEST_FAILED "Property CompileAsManaged not found in project file.")
+  return()
+endif()
diff --git a/Tests/RunCMake/VS10Project/VsCLRSafe.cmake b/Tests/RunCMake/VS10Project/VsCLRSafe.cmake
new file mode 100644
index 0000000..5f114bf
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsCLRSafe.cmake
@@ -0,0 +1,6 @@
+enable_language(CXX)
+
+add_library(foo foo.cpp)
+
+set_target_properties(foo PROPERTIES
+  COMMON_LANGUAGE_RUNTIME "safe")
diff --git a/Tests/RunCMake/alias_targets/duplicate-target-CMP0107-OLD-stderr.txt b/Tests/RunCMake/alias_targets/duplicate-target-CMP0107-OLD-stderr.txt
new file mode 100644
index 0000000..f5247ca
--- /dev/null
+++ b/Tests/RunCMake/alias_targets/duplicate-target-CMP0107-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at duplicate-target-CMP0107-OLD.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0107 will be removed from a future version
+  of CMake.
+
+  The cmake-policies\(7\) manual explains that the OLD behaviors of all
+  policies are deprecated and that a policy should be set to OLD only under
+  specific short-term circumstances.  Projects should be ported to the NEW
+  behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/export/Repeat-CMP0103-OLD-stderr.txt b/Tests/RunCMake/export/Repeat-CMP0103-OLD-stderr.txt
new file mode 100644
index 0000000..1183f86
--- /dev/null
+++ b/Tests/RunCMake/export/Repeat-CMP0103-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at Repeat-CMP0103-OLD.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0103 will be removed from a future version
+  of CMake.
+
+  The cmake-policies\(7\) manual explains that the OLD behaviors of all
+  policies are deprecated and that a policy should be set to OLD only under
+  specific short-term circumstances.  Projects should be ported to the NEW
+  behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/string/Timestamp-stderr.txt b/Tests/RunCMake/string/Timestamp-stderr.txt
index f162f52..c57bba6 100644
--- a/Tests/RunCMake/string/Timestamp-stderr.txt
+++ b/Tests/RunCMake/string/Timestamp-stderr.txt
@@ -1 +1 @@
-RESULT=2005-08-07 23:19:49.000000 Sunday=Sun August=Aug 05 day=219 wd=0 week=32 w_iso=31 %I=11 epoch=1123456789
+^RESULT=2005-08-07 23:19:49.000000 Sunday=Sun August=Aug 05 day=219 wd=0 week=32 w_iso=31 %I=11 epoch=1123456789 TZ=GMT tz=\+0000$
diff --git a/Tests/RunCMake/string/Timestamp.cmake b/Tests/RunCMake/string/Timestamp.cmake
index 531a237..3d68b1a 100644
--- a/Tests/RunCMake/string/Timestamp.cmake
+++ b/Tests/RunCMake/string/Timestamp.cmake
@@ -1,3 +1,3 @@
 set(ENV{SOURCE_DATE_EPOCH} "1123456789")
-string(TIMESTAMP RESULT "%Y-%m-%d %H:%M:%S.%f %A=%a %B=%b %y day=%j wd=%w week=%U w_iso=%V %%I=%I epoch=%s" UTC)
+string(TIMESTAMP RESULT "%Y-%m-%d %H:%M:%S.%f %A=%a %B=%b %y day=%j wd=%w week=%U w_iso=%V %%I=%I epoch=%s TZ=%Z tz=%z" UTC)
 message("RESULT=${RESULT}")
diff --git a/Tests/RunCMake/target_link_libraries/CMP0108-OLD-self-link-stderr.txt b/Tests/RunCMake/target_link_libraries/CMP0108-OLD-self-link-stderr.txt
new file mode 100644
index 0000000..07e9a9f
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries/CMP0108-OLD-self-link-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0108-OLD-self-link.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0108 will be removed from a future version
+  of CMake.
+
+  The cmake-policies\(7\) manual explains that the OLD behaviors of all
+  policies are deprecated and that a policy should be set to OLD only under
+  specific short-term circumstances.  Projects should be ported to the NEW
+  behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/try_compile/Inspect.cmake b/Tests/RunCMake/try_compile/Inspect.cmake
index added41..2977d02 100644
--- a/Tests/RunCMake/try_compile/Inspect.cmake
+++ b/Tests/RunCMake/try_compile/Inspect.cmake
@@ -1,4 +1,25 @@
+enable_language(C)
 enable_language(CXX)
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/info.cmake" "
-set(CMAKE_CXX_EXTENSIONS_DEFAULT \"${CMAKE_CXX_EXTENSIONS_DEFAULT}\")
-")
+if(CMake_TEST_OBJC)
+  enable_language(OBJC)
+  enable_language(OBJCXX)
+endif()
+
+set(info "")
+foreach(var
+    CMAKE_C_COMPILER_ID
+    CMAKE_C_COMPILER_VERSION
+    CMAKE_C_STANDARD_DEFAULT
+    CMAKE_CXX_COMPILER_ID
+    CMAKE_CXX_COMPILER_VERSION
+    CMAKE_CXX_STANDARD_DEFAULT
+    CMAKE_CXX_EXTENSIONS_DEFAULT
+    CMAKE_OBJC_STANDARD_DEFAULT
+    CMAKE_OBJCXX_STANDARD_DEFAULT
+    )
+  if(DEFINED ${var})
+    string(APPEND info "set(${var} \"${${var}}\")\n")
+  endif()
+endforeach()
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/info.cmake" "${info}")
diff --git a/Tests/RunCMake/try_compile/RunCMakeTest.cmake b/Tests/RunCMake/try_compile/RunCMakeTest.cmake
index 7245471..ad1cc29 100644
--- a/Tests/RunCMake/try_compile/RunCMakeTest.cmake
+++ b/Tests/RunCMake/try_compile/RunCMakeTest.cmake
@@ -1,5 +1,20 @@
 include(RunCMake)
 
+# Detect information from the toolchain:
+# - CMAKE_C_COMPILER_ID
+# - CMAKE_C_COMPILER_VERSION
+# - CMAKE_C_STANDARD_DEFAULT
+# - CMAKE_CXX_COMPILER_ID
+# - CMAKE_CXX_COMPILER_VERSION
+# - CMAKE_CXX_STANDARD_DEFAULT
+# - CMAKE_CXX_EXTENSIONS_DEFAULT
+# - CMAKE_OBJC_STANDARD_DEFAULT
+# - CMAKE_OBJCXX_STANDARD_DEFAULT
+run_cmake_with_options(Inspect
+  -DCMake_TEST_OBJC=${CMake_TEST_OBJC}
+  )
+include("${RunCMake_BINARY_DIR}/Inspect-build/info.cmake")
+
 run_cmake(NoArgs)
 run_cmake(OneArg)
 run_cmake(TwoArgs)
@@ -88,12 +103,6 @@
   unset(RunCMake_TEST_NO_CLEAN)
 endif()
 
-# Lookup CMAKE_CXX_EXTENSIONS_DEFAULT.
-# FIXME: Someday we could move this to the top of the file and use it in
-# place of some of the values passed by 'Tests/RunCMake/CMakeLists.txt'.
-run_cmake(Inspect)
-include("${RunCMake_BINARY_DIR}/Inspect-build/info.cmake")
-
 # FIXME: Support more compilers and default standard levels.
 if (DEFINED CMAKE_CXX_STANDARD_DEFAULT AND
     DEFINED CMAKE_CXX_EXTENSIONS_DEFAULT AND (
diff --git a/Tests/SwiftMixLib/CMakeLists.txt b/Tests/SwiftMixLib/CMakeLists.txt
index 40d3498..a52fc94 100644
--- a/Tests/SwiftMixLib/CMakeLists.txt
+++ b/Tests/SwiftMixLib/CMakeLists.txt
@@ -4,3 +4,6 @@
 add_library(SwiftMixedLib lib.c lib.cpp lib.swift)
 add_executable(Swifty main.swift)
 target_link_libraries(Swifty PUBLIC SwiftMixedLib)
+
+add_executable(c_main main.c)
+target_link_libraries(c_main PUBLIC SwiftMixedLib)
diff --git a/Tests/SwiftMixLib/main.c b/Tests/SwiftMixLib/main.c
new file mode 100644
index 0000000..6ecf984
--- /dev/null
+++ b/Tests/SwiftMixLib/main.c
@@ -0,0 +1,3 @@
+int main(int argc, char* argv[])
+{
+}
diff --git a/Tests/UseSWIG/BasicPerl/CMakeLists.txt b/Tests/UseSWIG/BasicPerl/CMakeLists.txt
index 671d529..1151739 100644
--- a/Tests/UseSWIG/BasicPerl/CMakeLists.txt
+++ b/Tests/UseSWIG/BasicPerl/CMakeLists.txt
@@ -4,7 +4,9 @@
 
 include(CTest)
 
-set(language "perl")
+if(NOT DEFINED language)
+  set(language "perl")
+endif()
 
 include (../BasicConfiguration.cmake)
 
diff --git a/Tests/UseSWIG/CMakeLists.txt b/Tests/UseSWIG/CMakeLists.txt
index c76e8a0..7c4925e 100644
--- a/Tests/UseSWIG/CMakeLists.txt
+++ b/Tests/UseSWIG/CMakeLists.txt
@@ -20,6 +20,16 @@
   --build-options ${build_options}
   --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
   )
+add_test(NAME UseSWIG.LegacyPerl5 COMMAND
+  ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+  --build-and-test
+  "${CMake_SOURCE_DIR}/Tests/UseSWIG/LegacyPerl"
+  "${CMake_BINARY_DIR}/Tests/UseSWIG/LegacyPerl5"
+  ${build_generator_args}
+  --build-project TestLegacyPerl
+  --build-options ${build_options} -Dlanguage=perl5
+  --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+  )
 
 include(CheckLanguage)
 check_language(CSharp)
@@ -66,6 +76,16 @@
   --build-options ${build_options}
   --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
   )
+add_test(NAME UseSWIG.BasicPerl5 COMMAND
+  ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+  --build-and-test
+  "${CMake_SOURCE_DIR}/Tests/UseSWIG/BasicPerl"
+  "${CMake_BINARY_DIR}/Tests/UseSWIG/BasicPerl5"
+  ${build_generator_args}
+  --build-project TestBasicPerl
+  --build-options ${build_options} -Dlanguage=perl5
+  --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+  )
 if(SWIG_FOUND AND NOT SWIG_VERSION VERSION_LESS "4.0.2"
     AND CMAKE_GENERATOR MATCHES "Make|Ninja|Xcode|Visual Studio (1[1-9]|[2-9][0-9])")
   add_test(NAME UseSWIG.Depfile.BasicPython COMMAND
@@ -89,6 +109,16 @@
     --build-options ${build_options} -DSWIG_USE_SWIG_DEPENDENCIES=ON
     --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
     )
+  add_test(NAME UseSWIG.Depfile.BasicPerl5 COMMAND
+    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/UseSWIG/BasicPerl"
+    "${CMake_BINARY_DIR}/Tests/UseSWIG/BasicPerl5.Depfile"
+    ${build_generator_args}
+    --build-project TestBasicPerl
+    --build-options ${build_options} -DSWIG_USE_SWIG_DEPENDENCIES=ON -Dlanguage=perl5
+    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+    )
 endif()
 
 if (CMake_TEST_UseSWIG_Fortran)
diff --git a/Tests/UseSWIG/LegacyPerl/CMakeLists.txt b/Tests/UseSWIG/LegacyPerl/CMakeLists.txt
index 90d92f4..be0b465 100644
--- a/Tests/UseSWIG/LegacyPerl/CMakeLists.txt
+++ b/Tests/UseSWIG/LegacyPerl/CMakeLists.txt
@@ -4,7 +4,9 @@
 
 include(CTest)
 
-set(language "perl")
+if(NOT DEFINED language)
+  set(language "perl")
+endif()
 
 include (../LegacyConfiguration.cmake)
 
diff --git a/Utilities/ClangTidyModule/CMakeLists.txt b/Utilities/ClangTidyModule/CMakeLists.txt
new file mode 100644
index 0000000..51603aa
--- /dev/null
+++ b/Utilities/ClangTidyModule/CMakeLists.txt
@@ -0,0 +1,29 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+cmake_minimum_required(VERSION 3.13)
+project(CMakeClangTidyModule C CXX)
+
+get_filename_component(tmp "${CMAKE_CURRENT_SOURCE_DIR}" PATH)
+get_filename_component(CMake_SOURCE_DIR "${tmp}" PATH)
+
+set(CMAKE_CXX_STANDARD 14)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+find_package(Clang REQUIRED)
+
+add_library(cmake-clang-tidy-module MODULE
+  Module.cxx
+
+  UseCmstrlenCheck.cxx
+  UseCmstrlenCheck.h
+  UseCmsysFstreamCheck.cxx
+  UseCmsysFstreamCheck.h
+  )
+target_include_directories(cmake-clang-tidy-module PRIVATE ${CLANG_INCLUDE_DIRS})
+target_link_libraries(cmake-clang-tidy-module PRIVATE clang-tidy)
+
+option(RUN_TESTS "Run the tests for the clang-tidy module" OFF)
+if(RUN_TESTS)
+  enable_testing()
+  add_subdirectory(Tests)
+endif()
diff --git a/Utilities/ClangTidyModule/Module.cxx b/Utilities/ClangTidyModule/Module.cxx
new file mode 100644
index 0000000..a9d344f
--- /dev/null
+++ b/Utilities/ClangTidyModule/Module.cxx
@@ -0,0 +1,27 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#include <clang-tidy/ClangTidyModule.h>
+#include <clang-tidy/ClangTidyModuleRegistry.h>
+
+#include "UseCmstrlenCheck.h"
+#include "UseCmsysFstreamCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace cmake {
+class CMakeClangTidyModule : public ClangTidyModule
+{
+public:
+  void addCheckFactories(ClangTidyCheckFactories& CheckFactories) override
+  {
+    CheckFactories.registerCheck<UseCmstrlenCheck>("cmake-use-cmstrlen");
+    CheckFactories.registerCheck<UseCmsysFstreamCheck>(
+      "cmake-use-cmsys-fstream");
+  }
+};
+
+static ClangTidyModuleRegistry::Add<CMakeClangTidyModule> X(
+  "cmake-clang-tidy", "Adds lint checks for the CMake code base.");
+}
+}
+}
diff --git a/Utilities/ClangTidyModule/Tests/CMakeLists.txt b/Utilities/ClangTidyModule/Tests/CMakeLists.txt
new file mode 100644
index 0000000..a66eaa8
--- /dev/null
+++ b/Utilities/ClangTidyModule/Tests/CMakeLists.txt
@@ -0,0 +1,14 @@
+configure_file("${CMake_SOURCE_DIR}/.clang-format" ".clang-format" COPYONLY)
+
+function(add_run_clang_tidy_test check_name)
+  add_test(NAME "RunClangTidy.${check_name}" COMMAND ${CMAKE_COMMAND}
+    "-DCLANG_TIDY_COMMAND=$<TARGET_FILE:clang-tidy>"
+    "-DCLANG_TIDY_MODULE=$<TARGET_FILE:cmake-clang-tidy-module>"
+    "-DCHECK_NAME=${check_name}"
+    "-DRunClangTidy_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}"
+    -P "${CMAKE_CURRENT_SOURCE_DIR}/RunClangTidy.cmake"
+    )
+endfunction()
+
+add_run_clang_tidy_test(cmake-use-cmstrlen)
+add_run_clang_tidy_test(cmake-use-cmsys-fstream)
diff --git a/Utilities/ClangTidyModule/Tests/RunClangTidy.cmake b/Utilities/ClangTidyModule/Tests/RunClangTidy.cmake
new file mode 100644
index 0000000..7fd7cdd
--- /dev/null
+++ b/Utilities/ClangTidyModule/Tests/RunClangTidy.cmake
@@ -0,0 +1,63 @@
+set(config_arg)
+if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}.clang-tidy")
+  set(config_arg "--config-file=${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}.clang-tidy")
+endif()
+
+if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}-stdout.txt")
+  file(READ "${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}-stdout.txt" expect_stdout)
+  string(REGEX REPLACE "\n+$" "" expect_stdout "${expect_stdout}")
+else()
+  set(expect_stdout "")
+endif()
+
+set(source_file "${RunClangTidy_BINARY_DIR}/${CHECK_NAME}.cxx")
+configure_file("${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}.cxx" "${source_file}" COPYONLY)
+
+set(command
+  "${CLANG_TIDY_COMMAND}"
+  "--load=${CLANG_TIDY_MODULE}"
+  "--checks=-*,${CHECK_NAME}"
+  "--fix"
+  "--format-style=file"
+  ${config_arg}
+  "${source_file}"
+  --
+  )
+execute_process(
+  COMMAND ${command}
+  RESULT_VARIABLE result
+  OUTPUT_VARIABLE actual_stdout
+  ERROR_VARIABLE actual_stderr
+  )
+string(REPLACE "${RunClangTidy_BINARY_DIR}/" "" actual_stdout "${actual_stdout}")
+
+set(RunClangTidy_TEST_FAILED)
+
+if(NOT result EQUAL 0)
+  string(APPEND RunClangTidy_TEST_FAILED "Expected result: 0, actual result: ${result}\n")
+endif()
+
+string(REGEX REPLACE "\n+$" "" actual_stdout "${actual_stdout}")
+if(NOT actual_stdout STREQUAL expect_stdout)
+  string(REPLACE "\n" "\n  " expect_stdout_formatted "  ${expect_stdout}")
+  string(REPLACE "\n" "\n  " actual_stdout_formatted "  ${actual_stdout}")
+  string(APPEND RunClangTidy_TEST_FAILED "Expected stdout:\n${expect_stdout_formatted}\nActual stdout:\n${actual_stdout_formatted}\n")
+endif()
+
+if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}-fixit.cxx")
+  set(expect_fixit_file "${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}-fixit.cxx")
+else()
+  set(expect_fixit_file "${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}.cxx")
+endif()
+file(READ "${expect_fixit_file}" expect_fixit)
+file(READ "${source_file}" actual_fixit)
+if(NOT expect_fixit STREQUAL actual_fixit)
+  string(REPLACE "\n" "\n  " expect_fixit_formatted "  ${expect_fixit}")
+  string(REPLACE "\n" "\n  " actual_fixit_formatted "  ${actual_fixit}")
+  string(APPEND RunClangTidy_TEST_FAILED "Expected fixit:\n${expect_fixit_formatted}\nActual fixit:\n${actual_fixit_formatted}\n")
+endif()
+
+if(RunClangTidy_TEST_FAILED)
+  string(REPLACE ";" " " command_formatted "${command}")
+  message(FATAL_ERROR "Command:\n  ${command_formatted}\n${RunClangTidy_TEST_FAILED}")
+endif()
diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen-fixit.cxx b/Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen-fixit.cxx
new file mode 100644
index 0000000..c93d557
--- /dev/null
+++ b/Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen-fixit.cxx
@@ -0,0 +1,37 @@
+#include <cstring>
+
+template <size_t N>
+constexpr size_t cmStrLen(const char (&/*str*/)[N])
+{
+  return N - 1;
+}
+
+namespace ns1 {
+using std::strlen;
+}
+
+namespace ns2 {
+std::size_t strlen(const char* str)
+{
+  return std::strlen(str);
+}
+}
+
+int main()
+{
+  // String variable used for calling strlen() on a variable
+  auto s0 = "howdy";
+
+  // Correction needed
+  (void)cmStrLen("Hello");
+  (void)cmStrLen("Goodbye");
+  (void)cmStrLen("Hola");
+  (void)cmStrLen("Bonjour");
+
+  // No correction needed
+  (void)ns2::strlen("Salve");
+  (void)cmStrLen("Konnichiwa");
+  (void)strlen(s0);
+
+  return 0;
+}
diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen-stdout.txt b/Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen-stdout.txt
new file mode 100644
index 0000000..6c52ad5
--- /dev/null
+++ b/Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen-stdout.txt
@@ -0,0 +1,20 @@
+cmake-use-cmstrlen.cxx:26:9: warning: use cmStrLen() for string literals [cmake-use-cmstrlen]
+  (void)strlen("Hello");
+        ^~~~~~
+        cmStrLen
+cmake-use-cmstrlen.cxx:26:9: note: FIX-IT applied suggested code changes
+cmake-use-cmstrlen.cxx:27:9: warning: use cmStrLen() for string literals [cmake-use-cmstrlen]
+  (void)::strlen("Goodbye");
+        ^~~~~~~~
+        cmStrLen
+cmake-use-cmstrlen.cxx:27:9: note: FIX-IT applied suggested code changes
+cmake-use-cmstrlen.cxx:28:9: warning: use cmStrLen() for string literals [cmake-use-cmstrlen]
+  (void)std::strlen("Hola");
+        ^~~~~~~~~~~
+        cmStrLen
+cmake-use-cmstrlen.cxx:28:9: note: FIX-IT applied suggested code changes
+cmake-use-cmstrlen.cxx:29:9: warning: use cmStrLen() for string literals [cmake-use-cmstrlen]
+  (void)ns1::strlen("Bonjour");
+        ^~~~~~~~~~~
+        cmStrLen
+cmake-use-cmstrlen.cxx:29:9: note: FIX-IT applied suggested code changes
diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen.cxx b/Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen.cxx
new file mode 100644
index 0000000..f36262b
--- /dev/null
+++ b/Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen.cxx
@@ -0,0 +1,37 @@
+#include <cstring>
+
+template <size_t N>
+constexpr size_t cmStrLen(const char (&/*str*/)[N])
+{
+  return N - 1;
+}
+
+namespace ns1 {
+using std::strlen;
+}
+
+namespace ns2 {
+std::size_t strlen(const char* str)
+{
+  return std::strlen(str);
+}
+}
+
+int main()
+{
+  // String variable used for calling strlen() on a variable
+  auto s0 = "howdy";
+
+  // Correction needed
+  (void)strlen("Hello");
+  (void)::strlen("Goodbye");
+  (void)std::strlen("Hola");
+  (void)ns1::strlen("Bonjour");
+
+  // No correction needed
+  (void)ns2::strlen("Salve");
+  (void)cmStrLen("Konnichiwa");
+  (void)strlen(s0);
+
+  return 0;
+}
diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-cmsys-fstream-fixit.cxx b/Utilities/ClangTidyModule/Tests/cmake-use-cmsys-fstream-fixit.cxx
new file mode 100644
index 0000000..5c7c123
--- /dev/null
+++ b/Utilities/ClangTidyModule/Tests/cmake-use-cmsys-fstream-fixit.cxx
@@ -0,0 +1,81 @@
+#include <fstream>
+#include <vector>
+
+namespace cmsys {
+using std::ifstream;
+using std::ofstream;
+using std::fstream;
+}
+
+namespace ns {
+using std::ifstream;
+using std::ofstream;
+using std::fstream;
+
+namespace ns {
+using std::ifstream;
+using std::ofstream;
+using std::fstream;
+}
+
+class cl
+{
+public:
+  using ifstream = cmsys::ifstream;
+  using ofstream = cmsys::ofstream;
+  using fstream = cmsys::fstream;
+};
+
+using ifs = cmsys::ifstream;
+using ofs = cmsys::ofstream;
+using fs = cmsys::fstream;
+}
+
+int main()
+{
+  using std::ifstream;
+  using std::ofstream;
+  using std::fstream;
+
+  // Correction needed
+  cmsys::ifstream ifsUnqual;
+  cmsys::ifstream ifsQual;
+  cmsys::ifstream ifsNS;
+  cmsys::ifstream ifsNested;
+  cmsys::ifstream ifsClass;
+  cmsys::ifstream ifsRenamed;
+
+  cmsys::ofstream ofsUnqual;
+  cmsys::ofstream ofsQual;
+  cmsys::ofstream ofsNS;
+  cmsys::ofstream ofsNested;
+  cmsys::ofstream ofsClass;
+  cmsys::ofstream ofsRenamed;
+
+  cmsys::fstream fsUnqual;
+  cmsys::fstream fsQual;
+  cmsys::fstream fsNS;
+  cmsys::fstream fsNested;
+  cmsys::fstream fsClass;
+  cmsys::fstream fsRenamed;
+
+  cmsys::ifstream::off_type offsetQual = 0;
+  cmsys::ifstream::off_type offsetUnqual = 0;
+  cmsys::ifstream::off_type offsetNS = 0;
+  cmsys::ifstream::off_type offsetNested = 0;
+  cmsys::ifstream::traits_type::off_type offsetTraitsNested = 0;
+  cmsys::ifstream::traits_type::off_type offsetTraitsClass = 0;
+
+  std::vector<cmsys::ifstream> ifsVectorUnqual;
+
+  // No correction needed
+  cmsys::ifstream ifsCmsys;
+  cmsys::ofstream ofsCmsys;
+  cmsys::fstream fsCmsys;
+  cmsys::ifstream::off_type offsetCmsys = 0;
+  cmsys::ifstream::traits_type::off_type offsetTraitsCmsys = 0;
+  std::vector<cmsys::ifstream> ifsVectorCmsys;
+  std::basic_ifstream<wchar_t> ifsWchar;
+
+  return 0;
+}
diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-cmsys-fstream-stdout.txt b/Utilities/ClangTidyModule/Tests/cmake-use-cmsys-fstream-stdout.txt
new file mode 100644
index 0000000..d2c45f2
--- /dev/null
+++ b/Utilities/ClangTidyModule/Tests/cmake-use-cmsys-fstream-stdout.txt
@@ -0,0 +1,155 @@
+cmake-use-cmsys-fstream.cxx:24:20: warning: use cmsys::ifstream [cmake-use-cmsys-fstream]
+  using ifstream = std::ifstream;
+                   ^~~~~~~~~~~~~
+                   cmsys::ifstream
+cmake-use-cmsys-fstream.cxx:24:20: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:25:20: warning: use cmsys::ofstream [cmake-use-cmsys-fstream]
+  using ofstream = std::ofstream;
+                   ^~~~~~~~~~~~~
+                   cmsys::ofstream
+cmake-use-cmsys-fstream.cxx:25:20: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:26:19: warning: use cmsys::fstream [cmake-use-cmsys-fstream]
+  using fstream = std::fstream;
+                  ^~~~~~~~~~~~
+                  cmsys::fstream
+cmake-use-cmsys-fstream.cxx:26:19: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:29:13: warning: use cmsys::ifstream [cmake-use-cmsys-fstream]
+using ifs = std::ifstream;
+            ^~~~~~~~~~~~~
+            cmsys::ifstream
+cmake-use-cmsys-fstream.cxx:29:13: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:30:13: warning: use cmsys::ofstream [cmake-use-cmsys-fstream]
+using ofs = std::ofstream;
+            ^~~~~~~~~~~~~
+            cmsys::ofstream
+cmake-use-cmsys-fstream.cxx:30:13: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:31:12: warning: use cmsys::fstream [cmake-use-cmsys-fstream]
+using fs = std::fstream;
+           ^~~~~~~~~~~~
+           cmsys::fstream
+cmake-use-cmsys-fstream.cxx:31:12: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:41:3: warning: use cmsys::ifstream [cmake-use-cmsys-fstream]
+  ifstream ifsUnqual;
+  ^~~~~~~~
+  cmsys::ifstream
+cmake-use-cmsys-fstream.cxx:41:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:42:3: warning: use cmsys::ifstream [cmake-use-cmsys-fstream]
+  std::ifstream ifsQual;
+  ^~~~~~~~~~~~~
+  cmsys::ifstream
+cmake-use-cmsys-fstream.cxx:42:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:43:3: warning: use cmsys::ifstream [cmake-use-cmsys-fstream]
+  ns::ifstream ifsNS;
+  ^~~~~~~~~~~~
+  cmsys::ifstream
+cmake-use-cmsys-fstream.cxx:43:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:44:3: warning: use cmsys::ifstream [cmake-use-cmsys-fstream]
+  ns::ns::ifstream ifsNested;
+  ^~~~~~~~~~~~~~~~
+  cmsys::ifstream
+cmake-use-cmsys-fstream.cxx:44:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:45:3: warning: use cmsys::ifstream [cmake-use-cmsys-fstream]
+  ns::cl::ifstream ifsClass;
+  ^~~~~~~~~~~~~~~~
+  cmsys::ifstream
+cmake-use-cmsys-fstream.cxx:45:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:46:3: warning: use cmsys::ifstream [cmake-use-cmsys-fstream]
+  ns::ifs ifsRenamed;
+  ^~~~~~~
+  cmsys::ifstream
+cmake-use-cmsys-fstream.cxx:46:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:48:3: warning: use cmsys::ofstream [cmake-use-cmsys-fstream]
+  ofstream ofsUnqual;
+  ^~~~~~~~
+  cmsys::ofstream
+cmake-use-cmsys-fstream.cxx:48:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:49:3: warning: use cmsys::ofstream [cmake-use-cmsys-fstream]
+  std::ofstream ofsQual;
+  ^~~~~~~~~~~~~
+  cmsys::ofstream
+cmake-use-cmsys-fstream.cxx:49:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:50:3: warning: use cmsys::ofstream [cmake-use-cmsys-fstream]
+  ns::ofstream ofsNS;
+  ^~~~~~~~~~~~
+  cmsys::ofstream
+cmake-use-cmsys-fstream.cxx:50:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:51:3: warning: use cmsys::ofstream [cmake-use-cmsys-fstream]
+  ns::ns::ofstream ofsNested;
+  ^~~~~~~~~~~~~~~~
+  cmsys::ofstream
+cmake-use-cmsys-fstream.cxx:51:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:52:3: warning: use cmsys::ofstream [cmake-use-cmsys-fstream]
+  ns::cl::ofstream ofsClass;
+  ^~~~~~~~~~~~~~~~
+  cmsys::ofstream
+cmake-use-cmsys-fstream.cxx:52:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:53:3: warning: use cmsys::ofstream [cmake-use-cmsys-fstream]
+  ns::ofs ofsRenamed;
+  ^~~~~~~
+  cmsys::ofstream
+cmake-use-cmsys-fstream.cxx:53:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:55:3: warning: use cmsys::fstream [cmake-use-cmsys-fstream]
+  fstream fsUnqual;
+  ^~~~~~~
+  cmsys::fstream
+cmake-use-cmsys-fstream.cxx:55:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:56:3: warning: use cmsys::fstream [cmake-use-cmsys-fstream]
+  std::fstream fsQual;
+  ^~~~~~~~~~~~
+  cmsys::fstream
+cmake-use-cmsys-fstream.cxx:56:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:57:3: warning: use cmsys::fstream [cmake-use-cmsys-fstream]
+  ns::fstream fsNS;
+  ^~~~~~~~~~~
+  cmsys::fstream
+cmake-use-cmsys-fstream.cxx:57:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:58:3: warning: use cmsys::fstream [cmake-use-cmsys-fstream]
+  ns::ns::fstream fsNested;
+  ^~~~~~~~~~~~~~~
+  cmsys::fstream
+cmake-use-cmsys-fstream.cxx:58:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:59:3: warning: use cmsys::fstream [cmake-use-cmsys-fstream]
+  ns::ns::fstream fsClass;
+  ^~~~~~~~~~~~~~~
+  cmsys::fstream
+cmake-use-cmsys-fstream.cxx:59:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:60:3: warning: use cmsys::fstream [cmake-use-cmsys-fstream]
+  ns::fs fsRenamed;
+  ^~~~~~
+  cmsys::fstream
+cmake-use-cmsys-fstream.cxx:60:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:62:3: warning: use cmsys::ifstream [cmake-use-cmsys-fstream]
+  std::ifstream::off_type offsetQual = 0;
+  ^~~~~~~~~~~~~
+  cmsys::ifstream
+cmake-use-cmsys-fstream.cxx:62:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:63:3: warning: use cmsys::ifstream [cmake-use-cmsys-fstream]
+  ifstream::off_type offsetUnqual = 0;
+  ^~~~~~~~
+  cmsys::ifstream
+cmake-use-cmsys-fstream.cxx:63:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:64:3: warning: use cmsys::ifstream [cmake-use-cmsys-fstream]
+  ns::ifstream::off_type offsetNS = 0;
+  ^~~~~~~~~~~~
+  cmsys::ifstream
+cmake-use-cmsys-fstream.cxx:64:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:65:3: warning: use cmsys::ifstream [cmake-use-cmsys-fstream]
+  ns::ns::ifstream::off_type offsetNested = 0;
+  ^~~~~~~~~~~~~~~~
+  cmsys::ifstream
+cmake-use-cmsys-fstream.cxx:65:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:66:3: warning: use cmsys::ifstream [cmake-use-cmsys-fstream]
+  ns::ns::ifstream::traits_type::off_type offsetTraitsNested = 0;
+  ^~~~~~~~~~~~~~~~
+  cmsys::ifstream
+cmake-use-cmsys-fstream.cxx:66:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:67:3: warning: use cmsys::ifstream [cmake-use-cmsys-fstream]
+  ns::cl::ifstream::traits_type::off_type offsetTraitsClass = 0;
+  ^~~~~~~~~~~~~~~~
+  cmsys::ifstream
+cmake-use-cmsys-fstream.cxx:67:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:69:15: warning: use cmsys::ifstream [cmake-use-cmsys-fstream]
+  std::vector<ifstream> ifsVectorUnqual;
+              ^~~~~~~~
+              cmsys::ifstream
+cmake-use-cmsys-fstream.cxx:69:15: note: FIX-IT applied suggested code changes
diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-cmsys-fstream.cxx b/Utilities/ClangTidyModule/Tests/cmake-use-cmsys-fstream.cxx
new file mode 100644
index 0000000..56a7611
--- /dev/null
+++ b/Utilities/ClangTidyModule/Tests/cmake-use-cmsys-fstream.cxx
@@ -0,0 +1,81 @@
+#include <fstream>
+#include <vector>
+
+namespace cmsys {
+using std::ifstream;
+using std::ofstream;
+using std::fstream;
+}
+
+namespace ns {
+using std::ifstream;
+using std::ofstream;
+using std::fstream;
+
+namespace ns {
+using std::ifstream;
+using std::ofstream;
+using std::fstream;
+}
+
+class cl
+{
+public:
+  using ifstream = std::ifstream;
+  using ofstream = std::ofstream;
+  using fstream = std::fstream;
+};
+
+using ifs = std::ifstream;
+using ofs = std::ofstream;
+using fs = std::fstream;
+}
+
+int main()
+{
+  using std::ifstream;
+  using std::ofstream;
+  using std::fstream;
+
+  // Correction needed
+  ifstream ifsUnqual;
+  std::ifstream ifsQual;
+  ns::ifstream ifsNS;
+  ns::ns::ifstream ifsNested;
+  ns::cl::ifstream ifsClass;
+  ns::ifs ifsRenamed;
+
+  ofstream ofsUnqual;
+  std::ofstream ofsQual;
+  ns::ofstream ofsNS;
+  ns::ns::ofstream ofsNested;
+  ns::cl::ofstream ofsClass;
+  ns::ofs ofsRenamed;
+
+  fstream fsUnqual;
+  std::fstream fsQual;
+  ns::fstream fsNS;
+  ns::ns::fstream fsNested;
+  ns::ns::fstream fsClass;
+  ns::fs fsRenamed;
+
+  std::ifstream::off_type offsetQual = 0;
+  ifstream::off_type offsetUnqual = 0;
+  ns::ifstream::off_type offsetNS = 0;
+  ns::ns::ifstream::off_type offsetNested = 0;
+  ns::ns::ifstream::traits_type::off_type offsetTraitsNested = 0;
+  ns::cl::ifstream::traits_type::off_type offsetTraitsClass = 0;
+
+  std::vector<ifstream> ifsVectorUnqual;
+
+  // No correction needed
+  cmsys::ifstream ifsCmsys;
+  cmsys::ofstream ofsCmsys;
+  cmsys::fstream fsCmsys;
+  cmsys::ifstream::off_type offsetCmsys = 0;
+  cmsys::ifstream::traits_type::off_type offsetTraitsCmsys = 0;
+  std::vector<cmsys::ifstream> ifsVectorCmsys;
+  std::basic_ifstream<wchar_t> ifsWchar;
+
+  return 0;
+}
diff --git a/Utilities/ClangTidyModule/UseCmstrlenCheck.cxx b/Utilities/ClangTidyModule/UseCmstrlenCheck.cxx
new file mode 100644
index 0000000..590d260
--- /dev/null
+++ b/Utilities/ClangTidyModule/UseCmstrlenCheck.cxx
@@ -0,0 +1,34 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#include "UseCmstrlenCheck.h"
+
+#include <clang/ASTMatchers/ASTMatchFinder.h>
+
+namespace clang {
+namespace tidy {
+namespace cmake {
+using namespace ast_matchers;
+
+UseCmstrlenCheck::UseCmstrlenCheck(StringRef Name, ClangTidyContext* Context)
+  : ClangTidyCheck(Name, Context)
+{
+}
+
+void UseCmstrlenCheck::registerMatchers(MatchFinder* Finder)
+{
+  Finder->addMatcher(callExpr(callee(functionDecl(hasName("::strlen"))),
+                              callee(expr().bind("callee")),
+                              hasArgument(0, stringLiteral())),
+                     this);
+}
+
+void UseCmstrlenCheck::check(const MatchFinder::MatchResult& Result)
+{
+  const Expr* Node = Result.Nodes.getNodeAs<Expr>("callee");
+
+  this->diag(Node->getBeginLoc(), "use cmStrLen() for string literals")
+    << FixItHint::CreateReplacement(Node->getSourceRange(), "cmStrLen");
+}
+}
+}
+}
diff --git a/Utilities/ClangTidyModule/UseCmstrlenCheck.h b/Utilities/ClangTidyModule/UseCmstrlenCheck.h
new file mode 100644
index 0000000..08f77c2
--- /dev/null
+++ b/Utilities/ClangTidyModule/UseCmstrlenCheck.h
@@ -0,0 +1,21 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#pragma once
+
+#include <clang-tidy/ClangTidyCheck.h>
+#include <clang/ASTMatchers/ASTMatchFinder.h>
+
+namespace clang {
+namespace tidy {
+namespace cmake {
+class UseCmstrlenCheck : public ClangTidyCheck
+{
+public:
+  UseCmstrlenCheck(StringRef Name, ClangTidyContext* Context);
+  void registerMatchers(ast_matchers::MatchFinder* Finder) override;
+
+  void check(const ast_matchers::MatchFinder::MatchResult& Result) override;
+};
+}
+}
+}
diff --git a/Utilities/ClangTidyModule/UseCmsysFstreamCheck.cxx b/Utilities/ClangTidyModule/UseCmsysFstreamCheck.cxx
new file mode 100644
index 0000000..95a0a4d
--- /dev/null
+++ b/Utilities/ClangTidyModule/UseCmsysFstreamCheck.cxx
@@ -0,0 +1,101 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#include "UseCmsysFstreamCheck.h"
+
+#include <clang/ASTMatchers/ASTMatchFinder.h>
+
+namespace clang {
+namespace tidy {
+namespace cmake {
+using namespace ast_matchers;
+
+UseCmsysFstreamCheck::UseCmsysFstreamCheck(StringRef Name,
+                                           ClangTidyContext* Context)
+  : ClangTidyCheck(Name, Context)
+{
+}
+
+void UseCmsysFstreamCheck::registerMatchers(MatchFinder* Finder)
+{
+  this->createMatcher("::std::basic_ifstream", "::cmsys::ifstream", Finder,
+                      "ifstream");
+  this->createMatcher("::std::basic_ofstream", "::cmsys::ofstream", Finder,
+                      "ofstream");
+  this->createMatcher("::std::basic_fstream", "::cmsys::fstream", Finder,
+                      "fstream");
+}
+
+void UseCmsysFstreamCheck::check(const MatchFinder::MatchResult& Result)
+{
+  const TypeLoc* ParentTypeNode =
+    Result.Nodes.getNodeAs<TypeLoc>("parentType");
+  const NestedNameSpecifierLoc* ParentNameNode =
+    Result.Nodes.getNodeAs<NestedNameSpecifierLoc>("parentName");
+  const TypeLoc* RootNode = nullptr;
+  StringRef BindName;
+  StringRef Warning;
+
+  if ((RootNode = Result.Nodes.getNodeAs<TypeLoc>("ifstream")) != nullptr) {
+    BindName = "cmsys::ifstream";
+    Warning = "use cmsys::ifstream";
+  } else if ((RootNode = Result.Nodes.getNodeAs<TypeLoc>("ofstream")) !=
+             nullptr) {
+    BindName = "cmsys::ofstream";
+    Warning = "use cmsys::ofstream";
+  } else if ((RootNode = Result.Nodes.getNodeAs<TypeLoc>("fstream")) !=
+             nullptr) {
+    BindName = "cmsys::fstream";
+    Warning = "use cmsys::fstream";
+  }
+
+  if (ParentTypeNode != nullptr) {
+    if (ParentTypeNode->getBeginLoc().isValid()) {
+      this->diag(ParentTypeNode->getBeginLoc(), Warning)
+        << FixItHint::CreateReplacement(ParentTypeNode->getSourceRange(),
+                                        BindName);
+    }
+  } else if (ParentNameNode != nullptr) {
+    if (ParentNameNode->getBeginLoc().isValid()) {
+      this->diag(ParentNameNode->getBeginLoc(), Warning)
+        << FixItHint::CreateReplacement(
+             SourceRange(ParentNameNode->getBeginLoc(), RootNode->getEndLoc()),
+             BindName);
+    }
+  } else if (RootNode != nullptr) {
+    if (RootNode->getBeginLoc().isValid()) {
+      this->diag(RootNode->getBeginLoc(), Warning)
+        << FixItHint::CreateReplacement(RootNode->getSourceRange(), BindName);
+    }
+  }
+}
+
+void UseCmsysFstreamCheck::createMatcher(StringRef StdName,
+                                         StringRef CmsysName,
+                                         ast_matchers::MatchFinder* Finder,
+                                         StringRef Bind)
+{
+  TypeLocMatcher IsStd = loc(qualType(hasUnqualifiedDesugaredType(
+    recordType(hasDeclaration(classTemplateSpecializationDecl(
+      hasName(StdName),
+      hasTemplateArgument(
+        0, templateArgument(refersToType(asString("char"))))))))));
+
+  // TODO This only checks to see if the type directly refers to
+  // cmsys::fstream. There are some corner cases involving template parameters
+  // that refer to cmsys::fstream that are missed by this matcher, resulting in
+  // a false positive. Figure out how to find these indirect references to
+  // cmsys::fstream and filter them out. In the meantime, such false positives
+  // can be silenced with NOLINT(cmake-use-cmsys-fstream).
+  TypeLocMatcher IsCmsys =
+    loc(usingType(throughUsingDecl(namedDecl(hasName(CmsysName)))));
+
+  Finder->addMatcher(
+    typeLoc(IsStd, unless(IsCmsys), unless(elaboratedTypeLoc()),
+            optionally(hasParent(elaboratedTypeLoc().bind("parentType"))),
+            optionally(hasParent(nestedNameSpecifierLoc().bind("parentName"))))
+      .bind(Bind),
+    this);
+}
+}
+}
+}
diff --git a/Utilities/ClangTidyModule/UseCmsysFstreamCheck.h b/Utilities/ClangTidyModule/UseCmsysFstreamCheck.h
new file mode 100644
index 0000000..782123c
--- /dev/null
+++ b/Utilities/ClangTidyModule/UseCmsysFstreamCheck.h
@@ -0,0 +1,24 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#pragma once
+
+#include <clang-tidy/ClangTidyCheck.h>
+#include <clang/ASTMatchers/ASTMatchFinder.h>
+
+namespace clang {
+namespace tidy {
+namespace cmake {
+class UseCmsysFstreamCheck : public ClangTidyCheck
+{
+public:
+  UseCmsysFstreamCheck(StringRef Name, ClangTidyContext* Context);
+  void registerMatchers(ast_matchers::MatchFinder* Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult& Result) override;
+
+private:
+  void createMatcher(StringRef name, StringRef CmsysName,
+                     ast_matchers::MatchFinder* Finder, StringRef bind);
+};
+}
+}
+}
diff --git a/Utilities/Doxygen/CMakeLists.txt b/Utilities/Doxygen/CMakeLists.txt
index bc16350..b084dd5 100644
--- a/Utilities/Doxygen/CMakeLists.txt
+++ b/Utilities/Doxygen/CMakeLists.txt
@@ -3,7 +3,7 @@
 
 if(NOT CMake_SOURCE_DIR)
   set(CMakeDeveloperReference_STANDALONE 1)
-  cmake_minimum_required(VERSION 3.13...3.23 FATAL_ERROR)
+  cmake_minimum_required(VERSION 3.13...3.24 FATAL_ERROR)
   get_filename_component(tmp "${CMAKE_CURRENT_SOURCE_DIR}" PATH)
   get_filename_component(CMake_SOURCE_DIR "${tmp}" PATH)
   include(${CMake_SOURCE_DIR}/Modules/CTestUseLaunchers.cmake)
diff --git a/Utilities/Scripts/update-nghttp2.bash b/Utilities/Scripts/update-nghttp2.bash
index 07a8f13..bc76377 100755
--- a/Utilities/Scripts/update-nghttp2.bash
+++ b/Utilities/Scripts/update-nghttp2.bash
@@ -8,7 +8,7 @@
 readonly ownership="nghttp2 upstream <kwrobot@kitware.com>"
 readonly subtree="Utilities/cmnghttp2"
 readonly repo="https://github.com/nghttp2/nghttp2.git"
-readonly tag="v1.40.0"
+readonly tag="v1.50.0"
 readonly shortlog=false
 readonly paths="
   COPYING
diff --git a/Utilities/Sphinx/CMakeLists.txt b/Utilities/Sphinx/CMakeLists.txt
index 886f4e0..bd2f305 100644
--- a/Utilities/Sphinx/CMakeLists.txt
+++ b/Utilities/Sphinx/CMakeLists.txt
@@ -3,7 +3,7 @@
 
 if(NOT CMake_SOURCE_DIR)
   set(CMakeHelp_STANDALONE 1)
-  cmake_minimum_required(VERSION 3.13...3.23 FATAL_ERROR)
+  cmake_minimum_required(VERSION 3.13...3.24 FATAL_ERROR)
   get_filename_component(tmp "${CMAKE_CURRENT_SOURCE_DIR}" PATH)
   get_filename_component(CMake_SOURCE_DIR "${tmp}" PATH)
   include(${CMake_SOURCE_DIR}/Modules/CTestUseLaunchers.cmake)
diff --git a/Utilities/Sphinx/cmake.py b/Utilities/Sphinx/cmake.py
index c7b1233..47e4909 100644
--- a/Utilities/Sphinx/cmake.py
+++ b/Utilities/Sphinx/cmake.py
@@ -475,3 +475,4 @@
     app.add_transform(CMakeTransform)
     app.add_transform(CMakeXRefTransform)
     app.add_domain(CMakeDomain)
+    return {"parallel_read_safe": True}
diff --git a/Utilities/cmnghttp2/CMakeLists.txt b/Utilities/cmnghttp2/CMakeLists.txt
index 9002ab6..6d0c76f 100644
--- a/Utilities/cmnghttp2/CMakeLists.txt
+++ b/Utilities/cmnghttp2/CMakeLists.txt
@@ -19,6 +19,7 @@
   lib/nghttp2_buf.c
   lib/nghttp2_callbacks.c
   lib/nghttp2_debug.c
+  lib/nghttp2_extpri.c
   lib/nghttp2_frame.c
   lib/nghttp2_hd.c
   lib/nghttp2_hd_huffman.c
diff --git a/Utilities/cmnghttp2/lib/includes/nghttp2/nghttp2.h b/Utilities/cmnghttp2/lib/includes/nghttp2/nghttp2.h
index e3aeb9f..61a14d9 100644
--- a/Utilities/cmnghttp2/lib/includes/nghttp2/nghttp2.h
+++ b/Utilities/cmnghttp2/lib/includes/nghttp2/nghttp2.h
@@ -229,6 +229,13 @@
 #define NGHTTP2_CLIENT_MAGIC_LEN 24
 
 /**
+ * @macro
+ *
+ * The default max number of settings per SETTINGS frame
+ */
+#define NGHTTP2_DEFAULT_MAX_SETTINGS 32
+
+/**
  * @enum
  *
  * Error codes used in this library.  The code range is [-999, -500],
@@ -399,12 +406,17 @@
    */
   NGHTTP2_ERR_SETTINGS_EXPECTED = -536,
   /**
-   * The errors < :enum:`NGHTTP2_ERR_FATAL` mean that the library is
-   * under unexpected condition and processing was terminated (e.g.,
-   * out of memory).  If application receives this error code, it must
-   * stop using that :type:`nghttp2_session` object and only allowed
-   * operation for that object is deallocate it using
-   * `nghttp2_session_del()`.
+   * When a local endpoint receives too many settings entries
+   * in a single SETTINGS frame.
+   */
+  NGHTTP2_ERR_TOO_MANY_SETTINGS = -537,
+  /**
+   * The errors < :enum:`nghttp2_error.NGHTTP2_ERR_FATAL` mean that
+   * the library is under unexpected condition and processing was
+   * terminated (e.g., out of memory).  If application receives this
+   * error code, it must stop using that :type:`nghttp2_session`
+   * object and only allowed operation for that object is deallocate
+   * it using `nghttp2_session_del()`.
    */
   NGHTTP2_ERR_FATAL = -900,
   /**
@@ -533,9 +545,9 @@
    * :type:`nghttp2_on_frame_send_callback`, and
    * :type:`nghttp2_on_frame_not_send_callback`), it may not be
    * NULL-terminated if header field is passed from application with
-   * the flag :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`).  When application
-   * is constructing this struct, |name| is not required to be
-   * NULL-terminated.
+   * the flag :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME`).
+   * When application is constructing this struct, |name| is not
+   * required to be NULL-terminated.
    */
   uint8_t *name;
   /**
@@ -546,9 +558,9 @@
    * :type:`nghttp2_on_frame_send_callback`, and
    * :type:`nghttp2_on_frame_not_send_callback`), it may not be
    * NULL-terminated if header field is passed from application with
-   * the flag :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE`).  When
-   * application is constructing this struct, |value| is not required
-   * to be NULL-terminated.
+   * the flag :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_VALUE`).
+   * When application is constructing this struct, |value| is not
+   * required to be NULL-terminated.
    */
   uint8_t *value;
   /**
@@ -622,7 +634,11 @@
    * The ORIGIN frame, which is defined by `RFC 8336
    * <https://tools.ietf.org/html/rfc8336>`_.
    */
-  NGHTTP2_ORIGIN = 0x0c
+  NGHTTP2_ORIGIN = 0x0c,
+  /**
+   * The PRIORITY_UPDATE frame, which is defined by :rfc:`9218`.
+   */
+  NGHTTP2_PRIORITY_UPDATE = 0x10
 } nghttp2_frame_type;
 
 /**
@@ -691,7 +707,11 @@
    * SETTINGS_ENABLE_CONNECT_PROTOCOL
    * (`RFC 8441 <https://tools.ietf.org/html/rfc8441>`_)
    */
-  NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL = 0x08
+  NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL = 0x08,
+  /**
+   * SETTINGS_NO_RFC7540_PRIORITIES (:rfc:`9218`)
+   */
+  NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES = 0x09
 } nghttp2_settings_id;
 /* Note: If we add SETTINGS, update the capacity of
    NGHTTP2_INBOUND_NUM_IV as well */
@@ -705,8 +725,8 @@
  *
  * Default maximum number of incoming concurrent streams.  Use
  * `nghttp2_submit_settings()` with
- * :enum:`NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS` to change the
- * maximum number of incoming concurrent streams.
+ * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS`
+ * to change the maximum number of incoming concurrent streams.
  *
  * .. note::
  *
@@ -860,38 +880,41 @@
  * The implementation of this function must read at most |length|
  * bytes of data from |source| (or possibly other places) and store
  * them in |buf| and return number of data stored in |buf|.  If EOF is
- * reached, set :enum:`NGHTTP2_DATA_FLAG_EOF` flag in |*data_flags|.
+ * reached, set :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_EOF` flag
+ * in |*data_flags|.
  *
  * Sometime it is desirable to avoid copying data into |buf| and let
  * application to send data directly.  To achieve this, set
- * :enum:`NGHTTP2_DATA_FLAG_NO_COPY` to |*data_flags| (and possibly
- * other flags, just like when we do copy), and return the number of
- * bytes to send without copying data into |buf|.  The library, seeing
- * :enum:`NGHTTP2_DATA_FLAG_NO_COPY`, will invoke
+ * :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_NO_COPY` to
+ * |*data_flags| (and possibly other flags, just like when we do
+ * copy), and return the number of bytes to send without copying data
+ * into |buf|.  The library, seeing
+ * :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_NO_COPY`, will invoke
  * :type:`nghttp2_send_data_callback`.  The application must send
  * complete DATA frame in that callback.
  *
  * If this callback is set by `nghttp2_submit_request()`,
  * `nghttp2_submit_response()` or `nghttp2_submit_headers()` and
  * `nghttp2_submit_data()` with flag parameter
- * :enum:`NGHTTP2_FLAG_END_STREAM` set, and
- * :enum:`NGHTTP2_DATA_FLAG_EOF` flag is set to |*data_flags|, DATA
- * frame will have END_STREAM flag set.  Usually, this is expected
- * behaviour and all are fine.  One exception is send trailer fields.
- * You cannot send trailer fields after sending frame with END_STREAM
- * set.  To avoid this problem, one can set
- * :enum:`NGHTTP2_DATA_FLAG_NO_END_STREAM` along with
- * :enum:`NGHTTP2_DATA_FLAG_EOF` to signal the library not to set
- * END_STREAM in DATA frame.  Then application can use
- * `nghttp2_submit_trailer()` to send trailer fields.
+ * :enum:`nghttp2_flag.NGHTTP2_FLAG_END_STREAM` set, and
+ * :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_EOF` flag is set to
+ * |*data_flags|, DATA frame will have END_STREAM flag set.  Usually,
+ * this is expected behaviour and all are fine.  One exception is send
+ * trailer fields.  You cannot send trailer fields after sending frame
+ * with END_STREAM set.  To avoid this problem, one can set
+ * :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_NO_END_STREAM` along
+ * with :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_EOF` to signal the
+ * library not to set END_STREAM in DATA frame.  Then application can
+ * use `nghttp2_submit_trailer()` to send trailer fields.
  * `nghttp2_submit_trailer()` can be called inside this callback.
  *
  * If the application wants to postpone DATA frames (e.g.,
  * asynchronous I/O, or reading data blocks for long time), it is
- * achieved by returning :enum:`NGHTTP2_ERR_DEFERRED` without reading
- * any data in this invocation.  The library removes DATA frame from
- * the outgoing queue temporarily.  To move back deferred DATA frame
- * to outgoing queue, call `nghttp2_session_resume_data()`.
+ * achieved by returning :enum:`nghttp2_error.NGHTTP2_ERR_DEFERRED`
+ * without reading any data in this invocation.  The library removes
+ * DATA frame from the outgoing queue temporarily.  To move back
+ * deferred DATA frame to outgoing queue, call
+ * `nghttp2_session_resume_data()`.
  *
  * By default, |length| is limited to 16KiB at maximum.  If peer
  * allows larger frames, application can enlarge transmission buffer
@@ -900,16 +923,17 @@
  *
  * If the application just wants to return from
  * `nghttp2_session_send()` or `nghttp2_session_mem_send()` without
- * sending anything, return :enum:`NGHTTP2_ERR_PAUSE`.
+ * sending anything, return :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE`.
  *
  * In case of error, there are 2 choices. Returning
- * :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will close the stream
- * by issuing RST_STREAM with :enum:`NGHTTP2_INTERNAL_ERROR`.  If a
- * different error code is desirable, use
- * `nghttp2_submit_rst_stream()` with a desired error code and then
- * return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`.  Returning
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` will signal the entire session
- * failure.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will
+ * close the stream by issuing RST_STREAM with
+ * :enum:`nghttp2_error_code.NGHTTP2_INTERNAL_ERROR`.  If a different
+ * error code is desirable, use `nghttp2_submit_rst_stream()` with a
+ * desired error code and then return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`.
+ * Returning :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` will
+ * signal the entire session failure.
  */
 typedef ssize_t (*nghttp2_data_source_read_callback)(
     nghttp2_session *session, int32_t stream_id, uint8_t *buf, size_t length,
@@ -1289,8 +1313,9 @@
  * |length| bytes of data stored in |data|.  The |flags| is currently
  * not used and always 0. It must return the number of bytes sent if
  * it succeeds.  If it cannot send any single byte without blocking,
- * it must return :enum:`NGHTTP2_ERR_WOULDBLOCK`.  For other errors,
- * it must return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  The
+ * it must return :enum:`nghttp2_error.NGHTTP2_ERR_WOULDBLOCK`.  For
+ * other errors, it must return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.  The
  * |user_data| pointer is the third argument passed in to the call to
  * `nghttp2_session_client_new()` or `nghttp2_session_server_new()`.
  *
@@ -1318,9 +1343,10 @@
 /**
  * @functypedef
  *
- * Callback function invoked when :enum:`NGHTTP2_DATA_FLAG_NO_COPY` is
- * used in :type:`nghttp2_data_source_read_callback` to send complete
- * DATA frame.
+ * Callback function invoked when
+ * :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_NO_COPY` is used in
+ * :type:`nghttp2_data_source_read_callback` to send complete DATA
+ * frame.
  *
  * The |frame| is a DATA frame to send.  The |framehd| is the
  * serialized frame header (9 bytes). The |length| is the length of
@@ -1338,21 +1364,22 @@
  * If all data were written successfully, return 0.
  *
  * If it cannot send any data at all, just return
- * :enum:`NGHTTP2_ERR_WOULDBLOCK`; the library will call this callback
- * with the same parameters later (It is recommended to send complete
- * DATA frame at once in this function to deal with error; if partial
- * frame data has already sent, it is impossible to send another data
- * in that state, and all we can do is tear down connection).  When
- * data is fully processed, but application wants to make
- * `nghttp2_session_mem_send()` or `nghttp2_session_send()` return
- * immediately without processing next frames, return
- * :enum:`NGHTTP2_ERR_PAUSE`.  If application decided to reset this
- * stream, return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`, then
+ * :enum:`nghttp2_error.NGHTTP2_ERR_WOULDBLOCK`; the library will call
+ * this callback with the same parameters later (It is recommended to
+ * send complete DATA frame at once in this function to deal with
+ * error; if partial frame data has already sent, it is impossible to
+ * send another data in that state, and all we can do is tear down
+ * connection).  When data is fully processed, but application wants
+ * to make `nghttp2_session_mem_send()` or `nghttp2_session_send()`
+ * return immediately without processing next frames, return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE`.  If application decided to
+ * reset this stream, return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`, then
  * the library will send RST_STREAM with INTERNAL_ERROR as error code.
  * The application can also return
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`, which will result in
- * connection closure.  Returning any other value is treated as
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`, which will
+ * result in connection closure.  Returning any other value is treated
+ * as :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` is returned.
  */
 typedef int (*nghttp2_send_data_callback)(nghttp2_session *session,
                                           nghttp2_frame *frame,
@@ -1369,11 +1396,13 @@
  * currently not used and always 0.  It must return the number of
  * bytes written in |buf| if it succeeds.  If it cannot read any
  * single byte without blocking, it must return
- * :enum:`NGHTTP2_ERR_WOULDBLOCK`.  If it gets EOF before it reads any
- * single byte, it must return :enum:`NGHTTP2_ERR_EOF`.  For other
- * errors, it must return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
- * Returning 0 is treated as :enum:`NGHTTP2_ERR_WOULDBLOCK`.  The
- * |user_data| pointer is the third argument passed in to the call to
+ * :enum:`nghttp2_error.NGHTTP2_ERR_WOULDBLOCK`.  If it gets EOF
+ * before it reads any single byte, it must return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_EOF`.  For other errors, it must
+ * return :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * Returning 0 is treated as
+ * :enum:`nghttp2_error.NGHTTP2_ERR_WOULDBLOCK`.  The |user_data|
+ * pointer is the third argument passed in to the call to
  * `nghttp2_session_client_new()` or `nghttp2_session_server_new()`.
  *
  * This callback is required if the application uses
@@ -1417,7 +1446,8 @@
  * The implementation of this function must return 0 if it succeeds.
  * If nonzero value is returned, it is treated as fatal error and
  * `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
- * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * immediately return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
  *
  * To set this callback to :type:`nghttp2_session_callbacks`, use
  * `nghttp2_session_callbacks_set_on_frame_recv_callback()`.
@@ -1445,7 +1475,8 @@
  * The implementation of this function must return 0 if it succeeds.
  * If nonzero is returned, it is treated as fatal error and
  * `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
- * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * immediately return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
  *
  * To set this callback to :type:`nghttp2_session_callbacks`, use
  * `nghttp2_session_callbacks_set_on_invalid_frame_recv_callback()`.
@@ -1468,9 +1499,9 @@
  * `nghttp2_session_server_new()`.
  *
  * If the application uses `nghttp2_session_mem_recv()`, it can return
- * :enum:`NGHTTP2_ERR_PAUSE` to make `nghttp2_session_mem_recv()`
- * return without processing further input bytes.  The memory by
- * pointed by the |data| is retained until
+ * :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE` to make
+ * `nghttp2_session_mem_recv()` return without processing further
+ * input bytes.  The memory by pointed by the |data| is retained until
  * `nghttp2_session_mem_recv()` or `nghttp2_session_recv()` is called.
  * The application must retain the input bytes which was used to
  * produce the |data| parameter, because it may refer to the memory
@@ -1479,7 +1510,8 @@
  * The implementation of this function must return 0 if it succeeds.
  * If nonzero is returned, it is treated as fatal error, and
  * `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
- * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * immediately return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
  *
  * To set this callback to :type:`nghttp2_session_callbacks`, use
  * `nghttp2_session_callbacks_set_on_data_chunk_recv_callback()`.
@@ -1499,19 +1531,20 @@
  * `nghttp2_session_server_new()`.
  *
  * The implementation of this function must return 0 if it succeeds.
- * It can also return :enum:`NGHTTP2_ERR_CANCEL` to cancel the
- * transmission of the given frame.
+ * It can also return :enum:`nghttp2_error.NGHTTP2_ERR_CANCEL` to
+ * cancel the transmission of the given frame.
  *
  * If there is a fatal error while executing this callback, the
- * implementation should return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`,
- * which makes `nghttp2_session_send()` and
- * `nghttp2_session_mem_send()` functions immediately return
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * implementation should return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`, which makes
+ * `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions
+ * immediately return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
  *
  * If the other value is returned, it is treated as if
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned.  But the
- * implementation should not rely on this since the library may define
- * new return value to extend its capability.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` is returned.
+ * But the implementation should not rely on this since the library
+ * may define new return value to extend its capability.
  *
  * To set this callback to :type:`nghttp2_session_callbacks`, use
  * `nghttp2_session_callbacks_set_before_frame_send_callback()`.
@@ -1530,7 +1563,8 @@
  * The implementation of this function must return 0 if it succeeds.
  * If nonzero is returned, it is treated as fatal error and
  * `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions
- * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * immediately return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
  *
  * To set this callback to :type:`nghttp2_session_callbacks`, use
  * `nghttp2_session_callbacks_set_on_frame_send_callback()`.
@@ -1552,7 +1586,8 @@
  * The implementation of this function must return 0 if it succeeds.
  * If nonzero is returned, it is treated as fatal error and
  * `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions
- * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * immediately return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
  *
  * `nghttp2_session_get_stream_user_data()` can be used to get
  * associated data.
@@ -1583,7 +1618,8 @@
  * If nonzero is returned, it is treated as fatal error and
  * `nghttp2_session_recv()`, `nghttp2_session_mem_recv()`,
  * `nghttp2_session_send()`, and `nghttp2_session_mem_send()`
- * functions immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * functions immediately return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
  *
  * To set this callback to :type:`nghttp2_session_callbacks`, use
  * `nghttp2_session_callbacks_set_on_stream_close_callback()`.
@@ -1601,10 +1637,11 @@
  * will be emitted by :type:`nghttp2_on_header_callback`.
  *
  * The ``frame->hd.flags`` may not have
- * :enum:`NGHTTP2_FLAG_END_HEADERS` flag set, which indicates that one
- * or more CONTINUATION frames are involved.  But the application does
- * not need to care about that because the header name/value pairs are
- * emitted transparently regardless of CONTINUATION frames.
+ * :enum:`nghttp2_flag.NGHTTP2_FLAG_END_HEADERS` flag set, which
+ * indicates that one or more CONTINUATION frames are involved.  But
+ * the application does not need to care about that because the header
+ * name/value pairs are emitted transparently regardless of
+ * CONTINUATION frames.
  *
  * The server applications probably create an object to store
  * information about new stream if ``frame->hd.type ==
@@ -1627,26 +1664,31 @@
  * trailer fields also has ``frame->headers.cat ==
  * NGHTTP2_HCAT_HEADERS`` which does not contain any status code.
  *
- * Returning :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will close
- * the stream (promised stream if frame is PUSH_PROMISE) by issuing
- * RST_STREAM with :enum:`NGHTTP2_INTERNAL_ERROR`.  In this case,
+ * Returning
+ * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will
+ * close the stream (promised stream if frame is PUSH_PROMISE) by
+ * issuing RST_STREAM with
+ * :enum:`nghttp2_error_code.NGHTTP2_INTERNAL_ERROR`.  In this case,
  * :type:`nghttp2_on_header_callback` and
  * :type:`nghttp2_on_frame_recv_callback` will not be invoked.  If a
  * different error code is desirable, use
  * `nghttp2_submit_rst_stream()` with a desired error code and then
- * return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`.  Again, use
- * ``frame->push_promise.promised_stream_id`` as stream_id parameter
- * in `nghttp2_submit_rst_stream()` if frame is PUSH_PROMISE.
+ * return :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`.
+ * Again, use ``frame->push_promise.promised_stream_id`` as stream_id
+ * parameter in `nghttp2_submit_rst_stream()` if frame is
+ * PUSH_PROMISE.
  *
  * The implementation of this function must return 0 if it succeeds.
- * It can return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` to
+ * It can return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` to
  * reset the stream (promised stream if frame is PUSH_PROMISE).  For
  * critical errors, it must return
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  If the other value is
- * returned, it is treated as if :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`
- * is returned.  If :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned,
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.  If the other
+ * value is returned, it is treated as if
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` is returned.  If
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` is returned,
  * `nghttp2_session_mem_recv()` function will immediately return
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
  *
  * To set this callback to :type:`nghttp2_session_callbacks`, use
  * `nghttp2_session_callbacks_set_on_begin_headers_callback()`.
@@ -1663,16 +1705,17 @@
  * The |value| of length |valuelen| is header value.  The |flags| is
  * bitwise OR of one or more of :type:`nghttp2_nv_flag`.
  *
- * If :enum:`NGHTTP2_NV_FLAG_NO_INDEX` is set in |flags|, the receiver
- * must not index this name/value pair when forwarding it to the next
- * hop.  More specifically, "Literal Header Field never Indexed"
- * representation must be used in HPACK encoding.
+ * If :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_INDEX` is set in
+ * |flags|, the receiver must not index this name/value pair when
+ * forwarding it to the next hop.  More specifically, "Literal Header
+ * Field never Indexed" representation must be used in HPACK encoding.
  *
  * When this callback is invoked, ``frame->hd.type`` is either
- * :enum:`NGHTTP2_HEADERS` or :enum:`NGHTTP2_PUSH_PROMISE`.  After all
- * header name/value pairs are processed with this callback, and no
- * error has been detected, :type:`nghttp2_on_frame_recv_callback`
- * will be invoked.  If there is an error in decompression,
+ * :enum:`nghttp2_frame_type.NGHTTP2_HEADERS` or
+ * :enum:`nghttp2_frame_type.NGHTTP2_PUSH_PROMISE`.  After all header
+ * name/value pairs are processed with this callback, and no error has
+ * been detected, :type:`nghttp2_on_frame_recv_callback` will be
+ * invoked.  If there is an error in decompression,
  * :type:`nghttp2_on_frame_recv_callback` for the |frame| will not be
  * invoked.
  *
@@ -1690,34 +1733,39 @@
  * explained in :ref:`http-messaging` section.
  *
  * If the application uses `nghttp2_session_mem_recv()`, it can return
- * :enum:`NGHTTP2_ERR_PAUSE` to make `nghttp2_session_mem_recv()`
- * return without processing further input bytes.  The memory pointed
- * by |frame|, |name| and |value| parameters are retained until
- * `nghttp2_session_mem_recv()` or `nghttp2_session_recv()` is called.
- * The application must retain the input bytes which was used to
- * produce these parameters, because it may refer to the memory region
- * included in the input bytes.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE` to make
+ * `nghttp2_session_mem_recv()` return without processing further
+ * input bytes.  The memory pointed by |frame|, |name| and |value|
+ * parameters are retained until `nghttp2_session_mem_recv()` or
+ * `nghttp2_session_recv()` is called.  The application must retain
+ * the input bytes which was used to produce these parameters, because
+ * it may refer to the memory region included in the input bytes.
  *
- * Returning :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will close
- * the stream (promised stream if frame is PUSH_PROMISE) by issuing
- * RST_STREAM with :enum:`NGHTTP2_INTERNAL_ERROR`.  In this case,
+ * Returning
+ * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will
+ * close the stream (promised stream if frame is PUSH_PROMISE) by
+ * issuing RST_STREAM with
+ * :enum:`nghttp2_error_code.NGHTTP2_INTERNAL_ERROR`.  In this case,
  * :type:`nghttp2_on_header_callback` and
  * :type:`nghttp2_on_frame_recv_callback` will not be invoked.  If a
  * different error code is desirable, use
  * `nghttp2_submit_rst_stream()` with a desired error code and then
- * return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`.  Again, use
- * ``frame->push_promise.promised_stream_id`` as stream_id parameter
- * in `nghttp2_submit_rst_stream()` if frame is PUSH_PROMISE.
+ * return :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`.
+ * Again, use ``frame->push_promise.promised_stream_id`` as stream_id
+ * parameter in `nghttp2_submit_rst_stream()` if frame is
+ * PUSH_PROMISE.
  *
  * The implementation of this function must return 0 if it succeeds.
- * It may return :enum:`NGHTTP2_ERR_PAUSE` or
- * :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`.  For other critical
- * failures, it must return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  If
- * the other nonzero value is returned, it is treated as
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  If
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned,
+ * It may return :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE` or
+ * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`.  For
+ * other critical failures, it must return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.  If the other
+ * nonzero value is returned, it is treated as
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.  If
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` is returned,
  * `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
- * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * immediately return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
  *
  * To set this callback to :type:`nghttp2_session_callbacks`, use
  * `nghttp2_session_callbacks_set_on_header_callback()`.
@@ -1784,11 +1832,12 @@
  *
  * With this callback, application inspects the incoming invalid
  * field, and it also can reset stream from this callback by returning
- * :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`.  By default, the
- * error code is :enum:`NGHTTP2_PROTOCOL_ERROR`.  To change the error
- * code, call `nghttp2_submit_rst_stream()` with the error code of
- * choice in addition to returning
- * :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`.  By
+ * default, the error code is
+ * :enum:`nghttp2_error_code.NGHTTP2_PROTOCOL_ERROR`.  To change the
+ * error code, call `nghttp2_submit_rst_stream()` with the error code
+ * of choice in addition to returning
+ * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`.
  *
  * If 0 is returned, the header field is ignored, and the stream is
  * not reset.
@@ -1819,11 +1868,12 @@
  *
  * With this callback, application inspects the incoming invalid
  * field, and it also can reset stream from this callback by returning
- * :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`.  By default, the
- * error code is :enum:`NGHTTP2_INTERNAL_ERROR`.  To change the error
- * code, call `nghttp2_submit_rst_stream()` with the error code of
- * choice in addition to returning
- * :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`.  By
+ * default, the error code is
+ * :enum:`nghttp2_error_code.NGHTTP2_INTERNAL_ERROR`.  To change the
+ * error code, call `nghttp2_submit_rst_stream()` with the error code
+ * of choice in addition to returning
+ * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`.
  */
 typedef int (*nghttp2_on_invalid_header_callback2)(
     nghttp2_session *session, const nghttp2_frame *frame, nghttp2_rcbuf *name,
@@ -1837,11 +1887,12 @@
  * |frame|.  The application must choose the total length of payload
  * including padded bytes in range [frame->hd.length, max_payloadlen],
  * inclusive.  Choosing number not in this range will be treated as
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  Returning
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.  Returning
  * ``frame->hd.length`` means no padding is added.  Returning
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` will make
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` will make
  * `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions
- * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * immediately return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
  *
  * To set this callback to :type:`nghttp2_session_callbacks`, use
  * `nghttp2_session_callbacks_set_select_padding_callback()`.
@@ -1861,16 +1912,17 @@
  * |remote_max_frame_size|)].  If a value greater than this range is
  * returned than the max allow value will be used.  Returning a value
  * smaller than this range is treated as
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  The |frame_type| is provided
- * for future extensibility and identifies the type of frame (see
- * :type:`nghttp2_frame_type`) for which to get the length for.
- * Currently supported frame types are: :enum:`NGHTTP2_DATA`.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.  The
+ * |frame_type| is provided for future extensibility and identifies
+ * the type of frame (see :type:`nghttp2_frame_type`) for which to get
+ * the length for.  Currently supported frame types are:
+ * :enum:`nghttp2_frame_type.NGHTTP2_DATA`.
  *
  * This callback can be used to control the length in bytes for which
  * :type:`nghttp2_data_source_read_callback` is allowed to send to the
  * remote endpoint.  This callback is optional.  Returning
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` will signal the entire session
- * failure.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` will signal the
+ * entire session failure.
  *
  * To set this callback to :type:`nghttp2_session_callbacks`, use
  * `nghttp2_session_callbacks_set_data_source_read_length_callback()`.
@@ -1897,7 +1949,8 @@
  * The implementation of this function must return 0 if it succeeds.
  * If nonzero value is returned, it is treated as fatal error and
  * `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
- * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * immediately return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
  *
  * To set this callback to :type:`nghttp2_session_callbacks`, use
  * `nghttp2_session_callbacks_set_on_begin_frame_callback()`.
@@ -1916,14 +1969,15 @@
  * The implementation of this function must return 0 if it succeeds.
  *
  * To abort processing this extension frame, return
- * :enum:`NGHTTP2_ERR_CANCEL`.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CANCEL`.
  *
  * If fatal error occurred, application should return
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  In this case,
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.  In this case,
  * `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
- * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  If the
- * other values are returned, currently they are treated as
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * immediately return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.  If the other
+ * values are returned, currently they are treated as
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
  */
 typedef int (*nghttp2_on_extension_chunk_recv_callback)(
     nghttp2_session *session, const nghttp2_frame_hd *hd, const uint8_t *data,
@@ -1953,14 +2007,15 @@
  * |*payload|, and do its own mechanism to process extension frames.
  *
  * To abort processing this extension frame, return
- * :enum:`NGHTTP2_ERR_CANCEL`.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CANCEL`.
  *
  * If fatal error occurred, application should return
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  In this case,
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.  In this case,
  * `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
- * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  If the
- * other values are returned, currently they are treated as
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * immediately return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.  If the other
+ * values are returned, currently they are treated as
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
  */
 typedef int (*nghttp2_unpack_extension_callback)(nghttp2_session *session,
                                                  void **payload,
@@ -1982,17 +2037,18 @@
  * bytes written into |buf| when it succeeds.
  *
  * To abort processing this extension frame, return
- * :enum:`NGHTTP2_ERR_CANCEL`, and
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CANCEL`, and
  * :type:`nghttp2_on_frame_not_send_callback` will be invoked.
  *
  * If fatal error occurred, application should return
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  In this case,
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.  In this case,
  * `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions
- * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  If the
- * other values are returned, currently they are treated as
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  If the return value is
- * strictly larger than |len|, it is treated as
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * immediately return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.  If the other
+ * values are returned, currently they are treated as
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.  If the return
+ * value is strictly larger than |len|, it is treated as
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
  */
 typedef ssize_t (*nghttp2_pack_extension_callback)(nghttp2_session *session,
                                                    uint8_t *buf, size_t len,
@@ -2017,12 +2073,12 @@
  *
  * Normally, application should return 0 from this callback.  If fatal
  * error occurred while doing something in this callback, application
- * should return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  In this case,
- * library will return immediately with return value
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  Currently, if nonzero value
- * is returned from this callback, they are treated as
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`, but application should not
- * rely on this details.
+ * should return :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * In this case, library will return immediately with return value
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.  Currently, if
+ * nonzero value is returned from this callback, they are treated as
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`, but application
+ * should not rely on this details.
  */
 typedef int (*nghttp2_error_callback)(nghttp2_session *session, const char *msg,
                                       size_t len, void *user_data);
@@ -2043,12 +2099,12 @@
  *
  * Normally, application should return 0 from this callback.  If fatal
  * error occurred while doing something in this callback, application
- * should return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  In this case,
- * library will return immediately with return value
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  Currently, if nonzero value
- * is returned from this callback, they are treated as
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`, but application should not
- * rely on this details.
+ * should return :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * In this case, library will return immediately with return value
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.  Currently, if
+ * nonzero value is returned from this callback, they are treated as
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`, but application
+ * should not rely on this details.
  */
 typedef int (*nghttp2_error_callback2)(nghttp2_session *session,
                                        int lib_error_code, const char *msg,
@@ -2078,7 +2134,7 @@
  * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
  */
 NGHTTP2_EXTERN int
@@ -2275,7 +2331,7 @@
  * @function
  *
  * Sets callback function invoked when
- * :enum:`NGHTTP2_DATA_FLAG_NO_COPY` is used in
+ * :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_NO_COPY` is used in
  * :type:`nghttp2_data_source_read_callback` to avoid data copy.
  */
 NGHTTP2_EXTERN void nghttp2_session_callbacks_set_send_data_callback(
@@ -2458,7 +2514,7 @@
  * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
  */
 NGHTTP2_EXTERN int nghttp2_option_new(nghttp2_option **option_ptr);
@@ -2519,7 +2575,8 @@
  * If this option is not used or used with zero value, if MAGIC does
  * not match :macro:`NGHTTP2_CLIENT_MAGIC`, `nghttp2_session_recv()`
  * and `nghttp2_session_mem_recv()` will return error
- * :enum:`NGHTTP2_ERR_BAD_CLIENT_MAGIC`, which is fatal error.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_BAD_CLIENT_MAGIC`, which is fatal
+ * error.
  */
 NGHTTP2_EXTERN void
 nghttp2_option_set_no_recv_client_magic(nghttp2_option *option, int val);
@@ -2604,8 +2661,8 @@
  * received.  If this option is set to nonzero, the library won't send
  * PING frame with ACK flag set in the response for incoming PING
  * frame.  The application can send PING frame with ACK flag set using
- * `nghttp2_submit_ping()` with :enum:`NGHTTP2_FLAG_ACK` as flags
- * parameter.
+ * `nghttp2_submit_ping()` with :enum:`nghttp2_flag.NGHTTP2_FLAG_ACK`
+ * as flags parameter.
  */
 NGHTTP2_EXTERN void nghttp2_option_set_no_auto_ping_ack(nghttp2_option *option,
                                                         int val);
@@ -2619,7 +2676,7 @@
  * `nghttp2_hd_deflate_bound()`.  The default value is 64KiB.  If
  * application attempts to send header fields larger than this limit,
  * the transmission of the frame fails with error code
- * :enum:`NGHTTP2_ERR_FRAME_SIZE_ERROR`.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_FRAME_SIZE_ERROR`.
  */
 NGHTTP2_EXTERN void
 nghttp2_option_set_max_send_header_block_length(nghttp2_option *option,
@@ -2644,6 +2701,11 @@
  * This option prevents the library from retaining closed streams to
  * maintain the priority tree.  If this option is set to nonzero,
  * applications can discard closed stream completely to save memory.
+ *
+ * If
+ * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
+ * of value of 1 is submitted via `nghttp2_submit_settings()`, any
+ * closed streams are not retained regardless of this option.
  */
 NGHTTP2_EXTERN void nghttp2_option_set_no_closed_streams(nghttp2_option *option,
                                                          int val);
@@ -2662,6 +2724,47 @@
 /**
  * @function
  *
+ * This function sets the maximum number of SETTINGS entries per
+ * SETTINGS frame that will be accepted. If more than those entries
+ * are received, the peer is considered to be misbehaving and session
+ * will be closed. The default value is 32.
+ */
+NGHTTP2_EXTERN void nghttp2_option_set_max_settings(nghttp2_option *option,
+                                                    size_t val);
+
+/**
+ * @function
+ *
+ * This option, if set to nonzero, allows server to fallback to
+ * :rfc:`7540` priorities if SETTINGS_NO_RFC7540_PRIORITIES was not
+ * received from client, and server submitted
+ * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
+ * = 1 via `nghttp2_submit_settings()`.  Most of the advanced
+ * functionality for RFC 7540 priorities are still disabled.  This
+ * fallback only enables the minimal feature set of RFC 7540
+ * priorities to deal with priority signaling from client.
+ *
+ * Client session ignores this option.
+ */
+NGHTTP2_EXTERN void
+nghttp2_option_set_server_fallback_rfc7540_priorities(nghttp2_option *option,
+                                                      int val);
+
+/**
+ * @function
+ *
+ * This option, if set to nonzero, turns off RFC 9113 leading and
+ * trailing white spaces validation against HTTP field value.  Some
+ * important fields, such as HTTP/2 pseudo header fields, are
+ * validated more strictly and this option does not apply to them.
+ */
+NGHTTP2_EXTERN void
+nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation(
+    nghttp2_option *option, int val);
+
+/**
+ * @function
+ *
  * Initializes |*session_ptr| for client use.  The all members of
  * |callbacks| are copied to |*session_ptr|.  Therefore |*session_ptr|
  * does not store |callbacks|.  The |user_data| is an arbitrary user
@@ -2677,7 +2780,7 @@
  * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
  */
 NGHTTP2_EXTERN int
@@ -2703,7 +2806,7 @@
  * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
  */
 NGHTTP2_EXTERN int
@@ -2729,7 +2832,7 @@
  * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
  */
 NGHTTP2_EXTERN int
@@ -2755,7 +2858,7 @@
  * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
  */
 NGHTTP2_EXTERN int
@@ -2781,7 +2884,7 @@
  * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
  */
 NGHTTP2_EXTERN int nghttp2_session_client_new3(
@@ -2806,7 +2909,7 @@
  * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
  */
 NGHTTP2_EXTERN int nghttp2_session_server_new3(
@@ -2828,12 +2931,14 @@
  *
  * This function retrieves the highest prioritized frame from the
  * outbound queue and sends it to the remote peer.  It does this as
- * many as possible until the user callback
+ * many times as possible until the user callback
  * :type:`nghttp2_send_callback` returns
- * :enum:`NGHTTP2_ERR_WOULDBLOCK` or the outbound queue becomes empty.
- * This function calls several callback functions which are passed
- * when initializing the |session|.  Here is the simple time chart
- * which tells when each callback is invoked:
+ * :enum:`nghttp2_error.NGHTTP2_ERR_WOULDBLOCK`, the outbound queue
+ * becomes empty or flow control is triggered (remote window size
+ * becomes depleted or maximum number of concurrent streams is
+ * reached).  This function calls several callback functions which are
+ * passed when initializing the |session|.  Here is the simple time
+ * chart which tells when each callback is invoked:
  *
  * 1. Get the next frame to send from outbound queue.
  *
@@ -2851,7 +2956,7 @@
  *
  * 6. :type:`nghttp2_before_frame_send_callback` is invoked.
  *
- * 7. If :enum:`NGHTTP2_ERR_CANCEL` is returned from
+ * 7. If :enum:`nghttp2_error.NGHTTP2_ERR_CANCEL` is returned from
  *    :type:`nghttp2_before_frame_send_callback`, the current frame
  *    transmission is canceled, and
  *    :type:`nghttp2_on_frame_not_send_callback` is invoked.  Abort
@@ -2869,9 +2974,9 @@
  * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`
  *     The callback function failed.
  */
 NGHTTP2_EXTERN int nghttp2_session_send(nghttp2_session *session);
@@ -2903,7 +3008,7 @@
  * |*data_ptr| if it succeeds, or one of the following negative error
  * codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
  *
  * .. note::
@@ -2925,8 +3030,8 @@
  *
  * This function receives as many frames as possible until the user
  * callback :type:`nghttp2_recv_callback` returns
- * :enum:`NGHTTP2_ERR_WOULDBLOCK`.  This function calls several
- * callback functions which are passed when initializing the
+ * :enum:`nghttp2_error.NGHTTP2_ERR_WOULDBLOCK`.  This function calls
+ * several callback functions which are passed when initializing the
  * |session|.  Here is the simple time chart which tells when each
  * callback is invoked:
  *
@@ -2971,18 +3076,18 @@
  * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
  *
- * :enum:`NGHTTP2_ERR_EOF`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_EOF`
  *     The remote peer did shutdown on the connection.
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`
  *     The callback function failed.
- * :enum:`NGHTTP2_ERR_BAD_CLIENT_MAGIC`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_BAD_CLIENT_MAGIC`
  *     Invalid client magic was detected.  This error only returns
  *     when |session| was configured as server and
  *     `nghttp2_option_set_no_recv_client_magic()` is not used with
  *     nonzero value.
- * :enum:`NGHTTP2_ERR_FLOODED`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_FLOODED`
  *     Flooding was detected in this HTTP/2 session, and it must be
  *     closed.  This is most likely caused by misbehaviour of peer.
  */
@@ -2992,7 +3097,7 @@
  * @function
  *
  * Processes data |in| as an input from the remote endpoint.  The
- * |inlen| indicates the number of bytes in the |in|.
+ * |inlen| indicates the number of bytes to receive in the |in|.
  *
  * This function behaves like `nghttp2_session_recv()` except that it
  * does not use :type:`nghttp2_recv_callback` to receive data; the
@@ -3001,27 +3106,27 @@
  * are called in the same way as they are in `nghttp2_session_recv()`.
  *
  * In the current implementation, this function always tries to
- * processes all input data unless either an error occurs or
- * :enum:`NGHTTP2_ERR_PAUSE` is returned from
+ * processes |inlen| bytes of input data unless either an error occurs or
+ * :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE` is returned from
  * :type:`nghttp2_on_header_callback` or
  * :type:`nghttp2_on_data_chunk_recv_callback`.  If
- * :enum:`NGHTTP2_ERR_PAUSE` is used, the return value includes the
- * number of bytes which was used to produce the data or frame for the
- * callback.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE` is used, the return value
+ * includes the number of bytes which was used to produce the data or
+ * frame for the callback.
  *
  * This function returns the number of processed bytes, or one of the
  * following negative error codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`
  *     The callback function failed.
- * :enum:`NGHTTP2_ERR_BAD_CLIENT_MAGIC`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_BAD_CLIENT_MAGIC`
  *     Invalid client magic was detected.  This error only returns
  *     when |session| was configured as server and
  *     `nghttp2_option_set_no_recv_client_magic()` is not used with
  *     nonzero value.
- * :enum:`NGHTTP2_ERR_FLOODED`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_FLOODED`
  *     Flooding was detected in this HTTP/2 session, and it must be
  *     closed.  This is most likely caused by misbehaviour of peer.
  */
@@ -3038,9 +3143,9 @@
  * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
  *
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
  *     The stream does not exist; or no deferred data exist.
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
  */
 NGHTTP2_EXTERN int nghttp2_session_resume_data(nghttp2_session *session,
@@ -3101,7 +3206,7 @@
  * This function returns 0 if it succeeds, or one of following
  * negative error codes:
  *
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
  *     The stream does not exist
  */
 NGHTTP2_EXTERN int
@@ -3318,7 +3423,7 @@
  * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
  */
 NGHTTP2_EXTERN int nghttp2_session_terminate_session(nghttp2_session *session,
@@ -3345,9 +3450,9 @@
  * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
  *     The |last_stream_id| is invalid.
  */
 NGHTTP2_EXTERN int nghttp2_session_terminate_session2(nghttp2_session *session,
@@ -3362,7 +3467,7 @@
  *
  * This function is only usable for server.  If this function is
  * called with client side session, this function returns
- * :enum:`NGHTTP2_ERR_INVALID_STATE`.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`.
  *
  * To gracefully shutdown HTTP/2 session, server should call this
  * function to send GOAWAY with last_stream_id (1u << 31) - 1.  And
@@ -3384,9 +3489,9 @@
  * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_STATE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`
  *     The |session| is initialized as client.
  */
 NGHTTP2_EXTERN int nghttp2_submit_shutdown_notice(nghttp2_session *session);
@@ -3421,7 +3526,7 @@
  * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
  *
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
  *     The |next_stream_id| is strictly less than the value
  *     `nghttp2_session_get_next_stream_id()` returns; or
  *     |next_stream_id| is invalid (e.g., even integer for client, or
@@ -3456,11 +3561,11 @@
  * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
  *     The |stream_id| is 0.
- * :enum:`NGHTTP2_ERR_INVALID_STATE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`
  *     Automatic WINDOW_UPDATE is not disabled.
  */
 NGHTTP2_EXTERN int nghttp2_session_consume(nghttp2_session *session,
@@ -3477,9 +3582,9 @@
  * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_STATE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`
  *     Automatic WINDOW_UPDATE is not disabled.
  */
 NGHTTP2_EXTERN int nghttp2_session_consume_connection(nghttp2_session *session,
@@ -3496,11 +3601,11 @@
  * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
  *     The |stream_id| is 0.
- * :enum:`NGHTTP2_ERR_INVALID_STATE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`
  *     Automatic WINDOW_UPDATE is not disabled.
  */
 NGHTTP2_EXTERN int nghttp2_session_consume_stream(nghttp2_session *session,
@@ -3527,12 +3632,17 @@
  * found, we use default priority instead of given |pri_spec|.  That
  * is make stream depend on root stream with weight 16.
  *
+ * If
+ * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
+ * of value of 1 is submitted via `nghttp2_submit_settings()`, this
+ * function does nothing and returns 0.
+ *
  * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
  *     Attempted to depend on itself; or no stream exist for the given
  *     |stream_id|; or |stream_id| is 0
  */
@@ -3570,12 +3680,17 @@
  * found, we use default priority instead of given |pri_spec|.  That
  * is make stream depend on root stream with weight 16.
  *
+ * If
+ * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
+ * of value of 1 is submitted via `nghttp2_submit_settings()`, this
+ * function does nothing and returns 0.
+ *
  * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
  *     Attempted to depend on itself; or stream denoted by |stream_id|
  *     already exists; or |stream_id| cannot be used to create idle
  *     stream (in other words, local endpoint has already opened
@@ -3626,11 +3741,11 @@
  * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
  *     The |settings_payload| is badly formed.
- * :enum:`NGHTTP2_ERR_PROTO`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_PROTO`
  *     The stream ID 1 is already used or closed; or is not available.
  */
 NGHTTP2_EXTERN int nghttp2_session_upgrade(nghttp2_session *session,
@@ -3670,11 +3785,11 @@
  * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
  *     The |settings_payload| is badly formed.
- * :enum:`NGHTTP2_ERR_PROTO`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_PROTO`
  *     The stream ID 1 is already used or closed; or is not available.
  */
 NGHTTP2_EXTERN int nghttp2_session_upgrade2(nghttp2_session *session,
@@ -3698,10 +3813,10 @@
  * This function returns the number of bytes written in |buf|, or one
  * of the following negative error codes:
  *
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
  *     The |iv| contains duplicate settings ID or invalid value.
  *
- * :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INSUFF_BUFSIZE`
  *     The provided |buflen| size is too small to hold the output.
  */
 NGHTTP2_EXTERN ssize_t nghttp2_pack_settings_payload(
@@ -3732,8 +3847,8 @@
  * on with |weight| and its exclusive flag.  If |exclusive| is
  * nonzero, exclusive flag is set.
  *
- * The |weight| must be in [:enum:`NGHTTP2_MIN_WEIGHT`,
- * :enum:`NGHTTP2_MAX_WEIGHT`], inclusive.
+ * The |weight| must be in [:macro:`NGHTTP2_MIN_WEIGHT`,
+ * :macro:`NGHTTP2_MAX_WEIGHT`], inclusive.
  */
 NGHTTP2_EXTERN void nghttp2_priority_spec_init(nghttp2_priority_spec *pri_spec,
                                                int32_t stream_id,
@@ -3768,11 +3883,17 @@
  * use `nghttp2_priority_spec_init()`.  If |pri_spec| is not ``NULL``,
  * this function will copy its data members.
  *
- * The ``pri_spec->weight`` must be in [:enum:`NGHTTP2_MIN_WEIGHT`,
- * :enum:`NGHTTP2_MAX_WEIGHT`], inclusive.  If ``pri_spec->weight`` is
- * strictly less than :enum:`NGHTTP2_MIN_WEIGHT`, it becomes
- * :enum:`NGHTTP2_MIN_WEIGHT`.  If it is strictly greater than
- * :enum:`NGHTTP2_MAX_WEIGHT`, it becomes :enum:`NGHTTP2_MAX_WEIGHT`.
+ * The ``pri_spec->weight`` must be in [:macro:`NGHTTP2_MIN_WEIGHT`,
+ * :macro:`NGHTTP2_MAX_WEIGHT`], inclusive.  If ``pri_spec->weight``
+ * is strictly less than :macro:`NGHTTP2_MIN_WEIGHT`, it becomes
+ * :macro:`NGHTTP2_MIN_WEIGHT`.  If it is strictly greater than
+ * :macro:`NGHTTP2_MAX_WEIGHT`, it becomes
+ * :macro:`NGHTTP2_MAX_WEIGHT`.
+ *
+ * If
+ * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
+ * of value of 1 is received by a remote endpoint, |pri_spec| is
+ * ignored, and treated as if ``NULL`` is specified.
  *
  * The |nva| is an array of name/value pair :type:`nghttp2_nv` with
  * |nvlen| elements.  The application is responsible to include
@@ -3783,12 +3904,12 @@
  * This function creates copies of all name/value pairs in |nva|.  It
  * also lower-cases all names in |nva|.  The order of elements in
  * |nva| is preserved.  For header fields with
- * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and
- * :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name
- * and value are not copied respectively.  With
- * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to
- * pass header field name in lowercase.  The application should
- * maintain the references to them until
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME` and
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set,
+ * header field name and value are not copied respectively.  With
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME`, application
+ * is responsible to pass header field name in lowercase.  The
+ * application should maintain the references to them until
  * :type:`nghttp2_on_frame_send_callback` or
  * :type:`nghttp2_on_frame_not_send_callback` is called.
  *
@@ -3810,15 +3931,15 @@
  * This function returns assigned stream ID if it succeeds, or one of
  * the following negative error codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
- * :enum:`NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE`
  *     No stream ID is available because maximum stream ID was
  *     reached.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
  *     Trying to depend on itself (new stream ID equals
  *     ``pri_spec->stream_id``).
- * :enum:`NGHTTP2_ERR_PROTO`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_PROTO`
  *     The |session| is server session.
  *
  * .. warning::
@@ -3853,12 +3974,12 @@
  * This function creates copies of all name/value pairs in |nva|.  It
  * also lower-cases all names in |nva|.  The order of elements in
  * |nva| is preserved.  For header fields with
- * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and
- * :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name
- * and value are not copied respectively.  With
- * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to
- * pass header field name in lowercase.  The application should
- * maintain the references to them until
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME` and
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set,
+ * header field name and value are not copied respectively.  With
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME`, application
+ * is responsible to pass header field name in lowercase.  The
+ * application should maintain the references to them until
  * :type:`nghttp2_on_frame_send_callback` or
  * :type:`nghttp2_on_frame_not_send_callback` is called.
  *
@@ -3884,16 +4005,16 @@
  * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
  *     The |stream_id| is 0.
- * :enum:`NGHTTP2_ERR_DATA_EXIST`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_DATA_EXIST`
  *     DATA or HEADERS has been already submitted and not fully
  *     processed yet.  Normally, this does not happen, but when
  *     application wrongly calls `nghttp2_submit_response()` twice,
  *     this may happen.
- * :enum:`NGHTTP2_ERR_PROTO`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_PROTO`
  *     The |session| is client session.
  *
  * .. warning::
@@ -3919,12 +4040,12 @@
  * This function creates copies of all name/value pairs in |nva|.  It
  * also lower-cases all names in |nva|.  The order of elements in
  * |nva| is preserved.  For header fields with
- * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and
- * :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name
- * and value are not copied respectively.  With
- * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to
- * pass header field name in lowercase.  The application should
- * maintain the references to them until
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME` and
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set,
+ * header field name and value are not copied respectively.  With
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME`, application
+ * is responsible to pass header field name in lowercase.  The
+ * application should maintain the references to them until
  * :type:`nghttp2_on_frame_send_callback` or
  * :type:`nghttp2_on_frame_not_send_callback` is called.
  *
@@ -3936,16 +4057,16 @@
  * |nva| will be sent as response headers, which will result in error.
  *
  * This function has the same effect with `nghttp2_submit_headers()`,
- * with flags = :enum:`NGHTTP2_FLAG_END_STREAM` and both pri_spec and
- * stream_user_data to NULL.
+ * with flags = :enum:`nghttp2_flag.NGHTTP2_FLAG_END_STREAM` and both
+ * pri_spec and stream_user_data to NULL.
  *
  * To submit trailer fields after `nghttp2_submit_response()` is
  * called, the application has to specify
  * :type:`nghttp2_data_provider` to `nghttp2_submit_response()`.
  * Inside of :type:`nghttp2_data_source_read_callback`, when setting
- * :enum:`NGHTTP2_DATA_FLAG_EOF`, also set
- * :enum:`NGHTTP2_DATA_FLAG_NO_END_STREAM`.  After that, the
- * application can send trailer fields using
+ * :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_EOF`, also set
+ * :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_NO_END_STREAM`.  After
+ * that, the application can send trailer fields using
  * `nghttp2_submit_trailer()`.  `nghttp2_submit_trailer()` can be used
  * inside :type:`nghttp2_data_source_read_callback`.
  *
@@ -3953,9 +4074,9 @@
  * Otherwise, this function returns 0 if it succeeds, or one of the
  * following negative error codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
  *     The |stream_id| is 0.
  */
 NGHTTP2_EXTERN int nghttp2_submit_trailer(nghttp2_session *session,
@@ -3968,10 +4089,10 @@
  * Submits HEADERS frame. The |flags| is bitwise OR of the
  * following values:
  *
- * * :enum:`NGHTTP2_FLAG_END_STREAM`
+ * * :enum:`nghttp2_flag.NGHTTP2_FLAG_END_STREAM`
  *
- * If |flags| includes :enum:`NGHTTP2_FLAG_END_STREAM`, this frame has
- * END_STREAM flag set.
+ * If |flags| includes :enum:`nghttp2_flag.NGHTTP2_FLAG_END_STREAM`,
+ * this frame has END_STREAM flag set.
  *
  * The library handles the CONTINUATION frame internally and it
  * correctly sets END_HEADERS to the last sequence of the PUSH_PROMISE
@@ -3988,11 +4109,16 @@
  * use `nghttp2_priority_spec_init()`.  If |pri_spec| is not ``NULL``,
  * this function will copy its data members.
  *
- * The ``pri_spec->weight`` must be in [:enum:`NGHTTP2_MIN_WEIGHT`,
- * :enum:`NGHTTP2_MAX_WEIGHT`], inclusive.  If ``pri_spec->weight`` is
- * strictly less than :enum:`NGHTTP2_MIN_WEIGHT`, it becomes
- * :enum:`NGHTTP2_MIN_WEIGHT`.  If it is strictly greater than
- * :enum:`NGHTTP2_MAX_WEIGHT`, it becomes :enum:`NGHTTP2_MAX_WEIGHT`.
+ * The ``pri_spec->weight`` must be in [:macro:`NGHTTP2_MIN_WEIGHT`,
+ * :macro:`NGHTTP2_MAX_WEIGHT`], inclusive.  If ``pri_spec->weight``
+ * is strictly less than :macro:`NGHTTP2_MIN_WEIGHT`, it becomes
+ * :macro:`NGHTTP2_MIN_WEIGHT`.  If it is strictly greater than
+ * :macro:`NGHTTP2_MAX_WEIGHT`, it becomes :macro:`NGHTTP2_MAX_WEIGHT`.
+ *
+ * If
+ * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
+ * of value of 1 is received by a remote endpoint, |pri_spec| is
+ * ignored, and treated as if ``NULL`` is specified.
  *
  * The |nva| is an array of name/value pair :type:`nghttp2_nv` with
  * |nvlen| elements.  The application is responsible to include
@@ -4003,12 +4129,12 @@
  * This function creates copies of all name/value pairs in |nva|.  It
  * also lower-cases all names in |nva|.  The order of elements in
  * |nva| is preserved.  For header fields with
- * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and
- * :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name
- * and value are not copied respectively.  With
- * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to
- * pass header field name in lowercase.  The application should
- * maintain the references to them until
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME` and
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set,
+ * header field name and value are not copied respectively.  With
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME`, application
+ * is responsible to pass header field name in lowercase.  The
+ * application should maintain the references to them until
  * :type:`nghttp2_on_frame_send_callback` or
  * :type:`nghttp2_on_frame_not_send_callback` is called.
  *
@@ -4026,19 +4152,19 @@
  * |stream_id| is -1.  Otherwise, this function returns 0 if it
  * succeeds, or one of the following negative error codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
- * :enum:`NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE`
  *     No stream ID is available because maximum stream ID was
  *     reached.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
  *     The |stream_id| is 0; or trying to depend on itself (stream ID
  *     equals ``pri_spec->stream_id``).
- * :enum:`NGHTTP2_ERR_DATA_EXIST`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_DATA_EXIST`
  *     DATA or HEADERS has been already submitted and not fully
  *     processed yet.  This happens if stream denoted by |stream_id|
  *     is in reserved state.
- * :enum:`NGHTTP2_ERR_PROTO`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_PROTO`
  *     The |stream_id| is -1, and |session| is server session.
  *
  * .. warning::
@@ -4060,8 +4186,8 @@
  *
  * Submits one or more DATA frames to the stream |stream_id|.  The
  * data to be sent are provided by |data_prd|.  If |flags| contains
- * :enum:`NGHTTP2_FLAG_END_STREAM`, the last DATA frame has END_STREAM
- * flag set.
+ * :enum:`nghttp2_flag.NGHTTP2_FLAG_END_STREAM`, the last DATA frame
+ * has END_STREAM flag set.
  *
  * This function does not take ownership of the |data_prd|.  The
  * function copies the members of the |data_prd|.
@@ -4069,27 +4195,28 @@
  * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
- * :enum:`NGHTTP2_ERR_DATA_EXIST`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_DATA_EXIST`
  *     DATA or HEADERS has been already submitted and not fully
  *     processed yet.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
  *     The |stream_id| is 0.
- * :enum:`NGHTTP2_ERR_STREAM_CLOSED`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_STREAM_CLOSED`
  *     The stream was already closed; or the |stream_id| is invalid.
  *
  * .. note::
  *
  *   Currently, only one DATA or HEADERS is allowed for a stream at a
  *   time.  Submitting these frames more than once before first DATA
- *   or HEADERS is finished results in :enum:`NGHTTP2_ERR_DATA_EXIST`
- *   error code.  The earliest callback which tells that previous
- *   frame is done is :type:`nghttp2_on_frame_send_callback`.  In side
- *   that callback, new data can be submitted using
- *   `nghttp2_submit_data()`.  Of course, all data except for last one
- *   must not have :enum:`NGHTTP2_FLAG_END_STREAM` flag set in
- *   |flags|.  This sounds a bit complicated, and we recommend to use
+ *   or HEADERS is finished results in
+ *   :enum:`nghttp2_error.NGHTTP2_ERR_DATA_EXIST` error code.  The
+ *   earliest callback which tells that previous frame is done is
+ *   :type:`nghttp2_on_frame_send_callback`.  In side that callback,
+ *   new data can be submitted using `nghttp2_submit_data()`.  Of
+ *   course, all data except for last one must not have
+ *   :enum:`nghttp2_flag.NGHTTP2_FLAG_END_STREAM` flag set in |flags|.
+ *   This sounds a bit complicated, and we recommend to use
  *   `nghttp2_submit_request()` and `nghttp2_submit_response()` to
  *   avoid this cascading issue.  The experience shows that for HTTP
  *   use, these two functions are enough to implement both client and
@@ -4106,25 +4233,31 @@
  * to the priority specification |pri_spec|.
  *
  * The |flags| is currently ignored and should be
- * :enum:`NGHTTP2_FLAG_NONE`.
+ * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`.
  *
  * The |pri_spec| is priority specification of this request.  ``NULL``
  * is not allowed for this function. To specify the priority, use
  * `nghttp2_priority_spec_init()`.  This function will copy its data
  * members.
  *
- * The ``pri_spec->weight`` must be in [:enum:`NGHTTP2_MIN_WEIGHT`,
- * :enum:`NGHTTP2_MAX_WEIGHT`], inclusive.  If ``pri_spec->weight`` is
- * strictly less than :enum:`NGHTTP2_MIN_WEIGHT`, it becomes
- * :enum:`NGHTTP2_MIN_WEIGHT`.  If it is strictly greater than
- * :enum:`NGHTTP2_MAX_WEIGHT`, it becomes :enum:`NGHTTP2_MAX_WEIGHT`.
+ * The ``pri_spec->weight`` must be in [:macro:`NGHTTP2_MIN_WEIGHT`,
+ * :macro:`NGHTTP2_MAX_WEIGHT`], inclusive.  If ``pri_spec->weight``
+ * is strictly less than :macro:`NGHTTP2_MIN_WEIGHT`, it becomes
+ * :macro:`NGHTTP2_MIN_WEIGHT`.  If it is strictly greater than
+ * :macro:`NGHTTP2_MAX_WEIGHT`, it becomes
+ * :macro:`NGHTTP2_MAX_WEIGHT`.
+ *
+ * If
+ * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
+ * of value of 1 is received by a remote endpoint, this function does
+ * nothing and returns 0.
  *
  * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
  *     The |stream_id| is 0; or the |pri_spec| is NULL; or trying to
  *     depend on itself.
  */
@@ -4134,6 +4267,61 @@
                         const nghttp2_priority_spec *pri_spec);
 
 /**
+ * @macro
+ *
+ * :macro:`NGHTTP2_EXTPRI_DEFAULT_URGENCY` is the default urgency
+ * level for :rfc:`9218` extensible priorities.
+ */
+#define NGHTTP2_EXTPRI_DEFAULT_URGENCY 3
+
+/**
+ * @macro
+ *
+ * :macro:`NGHTTP2_EXTPRI_URGENCY_HIGH` is the highest urgency level
+ * for :rfc:`9218` extensible priorities.
+ */
+#define NGHTTP2_EXTPRI_URGENCY_HIGH 0
+
+/**
+ * @macro
+ *
+ * :macro:`NGHTTP2_EXTPRI_URGENCY_LOW` is the lowest urgency level for
+ * :rfc:`9218` extensible priorities.
+ */
+#define NGHTTP2_EXTPRI_URGENCY_LOW 7
+
+/**
+ * @macro
+ *
+ * :macro:`NGHTTP2_EXTPRI_URGENCY_LEVELS` is the number of urgency
+ * levels for :rfc:`9218` extensible priorities.
+ */
+#define NGHTTP2_EXTPRI_URGENCY_LEVELS (NGHTTP2_EXTPRI_URGENCY_LOW + 1)
+
+/**
+ * @struct
+ *
+ * :type:`nghttp2_extpri` is :rfc:`9218` extensible priorities
+ * specification for a stream.
+ */
+typedef struct nghttp2_extpri {
+  /**
+   * :member:`urgency` is the urgency of a stream, it must be in
+   * [:macro:`NGHTTP2_EXTPRI_URGENCY_HIGH`,
+   * :macro:`NGHTTP2_EXTPRI_URGENCY_LOW`], inclusive, and 0 is the
+   * highest urgency.
+   */
+  uint32_t urgency;
+  /**
+   * :member:`inc` indicates that a content can be processed
+   * incrementally or not.  If inc is 0, it cannot be processed
+   * incrementally.  If inc is 1, it can be processed incrementally.
+   * Other value is not permitted.
+   */
+  int inc;
+} nghttp2_extpri;
+
+/**
  * @function
  *
  * Submits RST_STREAM frame to cancel/reject the stream |stream_id|
@@ -4142,14 +4330,14 @@
  * The pre-defined error code is one of :enum:`nghttp2_error_code`.
  *
  * The |flags| is currently ignored and should be
- * :enum:`NGHTTP2_FLAG_NONE`.
+ * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`.
  *
  * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
  *     The |stream_id| is 0.
  */
 NGHTTP2_EXTERN int nghttp2_submit_rst_stream(nghttp2_session *session,
@@ -4164,7 +4352,7 @@
  * indicates the number of :type:`nghttp2_settings_entry`.
  *
  * The |flags| is currently ignored and should be
- * :enum:`NGHTTP2_FLAG_NONE`.
+ * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`.
  *
  * This function does not take ownership of the |iv|.  This function
  * copies all the elements in the |iv|.
@@ -4173,16 +4361,17 @@
  * size becomes strictly larger than NGHTTP2_MAX_WINDOW_SIZE,
  * RST_STREAM is issued against such a stream.
  *
- * SETTINGS with :enum:`NGHTTP2_FLAG_ACK` is automatically submitted
- * by the library and application could not send it at its will.
+ * SETTINGS with :enum:`nghttp2_flag.NGHTTP2_FLAG_ACK` is
+ * automatically submitted by the library and application could not
+ * send it at its will.
  *
  * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
  *
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
  *     The |iv| contains invalid value (e.g., initial window size
  *     strictly greater than (1 << 31) - 1.
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
  */
 NGHTTP2_EXTERN int nghttp2_submit_settings(nghttp2_session *session,
@@ -4210,12 +4399,12 @@
  * This function creates copies of all name/value pairs in |nva|.  It
  * also lower-cases all names in |nva|.  The order of elements in
  * |nva| is preserved.  For header fields with
- * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and
- * :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name
- * and value are not copied respectively.  With
- * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to
- * pass header field name in lowercase.  The application should
- * maintain the references to them until
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME` and
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set,
+ * header field name and value are not copied respectively.  With
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME`, application
+ * is responsible to pass header field name in lowercase.  The
+ * application should maintain the references to them until
  * :type:`nghttp2_on_frame_send_callback` or
  * :type:`nghttp2_on_frame_not_send_callback` is called.
  *
@@ -4234,18 +4423,18 @@
  * This function returns assigned promised stream ID if it succeeds,
  * or one of the following negative error codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
- * :enum:`NGHTTP2_ERR_PROTO`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_PROTO`
  *     This function was invoked when |session| is initialized as
  *     client.
- * :enum:`NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE`
  *     No stream ID is available because maximum stream ID was
  *     reached.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
  *     The |stream_id| is 0; The |stream_id| does not designate stream
  *     that peer initiated.
- * :enum:`NGHTTP2_ERR_STREAM_CLOSED`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_STREAM_CLOSED`
  *     The stream was already closed; or the |stream_id| is invalid.
  *
  * .. warning::
@@ -4274,10 +4463,10 @@
  *
  * The |flags| is bitwise OR of 0 or more of the following value.
  *
- * * :enum:`NGHTTP2_FLAG_ACK`
+ * * :enum:`nghttp2_flag.NGHTTP2_FLAG_ACK`
  *
  * Unless `nghttp2_option_set_no_auto_ping_ack()` is used, the |flags|
- * should be :enum:`NGHTTP2_FLAG_NONE`.
+ * should be :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`.
  *
  * If the |opaque_data| is non ``NULL``, then it should point to the 8
  * bytes array of memory to specify opaque data to send with PING
@@ -4287,7 +4476,7 @@
  * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
  */
 NGHTTP2_EXTERN int nghttp2_submit_ping(nghttp2_session *session, uint8_t flags,
@@ -4302,7 +4491,7 @@
  * The pre-defined error code is one of :enum:`nghttp2_error_code`.
  *
  * The |flags| is currently ignored and should be
- * :enum:`NGHTTP2_FLAG_NONE`.
+ * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`.
  *
  * The |last_stream_id| is peer's stream ID or 0.  So if |session| is
  * initialized as client, |last_stream_id| must be even or 0.  If
@@ -4332,9 +4521,9 @@
  * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
  *     The |opaque_data_len| is too large; the |last_stream_id| is
  *     invalid.
  */
@@ -4390,7 +4579,7 @@
  * Submits WINDOW_UPDATE frame.
  *
  * The |flags| is currently ignored and should be
- * :enum:`NGHTTP2_FLAG_NONE`.
+ * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`.
  *
  * The |stream_id| is the stream ID to send this WINDOW_UPDATE.  To
  * send connection level WINDOW_UPDATE, specify 0 to |stream_id|.
@@ -4417,9 +4606,9 @@
  * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
  *
- * :enum:`NGHTTP2_ERR_FLOW_CONTROL`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_FLOW_CONTROL`
  *     The local window size overflow or gets negative.
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
  */
 NGHTTP2_EXTERN int nghttp2_submit_window_update(nghttp2_session *session,
@@ -4437,7 +4626,7 @@
  * to transmission queue.
  *
  * The |flags| is currently ignored and should be
- * :enum:`NGHTTP2_FLAG_NONE`.
+ * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`.
  *
  * This sounds similar to `nghttp2_submit_window_update()`, but there
  * are 2 differences.  The first difference is that this function
@@ -4456,9 +4645,9 @@
  * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
  *
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
  *     The |stream_id| is negative.
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
  */
 NGHTTP2_EXTERN int
@@ -4489,18 +4678,19 @@
  *
  * The standard HTTP/2 frame cannot be sent with this function, so
  * |type| must be strictly grater than 0x9.  Otherwise, this function
- * will fail with error code :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`.
+ * will fail with error code
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`.
  *
  * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
  *
- * :enum:`NGHTTP2_ERR_INVALID_STATE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`
  *     If :type:`nghttp2_pack_extension_callback` is not set.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
  *     If  |type| specifies  standard  HTTP/2 frame  type.  The  frame
  *     types  in the  rage [0x0,  0x9], both  inclusive, are  standard
  *     HTTP/2 frame type, and cannot be sent using this function.
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory
  */
 NGHTTP2_EXTERN int nghttp2_submit_extension(nghttp2_session *session,
@@ -4514,8 +4704,8 @@
  * extension to HTTP/2.  If this frame is received, and
  * `nghttp2_option_set_user_recv_extension_type()` is not set, and
  * `nghttp2_option_set_builtin_recv_extension_type()` is set for
- * :enum:`NGHTTP2_ALTSVC`, ``nghttp2_extension.payload`` will point to
- * this struct.
+ * :enum:`nghttp2_frame_type.NGHTTP2_ALTSVC`,
+ * ``nghttp2_extension.payload`` will point to this struct.
  *
  * It has the following members:
  */
@@ -4549,7 +4739,7 @@
  * `RFC 7383 <https://tools.ietf.org/html/rfc7838#section-4>`_.
  *
  * The |flags| is currently ignored and should be
- * :enum:`NGHTTP2_FLAG_NONE`.
+ * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`.
  *
  * The |origin| points to the origin this alternative service is
  * associated with.  The |origin_len| is the length of the origin.  If
@@ -4559,16 +4749,16 @@
  *
  * The ALTSVC frame is only usable from server side.  If this function
  * is invoked with client side session, this function returns
- * :enum:`NGHTTP2_ERR_INVALID_STATE`.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`.
  *
  * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory
- * :enum:`NGHTTP2_ERR_INVALID_STATE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`
  *     The function is called from client side session
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
  *     The sum of |origin_len| and |field_value_len| is larger than
  *     16382; or |origin_len| is 0 while |stream_id| is 0; or
  *     |origin_len| is not 0 while |stream_id| is not 0.
@@ -4607,8 +4797,8 @@
  * If this frame is received, and
  * `nghttp2_option_set_user_recv_extension_type()` is not set, and
  * `nghttp2_option_set_builtin_recv_extension_type()` is set for
- * :enum:`NGHTTP2_ORIGIN`, ``nghttp2_extension.payload`` will point to
- * this struct.
+ * :enum:`nghttp2_frame_type.NGHTTP2_ORIGIN`,
+ * ``nghttp2_extension.payload`` will point to this struct.
  *
  * It has the following members:
  */
@@ -4632,7 +4822,7 @@
  * `RFC 8336 <https://tools.ietf.org/html/rfc8336>`_.
  *
  * The |flags| is currently ignored and should be
- * :enum:`NGHTTP2_FLAG_NONE`.
+ * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`.
  *
  * The |ov| points to the array of origins.  The |nov| specifies the
  * number of origins included in |ov|.  This function creates copies
@@ -4640,13 +4830,13 @@
  *
  * The ORIGIN frame is only usable by a server.  If this function is
  * invoked with client side session, this function returns
- * :enum:`NGHTTP2_ERR_INVALID_STATE`.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`.
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory
- * :enum:`NGHTTP2_ERR_INVALID_STATE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`
  *     The function is called from client side session.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
  *     There are too many origins, or an origin is too large to fit
  *     into a default frame payload.
  */
@@ -4656,6 +4846,108 @@
                                          size_t nov);
 
 /**
+ * @struct
+ *
+ * The payload of PRIORITY_UPDATE frame.  PRIORITY_UPDATE frame is a
+ * non-critical extension to HTTP/2.  If this frame is received, and
+ * `nghttp2_option_set_user_recv_extension_type()` is not set, and
+ * `nghttp2_option_set_builtin_recv_extension_type()` is set for
+ * :enum:`nghttp2_frame_type.NGHTTP2_PRIORITY_UPDATE`,
+ * ``nghttp2_extension.payload`` will point to this struct.
+ *
+ * It has the following members:
+ */
+typedef struct {
+  /**
+   * The stream ID of the stream whose priority is updated.
+   */
+  int32_t stream_id;
+  /**
+   * The pointer to Priority field value.  It is not necessarily
+   * NULL-terminated.
+   */
+  uint8_t *field_value;
+  /**
+   * The length of the :member:`field_value`.
+   */
+  size_t field_value_len;
+} nghttp2_ext_priority_update;
+
+/**
+ * @function
+ *
+ * Submits PRIORITY_UPDATE frame.
+ *
+ * PRIORITY_UPDATE frame is a non-critical extension to HTTP/2, and
+ * defined in :rfc:`9218#section-7.1`.
+ *
+ * The |flags| is currently ignored and should be
+ * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`.
+ *
+ * The |stream_id| is the ID of stream which is prioritized.  The
+ * |field_value| points to the Priority field value.  The
+ * |field_value_len| is the length of the Priority field value.
+ *
+ * If this function is called by server,
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE` is returned.
+ *
+ * If
+ * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
+ * of value of 0 is received by a remote endpoint (or it is omitted),
+ * this function does nothing and returns 0.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
+ *     Out of memory
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`
+ *     The function is called from server side session
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The |field_value_len| is larger than 16380; or |stream_id| is
+ *     0.
+ */
+NGHTTP2_EXTERN int nghttp2_submit_priority_update(nghttp2_session *session,
+                                                  uint8_t flags,
+                                                  int32_t stream_id,
+                                                  const uint8_t *field_value,
+                                                  size_t field_value_len);
+
+/**
+ * @function
+ *
+ * Changes the priority of the existing stream denoted by |stream_id|.
+ * The new priority is |extpri|.  This function is meant to be used by
+ * server for :rfc:`9218` extensible prioritization scheme.
+ *
+ * If |session| is initialized as client, this function returns
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`.  For client, use
+ * `nghttp2_submit_priority_update()` instead.
+ *
+ * If :member:`extpri->urgency <nghttp2_extpri.urgency>` is out of
+ * bound, it is set to :macro:`NGHTTP2_EXTPRI_URGENCY_LOW`.
+ *
+ * If |ignore_client_signal| is nonzero, server starts to ignore
+ * client priority signals for this stream.
+ *
+ * If
+ * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
+ * of value of 1 is not submitted via `nghttp2_submit_settings()`,
+ * this function does nothing and returns 0.
+ *
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`
+ *     The |session| is initialized as client.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     |stream_id| is zero; or a stream denoted by |stream_id| is not
+ *     found.
+ */
+NGHTTP2_EXTERN int nghttp2_session_change_extpri_stream_priority(
+    nghttp2_session *session, int32_t stream_id, const nghttp2_extpri *extpri,
+    int ignore_client_signal);
+
+/**
  * @function
  *
  * Compares ``lhs->name`` of length ``lhs->namelen`` bytes and
@@ -4766,13 +5058,51 @@
  * Returns nonzero if HTTP header field value |value| of length |len|
  * is valid according to
  * http://tools.ietf.org/html/rfc7230#section-3.2
+ *
+ * This function is considered obsolete, and application should
+ * consider to use `nghttp2_check_header_value_rfc9113()` instead.
  */
 NGHTTP2_EXTERN int nghttp2_check_header_value(const uint8_t *value, size_t len);
 
 /**
  * @function
  *
- * Returns nonzero if the |value| which is supposed to the value of
+ * Returns nonzero if HTTP header field value |value| of length |len|
+ * is valid according to
+ * http://tools.ietf.org/html/rfc7230#section-3.2, plus
+ * https://datatracker.ietf.org/doc/html/rfc9113#section-8.2.1
+ */
+NGHTTP2_EXTERN int nghttp2_check_header_value_rfc9113(const uint8_t *value,
+                                                      size_t len);
+
+/**
+ * @function
+ *
+ * Returns nonzero if the |value| which is supposed to be the value of
+ * the :method header field is valid according to
+ * https://datatracker.ietf.org/doc/html/rfc7231#section-4 and
+ * https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6
+ */
+NGHTTP2_EXTERN int nghttp2_check_method(const uint8_t *value, size_t len);
+
+/**
+ * @function
+ *
+ * Returns nonzero if the |value| which is supposed to be the value of
+ * the :path header field is valid according to
+ * https://datatracker.ietf.org/doc/html/rfc7540#section-8.1.2.3
+ *
+ * |value| is valid if it merely consists of the allowed characters.
+ * In particular, it does not check whether |value| follows the syntax
+ * of path.  The allowed characters are all characters valid by
+ * `nghttp2_check_header_value` minus SPC and HT.
+ */
+NGHTTP2_EXTERN int nghttp2_check_path(const uint8_t *value, size_t len);
+
+/**
+ * @function
+ *
+ * Returns nonzero if the |value| which is supposed to be the value of the
  * :authority or host header field is valid according to
  * https://tools.ietf.org/html/rfc3986#section-3.2
  *
@@ -4806,7 +5136,7 @@
  * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
  */
 NGHTTP2_EXTERN int
@@ -4860,7 +5190,7 @@
  * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
  */
 NGHTTP2_EXTERN int
@@ -4874,24 +5204,24 @@
  * the |buf| of length |buflen|.
  *
  * If |buf| is not large enough to store the deflated header block,
- * this function fails with :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE`.  The
- * caller should use `nghttp2_hd_deflate_bound()` to know the upper
- * bound of buffer size required to deflate given header name/value
- * pairs.
+ * this function fails with
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INSUFF_BUFSIZE`.  The caller
+ * should use `nghttp2_hd_deflate_bound()` to know the upper bound of
+ * buffer size required to deflate given header name/value pairs.
  *
  * Once this function fails, subsequent call of this function always
- * returns :enum:`NGHTTP2_ERR_HEADER_COMP`.
+ * returns :enum:`nghttp2_error.NGHTTP2_ERR_HEADER_COMP`.
  *
  * After this function returns, it is safe to delete the |nva|.
  *
  * This function returns the number of bytes written to |buf| if it
  * succeeds, or one of the following negative error codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
- * :enum:`NGHTTP2_ERR_HEADER_COMP`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_HEADER_COMP`
  *     Deflation process has failed.
- * :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INSUFF_BUFSIZE`
  *     The provided |buflen| size is too small to hold the output.
  */
 NGHTTP2_EXTERN ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater,
@@ -4907,23 +5237,24 @@
  * must be set in len field of :type:`nghttp2_vec`.  If and only if
  * one chunk is filled up completely, next chunk will be used.  If
  * |vec| is not large enough to store the deflated header block, this
- * function fails with :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE`.  The caller
+ * function fails with
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INSUFF_BUFSIZE`.  The caller
  * should use `nghttp2_hd_deflate_bound()` to know the upper bound of
  * buffer size required to deflate given header name/value pairs.
  *
  * Once this function fails, subsequent call of this function always
- * returns :enum:`NGHTTP2_ERR_HEADER_COMP`.
+ * returns :enum:`nghttp2_error.NGHTTP2_ERR_HEADER_COMP`.
  *
  * After this function returns, it is safe to delete the |nva|.
  *
  * This function returns the number of bytes written to |vec| if it
  * succeeds, or one of the following negative error codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
- * :enum:`NGHTTP2_ERR_HEADER_COMP`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_HEADER_COMP`
  *     Deflation process has failed.
- * :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INSUFF_BUFSIZE`
  *     The provided |buflen| size is too small to hold the output.
  */
 NGHTTP2_EXTERN ssize_t nghttp2_hd_deflate_hd_vec(nghttp2_hd_deflater *deflater,
@@ -5003,7 +5334,7 @@
  * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
  */
 NGHTTP2_EXTERN int nghttp2_hd_inflate_new(nghttp2_hd_inflater **inflater_ptr);
@@ -5052,9 +5383,9 @@
  * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_STATE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`
  *     The function is called while header block is being inflated.
  *     Probably, application missed to call
  *     `nghttp2_hd_inflate_end_headers()`.
@@ -5092,7 +5423,8 @@
  *
  * Inflates name/value block stored in |in| with length |inlen|.  This
  * function performs decompression.  For each successful emission of
- * header name/value pair, :enum:`NGHTTP2_HD_INFLATE_EMIT` is set in
+ * header name/value pair,
+ * :enum:`nghttp2_hd_inflate_flag.NGHTTP2_HD_INFLATE_EMIT` is set in
  * |*inflate_flags| and name/value pair is assigned to the |nv_out|
  * and the function returns.  The caller must not free the members of
  * |nv_out|.
@@ -5115,11 +5447,11 @@
  * This function returns the number of bytes processed if it succeeds,
  * or one of the following negative error codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
- * :enum:`NGHTTP2_ERR_HEADER_COMP`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_HEADER_COMP`
  *     Inflation process has failed.
- * :enum:`NGHTTP2_ERR_BUFFER_ERROR`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_BUFFER_ERROR`
  *     The header field name or value is too large.
  *
  * Example follows::
@@ -5174,7 +5506,8 @@
  *
  * Inflates name/value block stored in |in| with length |inlen|.  This
  * function performs decompression.  For each successful emission of
- * header name/value pair, :enum:`NGHTTP2_HD_INFLATE_EMIT` is set in
+ * header name/value pair,
+ * :enum:`nghttp2_hd_inflate_flag.NGHTTP2_HD_INFLATE_EMIT` is set in
  * |*inflate_flags| and name/value pair is assigned to the |nv_out|
  * and the function returns.  The caller must not free the members of
  * |nv_out|.
@@ -5190,8 +5523,9 @@
  * for the next header block input.
  *
  * In other words, if |in_final| is nonzero, and this function returns
- * |inlen|, you can assert that :enum:`NGHTTP2_HD_INFLATE_FINAL` is
- * set in |*inflate_flags|.
+ * |inlen|, you can assert that
+ * :enum:`nghttp2_hd_inflate_final.NGHTTP2_HD_INFLATE_FINAL` is set in
+ * |*inflate_flags|.
  *
  * The caller can feed complete compressed header block.  It also can
  * feed it in several chunks.  The caller must set |in_final| to
@@ -5201,11 +5535,11 @@
  * This function returns the number of bytes processed if it succeeds,
  * or one of the following negative error codes:
  *
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
  *     Out of memory.
- * :enum:`NGHTTP2_ERR_HEADER_COMP`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_HEADER_COMP`
  *     Inflation process has failed.
- * :enum:`NGHTTP2_ERR_BUFFER_ERROR`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_BUFFER_ERROR`
  *     The header field name or value is too large.
  *
  * Example follows::
@@ -5376,7 +5710,7 @@
  *
  * Returns state of |stream|.  The root stream retrieved by
  * `nghttp2_session_get_root_stream()` will have stream state
- * :enum:`NGHTTP2_STREAM_STATE_IDLE`.
+ * :enum:`nghttp2_stream_proto_state.NGHTTP2_STREAM_STATE_IDLE`.
  */
 NGHTTP2_EXTERN nghttp2_stream_proto_state
 nghttp2_stream_get_state(nghttp2_stream *stream);
diff --git a/Utilities/cmnghttp2/lib/nghttp2_buf.c b/Utilities/cmnghttp2/lib/nghttp2_buf.c
index 2a435be..a328447 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_buf.c
+++ b/Utilities/cmnghttp2/lib/nghttp2_buf.c
@@ -82,8 +82,10 @@
 }
 
 void nghttp2_buf_wrap_init(nghttp2_buf *buf, uint8_t *begin, size_t len) {
-  buf->begin = buf->pos = buf->last = buf->mark = begin;
-  buf->end = begin + len;
+  buf->begin = buf->pos = buf->last = buf->mark = buf->end = begin;
+  if (len) {
+    buf->end += len;
+  }
 }
 
 static int buf_chain_new(nghttp2_buf_chain **chain, size_t chunk_length,
diff --git a/Utilities/cmnghttp2/lib/nghttp2_buf.h b/Utilities/cmnghttp2/lib/nghttp2_buf.h
index 06cce67..45f62f1 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_buf.h
+++ b/Utilities/cmnghttp2/lib/nghttp2_buf.h
@@ -99,7 +99,7 @@
  * |new_cap|. If extensions took place, buffer pointers in |buf| will
  * change.
  *
- * This function returns 0 if it succeeds, or one of the followings
+ * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
  *
  * NGHTTP2_ERR_NOMEM
diff --git a/Utilities/cmnghttp2/lib/nghttp2_extpri.c b/Utilities/cmnghttp2/lib/nghttp2_extpri.c
new file mode 100644
index 0000000..3fd9b78
--- /dev/null
+++ b/Utilities/cmnghttp2/lib/nghttp2_extpri.c
@@ -0,0 +1,35 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2022 nghttp3 contributors
+ * Copyright (c) 2022 nghttp2 contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "nghttp2_extpri.h"
+
+uint8_t nghttp2_extpri_to_uint8(const nghttp2_extpri *extpri) {
+  return (uint8_t)((uint32_t)extpri->inc << 7 | extpri->urgency);
+}
+
+void nghttp2_extpri_from_uint8(nghttp2_extpri *extpri, uint8_t u8extpri) {
+  extpri->urgency = nghttp2_extpri_uint8_urgency(u8extpri);
+  extpri->inc = nghttp2_extpri_uint8_inc(u8extpri);
+}
diff --git a/Utilities/cmnghttp2/lib/nghttp2_extpri.h b/Utilities/cmnghttp2/lib/nghttp2_extpri.h
new file mode 100644
index 0000000..23c6ddc
--- /dev/null
+++ b/Utilities/cmnghttp2/lib/nghttp2_extpri.h
@@ -0,0 +1,65 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2022 nghttp3 contributors
+ * Copyright (c) 2022 nghttp2 contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef NGHTTP2_EXTPRI_H
+#define NGHTTP2_EXTPRI_H
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+
+/*
+ * NGHTTP2_EXTPRI_INC_MASK is a bit mask to retrieve incremental bit
+ * from a value produced by nghttp2_extpri_to_uint8.
+ */
+#define NGHTTP2_EXTPRI_INC_MASK (1 << 7)
+
+/*
+ * nghttp2_extpri_to_uint8 encodes |pri| into uint8_t variable.
+ */
+uint8_t nghttp2_extpri_to_uint8(const nghttp2_extpri *extpri);
+
+/*
+ * nghttp2_extpri_from_uint8 decodes |u8extpri|, which is produced by
+ * nghttp2_extpri_to_uint8, intto |extpri|.
+ */
+void nghttp2_extpri_from_uint8(nghttp2_extpri *extpri, uint8_t u8extpri);
+
+/*
+ * nghttp2_extpri_uint8_urgency extracts urgency from |PRI| which is
+ * supposed to be constructed by nghttp2_extpri_to_uint8.
+ */
+#define nghttp2_extpri_uint8_urgency(PRI)                                      \
+  ((uint32_t)((PRI) & ~NGHTTP2_EXTPRI_INC_MASK))
+
+/*
+ * nghttp2_extpri_uint8_inc extracts inc from |PRI| which is supposed to
+ * be constructed by nghttp2_extpri_to_uint8.
+ */
+#define nghttp2_extpri_uint8_inc(PRI) (((PRI)&NGHTTP2_EXTPRI_INC_MASK) != 0)
+
+#endif /* NGHTTP2_EXTPRI_H */
diff --git a/Utilities/cmnghttp2/lib/nghttp2_frame.c b/Utilities/cmnghttp2/lib/nghttp2_frame.c
index 4821de4..35072c1 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_frame.c
+++ b/Utilities/cmnghttp2/lib/nghttp2_frame.c
@@ -253,6 +253,31 @@
   nghttp2_mem_free(mem, origin->ov);
 }
 
+void nghttp2_frame_priority_update_init(nghttp2_extension *frame,
+                                        int32_t stream_id, uint8_t *field_value,
+                                        size_t field_value_len) {
+  nghttp2_ext_priority_update *priority_update;
+
+  nghttp2_frame_hd_init(&frame->hd, 4 + field_value_len,
+                        NGHTTP2_PRIORITY_UPDATE, NGHTTP2_FLAG_NONE, 0);
+
+  priority_update = frame->payload;
+  priority_update->stream_id = stream_id;
+  priority_update->field_value = field_value;
+  priority_update->field_value_len = field_value_len;
+}
+
+void nghttp2_frame_priority_update_free(nghttp2_extension *frame,
+                                        nghttp2_mem *mem) {
+  nghttp2_ext_priority_update *priority_update;
+
+  priority_update = frame->payload;
+  if (priority_update == NULL) {
+    return;
+  }
+  nghttp2_mem_free(mem, priority_update->field_value);
+}
+
 size_t nghttp2_frame_priority_len(uint8_t flags) {
   if (flags & NGHTTP2_FLAG_PRIORITY) {
     return NGHTTP2_PRIORITY_SPECLEN;
@@ -654,8 +679,6 @@
     var_gift_payloadlen = 0;
   }
 
-  payloadlen -= var_gift_payloadlen;
-
   if (!var_gift_payloadlen) {
     var_gift_payload = NULL;
   } else {
@@ -818,8 +841,10 @@
   size_t len = 0;
 
   origin = frame->payload;
-  p = payload;
-  end = p + payloadlen;
+  p = end = payload;
+  if (payloadlen) {
+    end += payloadlen;
+  }
 
   for (; p != end;) {
     if (end - p < 2) {
@@ -876,6 +901,57 @@
   return 0;
 }
 
+int nghttp2_frame_pack_priority_update(nghttp2_bufs *bufs,
+                                       nghttp2_extension *frame) {
+  int rv;
+  nghttp2_buf *buf;
+  nghttp2_ext_priority_update *priority_update;
+
+  /* This is required with --disable-assert. */
+  (void)rv;
+
+  priority_update = frame->payload;
+
+  buf = &bufs->head->buf;
+
+  assert(nghttp2_buf_avail(buf) >= 4 + priority_update->field_value_len);
+
+  buf->pos -= NGHTTP2_FRAME_HDLEN;
+
+  nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
+
+  nghttp2_put_uint32be(buf->last, (uint32_t)priority_update->stream_id);
+  buf->last += 4;
+
+  rv = nghttp2_bufs_add(bufs, priority_update->field_value,
+                        priority_update->field_value_len);
+
+  assert(rv == 0);
+
+  return 0;
+}
+
+void nghttp2_frame_unpack_priority_update_payload(nghttp2_extension *frame,
+                                                  uint8_t *payload,
+                                                  size_t payloadlen) {
+  nghttp2_ext_priority_update *priority_update;
+
+  assert(payloadlen >= 4);
+
+  priority_update = frame->payload;
+
+  priority_update->stream_id =
+      nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK;
+
+  if (payloadlen > 4) {
+    priority_update->field_value = payload + 4;
+    priority_update->field_value_len = payloadlen - 4;
+  } else {
+    priority_update->field_value = NULL;
+    priority_update->field_value_len = 0;
+  }
+}
+
 nghttp2_settings_entry *nghttp2_frame_iv_copy(const nghttp2_settings_entry *iv,
                                               size_t niv, nghttp2_mem *mem) {
   nghttp2_settings_entry *iv_copy;
@@ -897,9 +973,25 @@
 }
 
 int nghttp2_nv_equal(const nghttp2_nv *a, const nghttp2_nv *b) {
-  return a->namelen == b->namelen && a->valuelen == b->valuelen &&
-         memcmp(a->name, b->name, a->namelen) == 0 &&
-         memcmp(a->value, b->value, a->valuelen) == 0;
+  if (a->namelen != b->namelen || a->valuelen != b->valuelen) {
+    return 0;
+  }
+
+  if (a->name == NULL || b->name == NULL) {
+    assert(a->namelen == 0);
+    assert(b->namelen == 0);
+  } else if (memcmp(a->name, b->name, a->namelen) != 0) {
+    return 0;
+  }
+
+  if (a->value == NULL || b->value == NULL) {
+    assert(a->valuelen == 0);
+    assert(b->valuelen == 0);
+  } else if (memcmp(a->value, b->value, a->valuelen) != 0) {
+    return 0;
+  }
+
+  return 1;
 }
 
 void nghttp2_nv_array_del(nghttp2_nv *nva, nghttp2_mem *mem) {
@@ -1055,6 +1147,11 @@
         return 0;
       }
       break;
+    case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES:
+      if (iv[i].value != 0 && iv[i].value != 1) {
+        return 0;
+      }
+      break;
     }
   }
   return 1;
diff --git a/Utilities/cmnghttp2/lib/nghttp2_frame.h b/Utilities/cmnghttp2/lib/nghttp2_frame.h
index 615bbf3..5f6152b 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_frame.h
+++ b/Utilities/cmnghttp2/lib/nghttp2_frame.h
@@ -46,7 +46,7 @@
 #define NGHTTP2_MAX_FRAME_SIZE_MIN (1 << 14)
 
 #define NGHTTP2_MAX_PAYLOADLEN 16384
-/* The one frame buffer length for tranmission.  We may use several of
+/* The one frame buffer length for transmission.  We may use several of
    them to support CONTINUATION.  To account for Pad Length field, we
    allocate extra 1 byte, which saves extra large memcopying. */
 #define NGHTTP2_FRAMEBUF_CHUNKLEN                                              \
@@ -57,7 +57,7 @@
 
 /* Maximum headers block size to send, calculated using
    nghttp2_hd_deflate_bound().  This is the default value, and can be
-   overridden by nghttp2_option_set_max_send_header_block_size(). */
+   overridden by nghttp2_option_set_max_send_header_block_length(). */
 #define NGHTTP2_MAX_HEADERSLEN 65536
 
 /* The number of bytes for each SETTINGS entry */
@@ -73,6 +73,7 @@
 typedef union {
   nghttp2_ext_altsvc altsvc;
   nghttp2_ext_origin origin;
+  nghttp2_ext_priority_update priority_update;
 } nghttp2_ext_frame_payload;
 
 void nghttp2_frame_pack_frame_hd(uint8_t *buf, const nghttp2_frame_hd *hd);
@@ -423,6 +424,31 @@
 int nghttp2_frame_unpack_origin_payload(nghttp2_extension *frame,
                                         const uint8_t *payload,
                                         size_t payloadlen, nghttp2_mem *mem);
+
+/*
+ * Packs PRIORITY_UPDATE frame |frame| in wire frame format and store
+ * it in |bufs|.
+ *
+ * The caller must make sure that nghttp2_bufs_reset(bufs) is called
+ * before calling this function.
+ *
+ * This function always succeeds and returns 0.
+ */
+int nghttp2_frame_pack_priority_update(nghttp2_bufs *bufs,
+                                       nghttp2_extension *ext);
+
+/*
+ * Unpacks PRIORITY_UPDATE wire format into |frame|.  The |payload| of
+ * |payloadlen| bytes contains frame payload.  This function assumes
+ * that frame->payload points to the nghttp2_ext_priority_update
+ * object.
+ *
+ * This function always succeeds and returns 0.
+ */
+void nghttp2_frame_unpack_priority_update_payload(nghttp2_extension *frame,
+                                                  uint8_t *payload,
+                                                  size_t payloadlen);
+
 /*
  * Initializes HEADERS frame |frame| with given values.  |frame| takes
  * ownership of |nva|, so caller must not free it. If |stream_id| is
@@ -539,6 +565,25 @@
 void nghttp2_frame_origin_free(nghttp2_extension *frame, nghttp2_mem *mem);
 
 /*
+ * Initializes PRIORITY_UPDATE frame |frame| with given values.  This
+ * function assumes that frame->payload points to
+ * nghttp2_ext_priority_update object.  On success, this function
+ * takes ownership of |field_value|, so caller must not free it.
+ */
+void nghttp2_frame_priority_update_init(nghttp2_extension *frame,
+                                        int32_t stream_id, uint8_t *field_value,
+                                        size_t field_value_len);
+
+/*
+ * Frees up resources under |frame|.  This function does not free
+ * nghttp2_ext_priority_update object pointed by frame->payload.  This
+ * function only frees field_value pointed by
+ * nghttp2_ext_priority_update.field_value.
+ */
+void nghttp2_frame_priority_update_free(nghttp2_extension *frame,
+                                        nghttp2_mem *mem);
+
+/*
  * Returns the number of padding bytes after payload.  The total
  * padding length is given in the |padlen|.  The returned value does
  * not include the Pad Length field.  If |padlen| is 0, this function
diff --git a/Utilities/cmnghttp2/lib/nghttp2_hd.c b/Utilities/cmnghttp2/lib/nghttp2_hd.c
index 5e86931..8a2bda6 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_hd.c
+++ b/Utilities/cmnghttp2/lib/nghttp2_hd.c
@@ -269,6 +269,11 @@
         return NGHTTP2_TOKEN_LOCATION;
       }
       break;
+    case 'y':
+      if (memeq("priorit", name, 7)) {
+        return NGHTTP2_TOKEN_PRIORITY;
+      }
+      break;
     }
     break;
   case 9:
@@ -1263,6 +1268,8 @@
     return NGHTTP2_ERR_INVALID_STATE;
   }
 
+  inflater->settings_hd_table_bufsize_max = settings_max_dynamic_table_size;
+
   /* It seems that encoder is not required to send dynamic table size
      update if the table size is not changed after applying
      SETTINGS_HEADER_TABLE_SIZE.  RFC 7541 is ambiguous here, but this
@@ -1275,13 +1282,12 @@
     /* Remember minimum value, and validate that encoder sends the
        value less than or equal to this. */
     inflater->min_hd_table_bufsize_max = settings_max_dynamic_table_size;
+
+    inflater->ctx.hd_table_bufsize_max = settings_max_dynamic_table_size;
+
+    hd_context_shrink_table_size(&inflater->ctx, NULL);
   }
 
-  inflater->settings_hd_table_bufsize_max = settings_max_dynamic_table_size;
-
-  inflater->ctx.hd_table_bufsize_max = settings_max_dynamic_table_size;
-
-  hd_context_shrink_table_size(&inflater->ctx, NULL);
   return 0;
 }
 
diff --git a/Utilities/cmnghttp2/lib/nghttp2_hd.h b/Utilities/cmnghttp2/lib/nghttp2_hd.h
index 2674028..6de0052 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_hd.h
+++ b/Utilities/cmnghttp2/lib/nghttp2_hd.h
@@ -112,6 +112,7 @@
   NGHTTP2_TOKEN_PROXY_CONNECTION,
   NGHTTP2_TOKEN_UPGRADE,
   NGHTTP2_TOKEN__PROTOCOL,
+  NGHTTP2_TOKEN_PRIORITY,
 } nghttp2_token;
 
 struct nghttp2_hd_entry;
diff --git a/Utilities/cmnghttp2/lib/nghttp2_helper.c b/Utilities/cmnghttp2/lib/nghttp2_helper.c
index 91136a6..93dd475 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_helper.c
+++ b/Utilities/cmnghttp2/lib/nghttp2_helper.c
@@ -334,6 +334,8 @@
   case NGHTTP2_ERR_FLOODED:
     return "Flooding was detected in this HTTP/2 session, and it must be "
            "closed";
+  case NGHTTP2_ERR_TOO_MANY_SETTINGS:
+    return "SETTINGS frame contained more than the maximum allowed entries";
   default:
     return "Unknown error code";
   }
@@ -505,7 +507,179 @@
   return 1;
 }
 
-/* Generated by genauthroitychartbl.py */
+int nghttp2_check_header_value_rfc9113(const uint8_t *value, size_t len) {
+  if (len == 0) {
+    return 1;
+  }
+
+  if (*value == ' ' || *value == '\t' || *(value + len - 1) == ' ' ||
+      *(value + len - 1) == '\t') {
+    return 0;
+  }
+
+  return nghttp2_check_header_value(value, len);
+}
+
+/* Generated by genmethodchartbl.py */
+static char VALID_METHOD_CHARS[] = {
+    0 /* NUL  */, 0 /* SOH  */, 0 /* STX  */, 0 /* ETX  */,
+    0 /* EOT  */, 0 /* ENQ  */, 0 /* ACK  */, 0 /* BEL  */,
+    0 /* BS   */, 0 /* HT   */, 0 /* LF   */, 0 /* VT   */,
+    0 /* FF   */, 0 /* CR   */, 0 /* SO   */, 0 /* SI   */,
+    0 /* DLE  */, 0 /* DC1  */, 0 /* DC2  */, 0 /* DC3  */,
+    0 /* DC4  */, 0 /* NAK  */, 0 /* SYN  */, 0 /* ETB  */,
+    0 /* CAN  */, 0 /* EM   */, 0 /* SUB  */, 0 /* ESC  */,
+    0 /* FS   */, 0 /* GS   */, 0 /* RS   */, 0 /* US   */,
+    0 /* SPC  */, 1 /* !    */, 0 /* "    */, 1 /* #    */,
+    1 /* $    */, 1 /* %    */, 1 /* &    */, 1 /* '    */,
+    0 /* (    */, 0 /* )    */, 1 /* *    */, 1 /* +    */,
+    0 /* ,    */, 1 /* -    */, 1 /* .    */, 0 /* /    */,
+    1 /* 0    */, 1 /* 1    */, 1 /* 2    */, 1 /* 3    */,
+    1 /* 4    */, 1 /* 5    */, 1 /* 6    */, 1 /* 7    */,
+    1 /* 8    */, 1 /* 9    */, 0 /* :    */, 0 /* ;    */,
+    0 /* <    */, 0 /* =    */, 0 /* >    */, 0 /* ?    */,
+    0 /* @    */, 1 /* A    */, 1 /* B    */, 1 /* C    */,
+    1 /* D    */, 1 /* E    */, 1 /* F    */, 1 /* G    */,
+    1 /* H    */, 1 /* I    */, 1 /* J    */, 1 /* K    */,
+    1 /* L    */, 1 /* M    */, 1 /* N    */, 1 /* O    */,
+    1 /* P    */, 1 /* Q    */, 1 /* R    */, 1 /* S    */,
+    1 /* T    */, 1 /* U    */, 1 /* V    */, 1 /* W    */,
+    1 /* X    */, 1 /* Y    */, 1 /* Z    */, 0 /* [    */,
+    0 /* \    */, 0 /* ]    */, 1 /* ^    */, 1 /* _    */,
+    1 /* `    */, 1 /* a    */, 1 /* b    */, 1 /* c    */,
+    1 /* d    */, 1 /* e    */, 1 /* f    */, 1 /* g    */,
+    1 /* h    */, 1 /* i    */, 1 /* j    */, 1 /* k    */,
+    1 /* l    */, 1 /* m    */, 1 /* n    */, 1 /* o    */,
+    1 /* p    */, 1 /* q    */, 1 /* r    */, 1 /* s    */,
+    1 /* t    */, 1 /* u    */, 1 /* v    */, 1 /* w    */,
+    1 /* x    */, 1 /* y    */, 1 /* z    */, 0 /* {    */,
+    1 /* |    */, 0 /* }    */, 1 /* ~    */, 0 /* DEL  */,
+    0 /* 0x80 */, 0 /* 0x81 */, 0 /* 0x82 */, 0 /* 0x83 */,
+    0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, 0 /* 0x87 */,
+    0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
+    0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */,
+    0 /* 0x90 */, 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */,
+    0 /* 0x94 */, 0 /* 0x95 */, 0 /* 0x96 */, 0 /* 0x97 */,
+    0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, 0 /* 0x9b */,
+    0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
+    0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */,
+    0 /* 0xa4 */, 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */,
+    0 /* 0xa8 */, 0 /* 0xa9 */, 0 /* 0xaa */, 0 /* 0xab */,
+    0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, 0 /* 0xaf */,
+    0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
+    0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */,
+    0 /* 0xb8 */, 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */,
+    0 /* 0xbc */, 0 /* 0xbd */, 0 /* 0xbe */, 0 /* 0xbf */,
+    0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, 0 /* 0xc3 */,
+    0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
+    0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */,
+    0 /* 0xcc */, 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */,
+    0 /* 0xd0 */, 0 /* 0xd1 */, 0 /* 0xd2 */, 0 /* 0xd3 */,
+    0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, 0 /* 0xd7 */,
+    0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
+    0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */,
+    0 /* 0xe0 */, 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */,
+    0 /* 0xe4 */, 0 /* 0xe5 */, 0 /* 0xe6 */, 0 /* 0xe7 */,
+    0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, 0 /* 0xeb */,
+    0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
+    0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */,
+    0 /* 0xf4 */, 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */,
+    0 /* 0xf8 */, 0 /* 0xf9 */, 0 /* 0xfa */, 0 /* 0xfb */,
+    0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, 0 /* 0xff */
+};
+
+int nghttp2_check_method(const uint8_t *value, size_t len) {
+  const uint8_t *last;
+  if (len == 0) {
+    return 0;
+  }
+  for (last = value + len; value != last; ++value) {
+    if (!VALID_METHOD_CHARS[*value]) {
+      return 0;
+    }
+  }
+  return 1;
+}
+
+/* Generated by genpathchartbl.py */
+static char VALID_PATH_CHARS[] = {
+    0 /* NUL  */, 0 /* SOH  */, 0 /* STX  */, 0 /* ETX  */,
+    0 /* EOT  */, 0 /* ENQ  */, 0 /* ACK  */, 0 /* BEL  */,
+    0 /* BS   */, 0 /* HT   */, 0 /* LF   */, 0 /* VT   */,
+    0 /* FF   */, 0 /* CR   */, 0 /* SO   */, 0 /* SI   */,
+    0 /* DLE  */, 0 /* DC1  */, 0 /* DC2  */, 0 /* DC3  */,
+    0 /* DC4  */, 0 /* NAK  */, 0 /* SYN  */, 0 /* ETB  */,
+    0 /* CAN  */, 0 /* EM   */, 0 /* SUB  */, 0 /* ESC  */,
+    0 /* FS   */, 0 /* GS   */, 0 /* RS   */, 0 /* US   */,
+    0 /* SPC  */, 1 /* !    */, 1 /* "    */, 1 /* #    */,
+    1 /* $    */, 1 /* %    */, 1 /* &    */, 1 /* '    */,
+    1 /* (    */, 1 /* )    */, 1 /* *    */, 1 /* +    */,
+    1 /* ,    */, 1 /* -    */, 1 /* .    */, 1 /* /    */,
+    1 /* 0    */, 1 /* 1    */, 1 /* 2    */, 1 /* 3    */,
+    1 /* 4    */, 1 /* 5    */, 1 /* 6    */, 1 /* 7    */,
+    1 /* 8    */, 1 /* 9    */, 1 /* :    */, 1 /* ;    */,
+    1 /* <    */, 1 /* =    */, 1 /* >    */, 1 /* ?    */,
+    1 /* @    */, 1 /* A    */, 1 /* B    */, 1 /* C    */,
+    1 /* D    */, 1 /* E    */, 1 /* F    */, 1 /* G    */,
+    1 /* H    */, 1 /* I    */, 1 /* J    */, 1 /* K    */,
+    1 /* L    */, 1 /* M    */, 1 /* N    */, 1 /* O    */,
+    1 /* P    */, 1 /* Q    */, 1 /* R    */, 1 /* S    */,
+    1 /* T    */, 1 /* U    */, 1 /* V    */, 1 /* W    */,
+    1 /* X    */, 1 /* Y    */, 1 /* Z    */, 1 /* [    */,
+    1 /* \    */, 1 /* ]    */, 1 /* ^    */, 1 /* _    */,
+    1 /* `    */, 1 /* a    */, 1 /* b    */, 1 /* c    */,
+    1 /* d    */, 1 /* e    */, 1 /* f    */, 1 /* g    */,
+    1 /* h    */, 1 /* i    */, 1 /* j    */, 1 /* k    */,
+    1 /* l    */, 1 /* m    */, 1 /* n    */, 1 /* o    */,
+    1 /* p    */, 1 /* q    */, 1 /* r    */, 1 /* s    */,
+    1 /* t    */, 1 /* u    */, 1 /* v    */, 1 /* w    */,
+    1 /* x    */, 1 /* y    */, 1 /* z    */, 1 /* {    */,
+    1 /* |    */, 1 /* }    */, 1 /* ~    */, 0 /* DEL  */,
+    1 /* 0x80 */, 1 /* 0x81 */, 1 /* 0x82 */, 1 /* 0x83 */,
+    1 /* 0x84 */, 1 /* 0x85 */, 1 /* 0x86 */, 1 /* 0x87 */,
+    1 /* 0x88 */, 1 /* 0x89 */, 1 /* 0x8a */, 1 /* 0x8b */,
+    1 /* 0x8c */, 1 /* 0x8d */, 1 /* 0x8e */, 1 /* 0x8f */,
+    1 /* 0x90 */, 1 /* 0x91 */, 1 /* 0x92 */, 1 /* 0x93 */,
+    1 /* 0x94 */, 1 /* 0x95 */, 1 /* 0x96 */, 1 /* 0x97 */,
+    1 /* 0x98 */, 1 /* 0x99 */, 1 /* 0x9a */, 1 /* 0x9b */,
+    1 /* 0x9c */, 1 /* 0x9d */, 1 /* 0x9e */, 1 /* 0x9f */,
+    1 /* 0xa0 */, 1 /* 0xa1 */, 1 /* 0xa2 */, 1 /* 0xa3 */,
+    1 /* 0xa4 */, 1 /* 0xa5 */, 1 /* 0xa6 */, 1 /* 0xa7 */,
+    1 /* 0xa8 */, 1 /* 0xa9 */, 1 /* 0xaa */, 1 /* 0xab */,
+    1 /* 0xac */, 1 /* 0xad */, 1 /* 0xae */, 1 /* 0xaf */,
+    1 /* 0xb0 */, 1 /* 0xb1 */, 1 /* 0xb2 */, 1 /* 0xb3 */,
+    1 /* 0xb4 */, 1 /* 0xb5 */, 1 /* 0xb6 */, 1 /* 0xb7 */,
+    1 /* 0xb8 */, 1 /* 0xb9 */, 1 /* 0xba */, 1 /* 0xbb */,
+    1 /* 0xbc */, 1 /* 0xbd */, 1 /* 0xbe */, 1 /* 0xbf */,
+    1 /* 0xc0 */, 1 /* 0xc1 */, 1 /* 0xc2 */, 1 /* 0xc3 */,
+    1 /* 0xc4 */, 1 /* 0xc5 */, 1 /* 0xc6 */, 1 /* 0xc7 */,
+    1 /* 0xc8 */, 1 /* 0xc9 */, 1 /* 0xca */, 1 /* 0xcb */,
+    1 /* 0xcc */, 1 /* 0xcd */, 1 /* 0xce */, 1 /* 0xcf */,
+    1 /* 0xd0 */, 1 /* 0xd1 */, 1 /* 0xd2 */, 1 /* 0xd3 */,
+    1 /* 0xd4 */, 1 /* 0xd5 */, 1 /* 0xd6 */, 1 /* 0xd7 */,
+    1 /* 0xd8 */, 1 /* 0xd9 */, 1 /* 0xda */, 1 /* 0xdb */,
+    1 /* 0xdc */, 1 /* 0xdd */, 1 /* 0xde */, 1 /* 0xdf */,
+    1 /* 0xe0 */, 1 /* 0xe1 */, 1 /* 0xe2 */, 1 /* 0xe3 */,
+    1 /* 0xe4 */, 1 /* 0xe5 */, 1 /* 0xe6 */, 1 /* 0xe7 */,
+    1 /* 0xe8 */, 1 /* 0xe9 */, 1 /* 0xea */, 1 /* 0xeb */,
+    1 /* 0xec */, 1 /* 0xed */, 1 /* 0xee */, 1 /* 0xef */,
+    1 /* 0xf0 */, 1 /* 0xf1 */, 1 /* 0xf2 */, 1 /* 0xf3 */,
+    1 /* 0xf4 */, 1 /* 0xf5 */, 1 /* 0xf6 */, 1 /* 0xf7 */,
+    1 /* 0xf8 */, 1 /* 0xf9 */, 1 /* 0xfa */, 1 /* 0xfb */,
+    1 /* 0xfc */, 1 /* 0xfd */, 1 /* 0xfe */, 1 /* 0xff */
+};
+
+int nghttp2_check_path(const uint8_t *value, size_t len) {
+  const uint8_t *last;
+  for (last = value + len; value != last; ++value) {
+    if (!VALID_PATH_CHARS[*value]) {
+      return 0;
+    }
+  }
+  return 1;
+}
+
+/* Generated by genauthoritychartbl.py */
 static char VALID_AUTHORITY_CHARS[] = {
     0 /* NUL  */, 0 /* SOH  */, 0 /* STX  */, 0 /* ETX  */,
     0 /* EOT  */, 0 /* ENQ  */, 0 /* ACK  */, 0 /* BEL  */,
diff --git a/Utilities/cmnghttp2/lib/nghttp2_http.c b/Utilities/cmnghttp2/lib/nghttp2_http.c
index 62f57b6..83e5e66 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_http.c
+++ b/Utilities/cmnghttp2/lib/nghttp2_http.c
@@ -30,6 +30,7 @@
 
 #include "nghttp2_hd.h"
 #include "nghttp2_helper.h"
+#include "nghttp2_extpri.h"
 
 static uint8_t downcase(uint8_t c) {
   return 'A' <= c && c <= 'Z' ? (uint8_t)(c - 'A' + 'a') : c;
@@ -72,25 +73,12 @@
   return n;
 }
 
-static int lws(const uint8_t *s, size_t n) {
-  size_t i;
-  for (i = 0; i < n; ++i) {
-    if (s[i] != ' ' && s[i] != '\t') {
-      return 0;
-    }
-  }
-  return 1;
-}
-
 static int check_pseudo_header(nghttp2_stream *stream, const nghttp2_hd_nv *nv,
-                               int flag) {
-  if (stream->http_flags & flag) {
+                               uint32_t flag) {
+  if ((stream->http_flags & flag) || nv->value->len == 0) {
     return 0;
   }
-  if (lws(nv->value->base, nv->value->len)) {
-    return 0;
-  }
-  stream->http_flags = (uint16_t)(stream->http_flags | flag);
+  stream->http_flags = stream->http_flags | flag;
   return 1;
 }
 
@@ -114,6 +102,8 @@
 
 static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
                                   int trailer, int connect_protocol) {
+  nghttp2_extpri extpri;
+
   if (nv->name->base[0] == ':') {
     if (trailer ||
         (stream->http_flags & NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) {
@@ -212,6 +202,23 @@
       return NGHTTP2_ERR_HTTP_HEADER;
     }
     break;
+  case NGHTTP2_TOKEN_PRIORITY:
+    if (!trailer &&
+        /* Do not parse the header field in PUSH_PROMISE. */
+        (stream->stream_id & 1) &&
+        (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) &&
+        !(stream->http_flags & NGHTTP2_HTTP_FLAG_BAD_PRIORITY)) {
+      nghttp2_extpri_from_uint8(&extpri, stream->http_extpri);
+      if (nghttp2_http_parse_priority(&extpri, nv->value->base,
+                                      nv->value->len) == 0) {
+        stream->http_extpri = nghttp2_extpri_to_uint8(&extpri);
+        stream->http_flags |= NGHTTP2_HTTP_FLAG_PRIORITY;
+      } else {
+        stream->http_flags &= (uint32_t)~NGHTTP2_HTTP_FLAG_PRIORITY;
+        stream->http_flags |= NGHTTP2_HTTP_FLAG_BAD_PRIORITY;
+      }
+    }
+    break;
   default:
     if (nv->name->base[0] == ':') {
       return NGHTTP2_ERR_HTTP_HEADER;
@@ -329,6 +336,16 @@
   return 1;
 }
 
+static int lws(const uint8_t *s, size_t n) {
+  size_t i;
+  for (i = 0; i < n; ++i) {
+    if (s[i] != ' ' && s[i] != '\t') {
+      return 0;
+    }
+  }
+  return 1;
+}
+
 int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
                            nghttp2_frame *frame, nghttp2_hd_nv *nv,
                            int trailer) {
@@ -360,13 +377,46 @@
     return NGHTTP2_ERR_IGN_HTTP_HEADER;
   }
 
-  if (nv->token == NGHTTP2_TOKEN__AUTHORITY ||
-      nv->token == NGHTTP2_TOKEN_HOST) {
-    rv = nghttp2_check_authority(nv->value->base, nv->value->len);
-  } else if (nv->token == NGHTTP2_TOKEN__SCHEME) {
+  switch (nv->token) {
+  case NGHTTP2_TOKEN__METHOD:
+    rv = nghttp2_check_method(nv->value->base, nv->value->len);
+    break;
+  case NGHTTP2_TOKEN__PATH:
+    rv = nghttp2_check_path(nv->value->base, nv->value->len);
+    break;
+  case NGHTTP2_TOKEN__AUTHORITY:
+  case NGHTTP2_TOKEN_HOST:
+    if (session->server || frame->hd.type == NGHTTP2_PUSH_PROMISE) {
+      rv = nghttp2_check_authority(nv->value->base, nv->value->len);
+    } else if (
+        stream->flags &
+        NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) {
+      rv = nghttp2_check_header_value(nv->value->base, nv->value->len);
+    } else {
+      rv = nghttp2_check_header_value_rfc9113(nv->value->base, nv->value->len);
+    }
+    break;
+  case NGHTTP2_TOKEN__SCHEME:
     rv = check_scheme(nv->value->base, nv->value->len);
-  } else {
-    rv = nghttp2_check_header_value(nv->value->base, nv->value->len);
+    break;
+  case NGHTTP2_TOKEN__PROTOCOL:
+    /* Check the value consists of just white spaces, which was done
+       in check_pseudo_header before
+       nghttp2_check_header_value_rfc9113 has been introduced. */
+    if ((stream->flags &
+         NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) &&
+        lws(nv->value->base, nv->value->len)) {
+      rv = 0;
+      break;
+    }
+    /* fall through */
+  default:
+    if (stream->flags &
+        NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) {
+      rv = nghttp2_check_header_value(nv->value->base, nv->value->len);
+    } else {
+      rv = nghttp2_check_header_value_rfc9113(nv->value->base, nv->value->len);
+    }
   }
 
   if (rv == 0) {
@@ -434,16 +484,15 @@
 
   if (stream->status_code / 100 == 1) {
     /* non-final response */
-    stream->http_flags =
-        (uint16_t)((stream->http_flags & NGHTTP2_HTTP_FLAG_METH_ALL) |
-                   NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE);
+    stream->http_flags = (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_ALL) |
+                         NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE;
     stream->content_length = -1;
     stream->status_code = -1;
     return 0;
   }
 
   stream->http_flags =
-      (uint16_t)(stream->http_flags & ~NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE);
+      stream->http_flags & (uint32_t)~NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE;
 
   if (!expect_response_body(stream)) {
     stream->content_length = 0;
@@ -528,3 +577,715 @@
     return;
   }
 }
+
+/* Generated by genchartbl.py */
+static const int SF_KEY_CHARS[] = {
+    0 /* NUL  */, 0 /* SOH  */, 0 /* STX  */, 0 /* ETX  */, 0 /* EOT  */,
+    0 /* ENQ  */, 0 /* ACK  */, 0 /* BEL  */, 0 /* BS   */, 0 /* HT   */,
+    0 /* LF   */, 0 /* VT   */, 0 /* FF   */, 0 /* CR   */, 0 /* SO   */,
+    0 /* SI   */, 0 /* DLE  */, 0 /* DC1  */, 0 /* DC2  */, 0 /* DC3  */,
+    0 /* DC4  */, 0 /* NAK  */, 0 /* SYN  */, 0 /* ETB  */, 0 /* CAN  */,
+    0 /* EM   */, 0 /* SUB  */, 0 /* ESC  */, 0 /* FS   */, 0 /* GS   */,
+    0 /* RS   */, 0 /* US   */, 0 /* SPC  */, 0 /* !    */, 0 /* "    */,
+    0 /* #    */, 0 /* $    */, 0 /* %    */, 0 /* &    */, 0 /* '    */,
+    0 /* (    */, 0 /* )    */, 1 /* *    */, 0 /* +    */, 0 /* ,    */,
+    1 /* -    */, 1 /* .    */, 0 /* /    */, 1 /* 0    */, 1 /* 1    */,
+    1 /* 2    */, 1 /* 3    */, 1 /* 4    */, 1 /* 5    */, 1 /* 6    */,
+    1 /* 7    */, 1 /* 8    */, 1 /* 9    */, 0 /* :    */, 0 /* ;    */,
+    0 /* <    */, 0 /* =    */, 0 /* >    */, 0 /* ?    */, 0 /* @    */,
+    0 /* A    */, 0 /* B    */, 0 /* C    */, 0 /* D    */, 0 /* E    */,
+    0 /* F    */, 0 /* G    */, 0 /* H    */, 0 /* I    */, 0 /* J    */,
+    0 /* K    */, 0 /* L    */, 0 /* M    */, 0 /* N    */, 0 /* O    */,
+    0 /* P    */, 0 /* Q    */, 0 /* R    */, 0 /* S    */, 0 /* T    */,
+    0 /* U    */, 0 /* V    */, 0 /* W    */, 0 /* X    */, 0 /* Y    */,
+    0 /* Z    */, 0 /* [    */, 0 /* \    */, 0 /* ]    */, 0 /* ^    */,
+    1 /* _    */, 0 /* `    */, 1 /* a    */, 1 /* b    */, 1 /* c    */,
+    1 /* d    */, 1 /* e    */, 1 /* f    */, 1 /* g    */, 1 /* h    */,
+    1 /* i    */, 1 /* j    */, 1 /* k    */, 1 /* l    */, 1 /* m    */,
+    1 /* n    */, 1 /* o    */, 1 /* p    */, 1 /* q    */, 1 /* r    */,
+    1 /* s    */, 1 /* t    */, 1 /* u    */, 1 /* v    */, 1 /* w    */,
+    1 /* x    */, 1 /* y    */, 1 /* z    */, 0 /* {    */, 0 /* |    */,
+    0 /* }    */, 0 /* ~    */, 0 /* DEL  */, 0 /* 0x80 */, 0 /* 0x81 */,
+    0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */,
+    0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
+    0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */,
+    0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */,
+    0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */,
+    0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
+    0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */,
+    0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */,
+    0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */,
+    0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
+    0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */,
+    0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */,
+    0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */,
+    0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
+    0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */,
+    0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */,
+    0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */,
+    0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
+    0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */,
+    0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */,
+    0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */,
+    0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
+    0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */,
+    0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */,
+    0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */,
+    0 /* 0xff */,
+};
+
+static ssize_t sf_parse_key(const uint8_t *begin, const uint8_t *end) {
+  const uint8_t *p = begin;
+
+  if ((*p < 'a' || 'z' < *p) && *p != '*') {
+    return -1;
+  }
+
+  for (; p != end && SF_KEY_CHARS[*p]; ++p)
+    ;
+
+  return p - begin;
+}
+
+static ssize_t sf_parse_integer_or_decimal(nghttp2_sf_value *dest,
+                                           const uint8_t *begin,
+                                           const uint8_t *end) {
+  const uint8_t *p = begin;
+  int sign = 1;
+  int64_t value = 0;
+  int type = NGHTTP2_SF_VALUE_TYPE_INTEGER;
+  size_t len = 0;
+  size_t fpos = 0;
+  size_t i;
+
+  if (*p == '-') {
+    if (++p == end) {
+      return -1;
+    }
+
+    sign = -1;
+  }
+
+  if (*p < '0' || '9' < *p) {
+    return -1;
+  }
+
+  for (; p != end; ++p) {
+    switch (*p) {
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+    case '8':
+    case '9':
+      value *= 10;
+      value += *p - '0';
+
+      if (++len > 15) {
+        return -1;
+      }
+
+      break;
+    case '.':
+      if (type != NGHTTP2_SF_VALUE_TYPE_INTEGER) {
+        goto fin;
+      }
+
+      if (len > 12) {
+        return -1;
+      }
+      fpos = len;
+      type = NGHTTP2_SF_VALUE_TYPE_DECIMAL;
+
+      break;
+    default:
+      goto fin;
+    };
+  }
+
+fin:
+  switch (type) {
+  case NGHTTP2_SF_VALUE_TYPE_INTEGER:
+    if (dest) {
+      dest->type = (uint8_t)type;
+      dest->i = value * sign;
+    }
+
+    return p - begin;
+  case NGHTTP2_SF_VALUE_TYPE_DECIMAL:
+    if (fpos == len || len - fpos > 3) {
+      return -1;
+    }
+
+    if (dest) {
+      dest->type = (uint8_t)type;
+      dest->d = (double)value;
+      for (i = len - fpos; i > 0; --i) {
+        dest->d /= (double)10;
+      }
+      dest->d *= sign;
+    }
+
+    return p - begin;
+  default:
+    assert(0);
+    abort();
+  }
+}
+
+/* Generated by genchartbl.py */
+static const int SF_DQUOTE_CHARS[] = {
+    0 /* NUL  */, 0 /* SOH  */, 0 /* STX  */, 0 /* ETX  */, 0 /* EOT  */,
+    0 /* ENQ  */, 0 /* ACK  */, 0 /* BEL  */, 0 /* BS   */, 0 /* HT   */,
+    0 /* LF   */, 0 /* VT   */, 0 /* FF   */, 0 /* CR   */, 0 /* SO   */,
+    0 /* SI   */, 0 /* DLE  */, 0 /* DC1  */, 0 /* DC2  */, 0 /* DC3  */,
+    0 /* DC4  */, 0 /* NAK  */, 0 /* SYN  */, 0 /* ETB  */, 0 /* CAN  */,
+    0 /* EM   */, 0 /* SUB  */, 0 /* ESC  */, 0 /* FS   */, 0 /* GS   */,
+    0 /* RS   */, 0 /* US   */, 1 /* SPC  */, 1 /* !    */, 0 /* "    */,
+    1 /* #    */, 1 /* $    */, 1 /* %    */, 1 /* &    */, 1 /* '    */,
+    1 /* (    */, 1 /* )    */, 1 /* *    */, 1 /* +    */, 1 /* ,    */,
+    1 /* -    */, 1 /* .    */, 1 /* /    */, 1 /* 0    */, 1 /* 1    */,
+    1 /* 2    */, 1 /* 3    */, 1 /* 4    */, 1 /* 5    */, 1 /* 6    */,
+    1 /* 7    */, 1 /* 8    */, 1 /* 9    */, 1 /* :    */, 1 /* ;    */,
+    1 /* <    */, 1 /* =    */, 1 /* >    */, 1 /* ?    */, 1 /* @    */,
+    1 /* A    */, 1 /* B    */, 1 /* C    */, 1 /* D    */, 1 /* E    */,
+    1 /* F    */, 1 /* G    */, 1 /* H    */, 1 /* I    */, 1 /* J    */,
+    1 /* K    */, 1 /* L    */, 1 /* M    */, 1 /* N    */, 1 /* O    */,
+    1 /* P    */, 1 /* Q    */, 1 /* R    */, 1 /* S    */, 1 /* T    */,
+    1 /* U    */, 1 /* V    */, 1 /* W    */, 1 /* X    */, 1 /* Y    */,
+    1 /* Z    */, 1 /* [    */, 0 /* \    */, 1 /* ]    */, 1 /* ^    */,
+    1 /* _    */, 1 /* `    */, 1 /* a    */, 1 /* b    */, 1 /* c    */,
+    1 /* d    */, 1 /* e    */, 1 /* f    */, 1 /* g    */, 1 /* h    */,
+    1 /* i    */, 1 /* j    */, 1 /* k    */, 1 /* l    */, 1 /* m    */,
+    1 /* n    */, 1 /* o    */, 1 /* p    */, 1 /* q    */, 1 /* r    */,
+    1 /* s    */, 1 /* t    */, 1 /* u    */, 1 /* v    */, 1 /* w    */,
+    1 /* x    */, 1 /* y    */, 1 /* z    */, 1 /* {    */, 1 /* |    */,
+    1 /* }    */, 1 /* ~    */, 0 /* DEL  */, 0 /* 0x80 */, 0 /* 0x81 */,
+    0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */,
+    0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
+    0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */,
+    0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */,
+    0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */,
+    0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
+    0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */,
+    0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */,
+    0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */,
+    0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
+    0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */,
+    0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */,
+    0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */,
+    0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
+    0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */,
+    0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */,
+    0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */,
+    0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
+    0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */,
+    0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */,
+    0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */,
+    0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
+    0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */,
+    0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */,
+    0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */,
+    0 /* 0xff */,
+};
+
+static ssize_t sf_parse_string(nghttp2_sf_value *dest, const uint8_t *begin,
+                               const uint8_t *end) {
+  const uint8_t *p = begin;
+
+  if (*p++ != '"') {
+    return -1;
+  }
+
+  for (; p != end; ++p) {
+    switch (*p) {
+    case '\\':
+      if (++p == end) {
+        return -1;
+      }
+
+      switch (*p) {
+      case '"':
+      case '\\':
+        break;
+      default:
+        return -1;
+      }
+
+      break;
+    case '"':
+      if (dest) {
+        dest->type = NGHTTP2_SF_VALUE_TYPE_STRING;
+        dest->s.base = begin + 1;
+        dest->s.len = (size_t)(p - dest->s.base);
+      }
+
+      ++p;
+
+      return p - begin;
+    default:
+      if (!SF_DQUOTE_CHARS[*p]) {
+        return -1;
+      }
+    }
+  }
+
+  return -1;
+}
+
+/* Generated by genchartbl.py */
+static const int SF_TOKEN_CHARS[] = {
+    0 /* NUL  */, 0 /* SOH  */, 0 /* STX  */, 0 /* ETX  */, 0 /* EOT  */,
+    0 /* ENQ  */, 0 /* ACK  */, 0 /* BEL  */, 0 /* BS   */, 0 /* HT   */,
+    0 /* LF   */, 0 /* VT   */, 0 /* FF   */, 0 /* CR   */, 0 /* SO   */,
+    0 /* SI   */, 0 /* DLE  */, 0 /* DC1  */, 0 /* DC2  */, 0 /* DC3  */,
+    0 /* DC4  */, 0 /* NAK  */, 0 /* SYN  */, 0 /* ETB  */, 0 /* CAN  */,
+    0 /* EM   */, 0 /* SUB  */, 0 /* ESC  */, 0 /* FS   */, 0 /* GS   */,
+    0 /* RS   */, 0 /* US   */, 0 /* SPC  */, 1 /* !    */, 0 /* "    */,
+    1 /* #    */, 1 /* $    */, 1 /* %    */, 1 /* &    */, 1 /* '    */,
+    0 /* (    */, 0 /* )    */, 1 /* *    */, 1 /* +    */, 0 /* ,    */,
+    1 /* -    */, 1 /* .    */, 1 /* /    */, 1 /* 0    */, 1 /* 1    */,
+    1 /* 2    */, 1 /* 3    */, 1 /* 4    */, 1 /* 5    */, 1 /* 6    */,
+    1 /* 7    */, 1 /* 8    */, 1 /* 9    */, 1 /* :    */, 0 /* ;    */,
+    0 /* <    */, 0 /* =    */, 0 /* >    */, 0 /* ?    */, 0 /* @    */,
+    1 /* A    */, 1 /* B    */, 1 /* C    */, 1 /* D    */, 1 /* E    */,
+    1 /* F    */, 1 /* G    */, 1 /* H    */, 1 /* I    */, 1 /* J    */,
+    1 /* K    */, 1 /* L    */, 1 /* M    */, 1 /* N    */, 1 /* O    */,
+    1 /* P    */, 1 /* Q    */, 1 /* R    */, 1 /* S    */, 1 /* T    */,
+    1 /* U    */, 1 /* V    */, 1 /* W    */, 1 /* X    */, 1 /* Y    */,
+    1 /* Z    */, 0 /* [    */, 0 /* \    */, 0 /* ]    */, 1 /* ^    */,
+    1 /* _    */, 1 /* `    */, 1 /* a    */, 1 /* b    */, 1 /* c    */,
+    1 /* d    */, 1 /* e    */, 1 /* f    */, 1 /* g    */, 1 /* h    */,
+    1 /* i    */, 1 /* j    */, 1 /* k    */, 1 /* l    */, 1 /* m    */,
+    1 /* n    */, 1 /* o    */, 1 /* p    */, 1 /* q    */, 1 /* r    */,
+    1 /* s    */, 1 /* t    */, 1 /* u    */, 1 /* v    */, 1 /* w    */,
+    1 /* x    */, 1 /* y    */, 1 /* z    */, 0 /* {    */, 1 /* |    */,
+    0 /* }    */, 1 /* ~    */, 0 /* DEL  */, 0 /* 0x80 */, 0 /* 0x81 */,
+    0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */,
+    0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
+    0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */,
+    0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */,
+    0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */,
+    0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
+    0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */,
+    0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */,
+    0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */,
+    0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
+    0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */,
+    0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */,
+    0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */,
+    0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
+    0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */,
+    0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */,
+    0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */,
+    0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
+    0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */,
+    0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */,
+    0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */,
+    0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
+    0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */,
+    0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */,
+    0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */,
+    0 /* 0xff */,
+};
+
+static ssize_t sf_parse_token(nghttp2_sf_value *dest, const uint8_t *begin,
+                              const uint8_t *end) {
+  const uint8_t *p = begin;
+
+  if ((*p < 'A' || 'Z' < *p) && (*p < 'a' || 'z' < *p) && *p != '*') {
+    return -1;
+  }
+
+  for (; p != end && SF_TOKEN_CHARS[*p]; ++p)
+    ;
+
+  if (dest) {
+    dest->type = NGHTTP2_SF_VALUE_TYPE_TOKEN;
+    dest->s.base = begin;
+    dest->s.len = (size_t)(p - begin);
+  }
+
+  return p - begin;
+}
+
+/* Generated by genchartbl.py */
+static const int SF_BYTESEQ_CHARS[] = {
+    0 /* NUL  */, 0 /* SOH  */, 0 /* STX  */, 0 /* ETX  */, 0 /* EOT  */,
+    0 /* ENQ  */, 0 /* ACK  */, 0 /* BEL  */, 0 /* BS   */, 0 /* HT   */,
+    0 /* LF   */, 0 /* VT   */, 0 /* FF   */, 0 /* CR   */, 0 /* SO   */,
+    0 /* SI   */, 0 /* DLE  */, 0 /* DC1  */, 0 /* DC2  */, 0 /* DC3  */,
+    0 /* DC4  */, 0 /* NAK  */, 0 /* SYN  */, 0 /* ETB  */, 0 /* CAN  */,
+    0 /* EM   */, 0 /* SUB  */, 0 /* ESC  */, 0 /* FS   */, 0 /* GS   */,
+    0 /* RS   */, 0 /* US   */, 0 /* SPC  */, 0 /* !    */, 0 /* "    */,
+    0 /* #    */, 0 /* $    */, 0 /* %    */, 0 /* &    */, 0 /* '    */,
+    0 /* (    */, 0 /* )    */, 0 /* *    */, 1 /* +    */, 0 /* ,    */,
+    0 /* -    */, 0 /* .    */, 1 /* /    */, 1 /* 0    */, 1 /* 1    */,
+    1 /* 2    */, 1 /* 3    */, 1 /* 4    */, 1 /* 5    */, 1 /* 6    */,
+    1 /* 7    */, 1 /* 8    */, 1 /* 9    */, 0 /* :    */, 0 /* ;    */,
+    0 /* <    */, 1 /* =    */, 0 /* >    */, 0 /* ?    */, 0 /* @    */,
+    1 /* A    */, 1 /* B    */, 1 /* C    */, 1 /* D    */, 1 /* E    */,
+    1 /* F    */, 1 /* G    */, 1 /* H    */, 1 /* I    */, 1 /* J    */,
+    1 /* K    */, 1 /* L    */, 1 /* M    */, 1 /* N    */, 1 /* O    */,
+    1 /* P    */, 1 /* Q    */, 1 /* R    */, 1 /* S    */, 1 /* T    */,
+    1 /* U    */, 1 /* V    */, 1 /* W    */, 1 /* X    */, 1 /* Y    */,
+    1 /* Z    */, 0 /* [    */, 0 /* \    */, 0 /* ]    */, 0 /* ^    */,
+    0 /* _    */, 0 /* `    */, 1 /* a    */, 1 /* b    */, 1 /* c    */,
+    1 /* d    */, 1 /* e    */, 1 /* f    */, 1 /* g    */, 1 /* h    */,
+    1 /* i    */, 1 /* j    */, 1 /* k    */, 1 /* l    */, 1 /* m    */,
+    1 /* n    */, 1 /* o    */, 1 /* p    */, 1 /* q    */, 1 /* r    */,
+    1 /* s    */, 1 /* t    */, 1 /* u    */, 1 /* v    */, 1 /* w    */,
+    1 /* x    */, 1 /* y    */, 1 /* z    */, 0 /* {    */, 0 /* |    */,
+    0 /* }    */, 0 /* ~    */, 0 /* DEL  */, 0 /* 0x80 */, 0 /* 0x81 */,
+    0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */,
+    0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
+    0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */,
+    0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */,
+    0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */,
+    0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
+    0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */,
+    0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */,
+    0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */,
+    0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
+    0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */,
+    0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */,
+    0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */,
+    0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
+    0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */,
+    0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */,
+    0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */,
+    0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
+    0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */,
+    0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */,
+    0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */,
+    0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
+    0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */,
+    0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */,
+    0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */,
+    0 /* 0xff */,
+};
+
+static ssize_t sf_parse_byteseq(nghttp2_sf_value *dest, const uint8_t *begin,
+                                const uint8_t *end) {
+  const uint8_t *p = begin;
+
+  if (*p++ != ':') {
+    return -1;
+  }
+
+  for (; p != end; ++p) {
+    switch (*p) {
+    case ':':
+      if (dest) {
+        dest->type = NGHTTP2_SF_VALUE_TYPE_BYTESEQ;
+        dest->s.base = begin + 1;
+        dest->s.len = (size_t)(p - dest->s.base);
+      }
+
+      ++p;
+
+      return p - begin;
+    default:
+      if (!SF_BYTESEQ_CHARS[*p]) {
+        return -1;
+      }
+    }
+  }
+
+  return -1;
+}
+
+static ssize_t sf_parse_boolean(nghttp2_sf_value *dest, const uint8_t *begin,
+                                const uint8_t *end) {
+  const uint8_t *p = begin;
+  int b;
+
+  if (*p++ != '?') {
+    return -1;
+  }
+
+  if (p == end) {
+    return -1;
+  }
+
+  switch (*p++) {
+  case '0':
+    b = 0;
+    break;
+  case '1':
+    b = 1;
+    break;
+  default:
+    return -1;
+  }
+
+  if (dest) {
+    dest->type = NGHTTP2_SF_VALUE_TYPE_BOOLEAN;
+    dest->b = b;
+  }
+
+  return p - begin;
+}
+
+static ssize_t sf_parse_bare_item(nghttp2_sf_value *dest, const uint8_t *begin,
+                                  const uint8_t *end) {
+  switch (*begin) {
+  case '-':
+  case '0':
+  case '1':
+  case '2':
+  case '3':
+  case '4':
+  case '5':
+  case '6':
+  case '7':
+  case '8':
+  case '9':
+    return sf_parse_integer_or_decimal(dest, begin, end);
+  case '"':
+    return sf_parse_string(dest, begin, end);
+  case '*':
+    return sf_parse_token(dest, begin, end);
+  case ':':
+    return sf_parse_byteseq(dest, begin, end);
+  case '?':
+    return sf_parse_boolean(dest, begin, end);
+  default:
+    if (('A' <= *begin && *begin <= 'Z') || ('a' <= *begin && *begin <= 'z')) {
+      return sf_parse_token(dest, begin, end);
+    }
+    return -1;
+  }
+}
+
+#define sf_discard_sp_end_err(BEGIN, END, ERR)                                 \
+  for (;; ++(BEGIN)) {                                                         \
+    if ((BEGIN) == (END)) {                                                    \
+      return (ERR);                                                            \
+    }                                                                          \
+    if (*(BEGIN) != ' ') {                                                     \
+      break;                                                                   \
+    }                                                                          \
+  }
+
+static ssize_t sf_parse_params(const uint8_t *begin, const uint8_t *end) {
+  const uint8_t *p = begin;
+  ssize_t slen;
+
+  for (; p != end && *p == ';';) {
+    ++p;
+
+    sf_discard_sp_end_err(p, end, -1);
+
+    slen = sf_parse_key(p, end);
+    if (slen < 0) {
+      return -1;
+    }
+
+    p += slen;
+
+    if (p == end || *p != '=') {
+      /* Boolean true */
+    } else if (++p == end) {
+      return -1;
+    } else {
+      slen = sf_parse_bare_item(NULL, p, end);
+      if (slen < 0) {
+        return -1;
+      }
+
+      p += slen;
+    }
+  }
+
+  return p - begin;
+}
+
+static ssize_t sf_parse_item(nghttp2_sf_value *dest, const uint8_t *begin,
+                             const uint8_t *end) {
+  const uint8_t *p = begin;
+  ssize_t slen;
+
+  slen = sf_parse_bare_item(dest, p, end);
+  if (slen < 0) {
+    return -1;
+  }
+
+  p += slen;
+
+  slen = sf_parse_params(p, end);
+  if (slen < 0) {
+    return -1;
+  }
+
+  p += slen;
+
+  return p - begin;
+}
+
+ssize_t nghttp2_sf_parse_item(nghttp2_sf_value *dest, const uint8_t *begin,
+                              const uint8_t *end) {
+  return sf_parse_item(dest, begin, end);
+}
+
+static ssize_t sf_parse_inner_list(nghttp2_sf_value *dest, const uint8_t *begin,
+                                   const uint8_t *end) {
+  const uint8_t *p = begin;
+  ssize_t slen;
+
+  if (*p++ != '(') {
+    return -1;
+  }
+
+  for (;;) {
+    sf_discard_sp_end_err(p, end, -1);
+
+    if (*p == ')') {
+      ++p;
+
+      slen = sf_parse_params(p, end);
+      if (slen < 0) {
+        return -1;
+      }
+
+      p += slen;
+
+      if (dest) {
+        dest->type = NGHTTP2_SF_VALUE_TYPE_INNER_LIST;
+      }
+
+      return p - begin;
+    }
+
+    slen = sf_parse_item(NULL, p, end);
+    if (slen < 0) {
+      return -1;
+    }
+
+    p += slen;
+
+    if (p == end || (*p != ' ' && *p != ')')) {
+      return -1;
+    }
+  }
+}
+
+ssize_t nghttp2_sf_parse_inner_list(nghttp2_sf_value *dest,
+                                    const uint8_t *begin, const uint8_t *end) {
+  return sf_parse_inner_list(dest, begin, end);
+}
+
+static ssize_t sf_parse_item_or_inner_list(nghttp2_sf_value *dest,
+                                           const uint8_t *begin,
+                                           const uint8_t *end) {
+  if (*begin == '(') {
+    return sf_parse_inner_list(dest, begin, end);
+  }
+
+  return sf_parse_item(dest, begin, end);
+}
+
+#define sf_discard_ows(BEGIN, END)                                             \
+  for (;; ++(BEGIN)) {                                                         \
+    if ((BEGIN) == (END)) {                                                    \
+      goto fin;                                                                \
+    }                                                                          \
+    if (*(BEGIN) != ' ' && *(BEGIN) != '\t') {                                 \
+      break;                                                                   \
+    }                                                                          \
+  }
+
+#define sf_discard_ows_end_err(BEGIN, END, ERR)                                \
+  for (;; ++(BEGIN)) {                                                         \
+    if ((BEGIN) == (END)) {                                                    \
+      return (ERR);                                                            \
+    }                                                                          \
+    if (*(BEGIN) != ' ' && *(BEGIN) != '\t') {                                 \
+      break;                                                                   \
+    }                                                                          \
+  }
+
+int nghttp2_http_parse_priority(nghttp2_extpri *dest, const uint8_t *value,
+                                size_t valuelen) {
+  const uint8_t *p = value, *end = value + valuelen;
+  ssize_t slen;
+  nghttp2_sf_value val;
+  nghttp2_extpri pri = *dest;
+  const uint8_t *key;
+  size_t keylen;
+
+  for (; p != end && *p == ' '; ++p)
+    ;
+
+  for (; p != end;) {
+    slen = sf_parse_key(p, end);
+    if (slen < 0) {
+      return NGHTTP2_ERR_INVALID_ARGUMENT;
+    }
+
+    key = p;
+    keylen = (size_t)slen;
+
+    p += slen;
+
+    if (p == end || *p != '=') {
+      /* Boolean true */
+      val.type = NGHTTP2_SF_VALUE_TYPE_BOOLEAN;
+      val.b = 1;
+
+      slen = sf_parse_params(p, end);
+      if (slen < 0) {
+        return NGHTTP2_ERR_INVALID_ARGUMENT;
+      }
+    } else if (++p == end) {
+      return NGHTTP2_ERR_INVALID_ARGUMENT;
+    } else {
+      slen = sf_parse_item_or_inner_list(&val, p, end);
+      if (slen < 0) {
+        return NGHTTP2_ERR_INVALID_ARGUMENT;
+      }
+    }
+
+    p += slen;
+
+    if (keylen == 1) {
+      switch (key[0]) {
+      case 'i':
+        if (val.type != NGHTTP2_SF_VALUE_TYPE_BOOLEAN) {
+          return NGHTTP2_ERR_INVALID_ARGUMENT;
+        }
+
+        pri.inc = val.b;
+
+        break;
+      case 'u':
+        if (val.type != NGHTTP2_SF_VALUE_TYPE_INTEGER ||
+            val.i < NGHTTP2_EXTPRI_URGENCY_HIGH ||
+            NGHTTP2_EXTPRI_URGENCY_LOW < val.i) {
+          return NGHTTP2_ERR_INVALID_ARGUMENT;
+        }
+
+        pri.urgency = (uint32_t)val.i;
+
+        break;
+      }
+    }
+
+    sf_discard_ows(p, end);
+
+    if (*p++ != ',') {
+      return NGHTTP2_ERR_INVALID_ARGUMENT;
+    }
+
+    sf_discard_ows_end_err(p, end, NGHTTP2_ERR_INVALID_ARGUMENT);
+  }
+
+fin:
+  *dest = pri;
+
+  return 0;
+}
diff --git a/Utilities/cmnghttp2/lib/nghttp2_http.h b/Utilities/cmnghttp2/lib/nghttp2_http.h
index dd057cd..0c3a78e 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_http.h
+++ b/Utilities/cmnghttp2/lib/nghttp2_http.h
@@ -94,4 +94,55 @@
 void nghttp2_http_record_request_method(nghttp2_stream *stream,
                                         nghttp2_frame *frame);
 
+/*
+ * RFC 8941 Structured Field Values.
+ */
+typedef enum nghttp2_sf_value_type {
+  NGHTTP2_SF_VALUE_TYPE_BOOLEAN,
+  NGHTTP2_SF_VALUE_TYPE_INTEGER,
+  NGHTTP2_SF_VALUE_TYPE_DECIMAL,
+  NGHTTP2_SF_VALUE_TYPE_STRING,
+  NGHTTP2_SF_VALUE_TYPE_TOKEN,
+  NGHTTP2_SF_VALUE_TYPE_BYTESEQ,
+  NGHTTP2_SF_VALUE_TYPE_INNER_LIST,
+} nghttp2_sf_value_type;
+
+/*
+ * nghttp2_sf_value stores Structured Field Values item.  For Inner
+ * List, only type is set to NGHTTP2_SF_VALUE_TYPE_INNER_LIST.
+ */
+typedef struct nghttp2_sf_value {
+  uint8_t type;
+  union {
+    int b;
+    int64_t i;
+    double d;
+    struct {
+      const uint8_t *base;
+      size_t len;
+    } s;
+  };
+} nghttp2_sf_value;
+
+/*
+ * nghttp2_sf_parse_item parses the input sequence [|begin|, |end|)
+ * and stores the parsed an Item in |dest|.  It returns the number of
+ * bytes consumed if it succeeds, or -1.  This function is declared
+ * here for unit tests.
+ */
+ssize_t nghttp2_sf_parse_item(nghttp2_sf_value *dest, const uint8_t *begin,
+                              const uint8_t *end);
+
+/*
+ * nghttp2_sf_parse_inner_list parses the input sequence [|begin|, |end|)
+ * and stores the parsed an Inner List in |dest|.  It returns the number of
+ * bytes consumed if it succeeds, or -1.  This function is declared
+ * here for unit tests.
+ */
+ssize_t nghttp2_sf_parse_inner_list(nghttp2_sf_value *dest,
+                                    const uint8_t *begin, const uint8_t *end);
+
+int nghttp2_http_parse_priority(nghttp2_extpri *dest, const uint8_t *value,
+                                size_t valuelen);
+
 #endif /* NGHTTP2_HTTP_H */
diff --git a/Utilities/cmnghttp2/lib/nghttp2_map.c b/Utilities/cmnghttp2/lib/nghttp2_map.c
index 4d9f97b..e5db168 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_map.c
+++ b/Utilities/cmnghttp2/lib/nghttp2_map.c
@@ -1,7 +1,8 @@
 /*
  * nghttp2 - HTTP/2 C Library
  *
- * Copyright (c) 2012 Tatsuhiro Tsujikawa
+ * Copyright (c) 2017 ngtcp2 contributors
+ * Copyright (c) 2012 nghttp2 contributors
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -25,14 +26,19 @@
 #include "nghttp2_map.h"
 
 #include <string.h>
+#include <assert.h>
+#include <stdio.h>
 
-#define INITIAL_TABLE_LENGTH 256
+#include "nghttp2_helper.h"
+
+#define NGHTTP2_INITIAL_TABLE_LENBITS 8
 
 int nghttp2_map_init(nghttp2_map *map, nghttp2_mem *mem) {
   map->mem = mem;
-  map->tablelen = INITIAL_TABLE_LENGTH;
+  map->tablelen = 1 << NGHTTP2_INITIAL_TABLE_LENBITS;
+  map->tablelenbits = NGHTTP2_INITIAL_TABLE_LENBITS;
   map->table =
-      nghttp2_mem_calloc(mem, map->tablelen, sizeof(nghttp2_map_entry *));
+      nghttp2_mem_calloc(mem, map->tablelen, sizeof(nghttp2_map_bucket));
   if (map->table == NULL) {
     return NGHTTP2_ERR_NOMEM;
   }
@@ -43,112 +49,188 @@
 }
 
 void nghttp2_map_free(nghttp2_map *map) {
+  if (!map) {
+    return;
+  }
+
   nghttp2_mem_free(map->mem, map->table);
 }
 
-void nghttp2_map_each_free(nghttp2_map *map,
-                           int (*func)(nghttp2_map_entry *entry, void *ptr),
+void nghttp2_map_each_free(nghttp2_map *map, int (*func)(void *data, void *ptr),
                            void *ptr) {
   uint32_t i;
+  nghttp2_map_bucket *bkt;
+
   for (i = 0; i < map->tablelen; ++i) {
-    nghttp2_map_entry *entry;
-    for (entry = map->table[i]; entry;) {
-      nghttp2_map_entry *next = entry->next;
-      func(entry, ptr);
-      entry = next;
+    bkt = &map->table[i];
+
+    if (bkt->data == NULL) {
+      continue;
     }
-    map->table[i] = NULL;
+
+    func(bkt->data, ptr);
   }
 }
 
-int nghttp2_map_each(nghttp2_map *map,
-                     int (*func)(nghttp2_map_entry *entry, void *ptr),
+int nghttp2_map_each(nghttp2_map *map, int (*func)(void *data, void *ptr),
                      void *ptr) {
   int rv;
   uint32_t i;
+  nghttp2_map_bucket *bkt;
+
   for (i = 0; i < map->tablelen; ++i) {
-    nghttp2_map_entry *entry;
-    for (entry = map->table[i]; entry; entry = entry->next) {
-      rv = func(entry, ptr);
-      if (rv != 0) {
-        return rv;
-      }
+    bkt = &map->table[i];
+
+    if (bkt->data == NULL) {
+      continue;
+    }
+
+    rv = func(bkt->data, ptr);
+    if (rv != 0) {
+      return rv;
     }
   }
+
   return 0;
 }
 
-void nghttp2_map_entry_init(nghttp2_map_entry *entry, key_type key) {
-  entry->key = key;
-  entry->next = NULL;
+static uint32_t hash(nghttp2_map_key_type key) {
+  return (uint32_t)key * 2654435769u;
 }
 
-/* Same hash function in android HashMap source code. */
-/* The |mod| must be power of 2 */
-static uint32_t hash(int32_t key, uint32_t mod) {
-  uint32_t h = (uint32_t)key;
-  h ^= (h >> 20) ^ (h >> 12);
-  h ^= (h >> 7) ^ (h >> 4);
-  return h & (mod - 1);
+static size_t h2idx(uint32_t hash, uint32_t bits) {
+  return hash >> (32 - bits);
 }
 
-static int insert(nghttp2_map_entry **table, uint32_t tablelen,
-                  nghttp2_map_entry *entry) {
-  uint32_t h = hash(entry->key, tablelen);
-  if (table[h] == NULL) {
-    table[h] = entry;
-  } else {
-    nghttp2_map_entry *p;
-    /* We won't allow duplicated key, so check it out. */
-    for (p = table[h]; p; p = p->next) {
-      if (p->key == entry->key) {
-        return NGHTTP2_ERR_INVALID_ARGUMENT;
-      }
-    }
-    entry->next = table[h];
-    table[h] = entry;
-  }
-  return 0;
+static size_t distance(uint32_t tablelen, uint32_t tablelenbits,
+                       nghttp2_map_bucket *bkt, size_t idx) {
+  return (idx - h2idx(bkt->hash, tablelenbits)) & (tablelen - 1);
 }
 
-/* new_tablelen must be power of 2 */
-static int resize(nghttp2_map *map, uint32_t new_tablelen) {
+static void map_bucket_swap(nghttp2_map_bucket *bkt, uint32_t *phash,
+                            nghttp2_map_key_type *pkey, void **pdata) {
+  uint32_t h = bkt->hash;
+  nghttp2_map_key_type key = bkt->key;
+  void *data = bkt->data;
+
+  bkt->hash = *phash;
+  bkt->key = *pkey;
+  bkt->data = *pdata;
+
+  *phash = h;
+  *pkey = key;
+  *pdata = data;
+}
+
+static void map_bucket_set_data(nghttp2_map_bucket *bkt, uint32_t hash,
+                                nghttp2_map_key_type key, void *data) {
+  bkt->hash = hash;
+  bkt->key = key;
+  bkt->data = data;
+}
+
+void nghttp2_map_print_distance(nghttp2_map *map) {
   uint32_t i;
-  nghttp2_map_entry **new_table;
+  size_t idx;
+  nghttp2_map_bucket *bkt;
+
+  for (i = 0; i < map->tablelen; ++i) {
+    bkt = &map->table[i];
+
+    if (bkt->data == NULL) {
+      fprintf(stderr, "@%u <EMPTY>\n", i);
+      continue;
+    }
+
+    idx = h2idx(bkt->hash, map->tablelenbits);
+    fprintf(stderr, "@%u hash=%08x key=%d base=%zu distance=%zu\n", i,
+            bkt->hash, bkt->key, idx,
+            distance(map->tablelen, map->tablelenbits, bkt, idx));
+  }
+}
+
+static int insert(nghttp2_map_bucket *table, uint32_t tablelen,
+                  uint32_t tablelenbits, uint32_t hash,
+                  nghttp2_map_key_type key, void *data) {
+  size_t idx = h2idx(hash, tablelenbits);
+  size_t d = 0, dd;
+  nghttp2_map_bucket *bkt;
+
+  for (;;) {
+    bkt = &table[idx];
+
+    if (bkt->data == NULL) {
+      map_bucket_set_data(bkt, hash, key, data);
+      return 0;
+    }
+
+    dd = distance(tablelen, tablelenbits, bkt, idx);
+    if (d > dd) {
+      map_bucket_swap(bkt, &hash, &key, &data);
+      d = dd;
+    } else if (bkt->key == key) {
+      /* TODO This check is just a waste after first swap or if this
+         function is called from map_resize.  That said, there is no
+         difference with or without this conditional in performance
+         wise. */
+      return NGHTTP2_ERR_INVALID_ARGUMENT;
+    }
+
+    ++d;
+    idx = (idx + 1) & (tablelen - 1);
+  }
+}
+
+/* new_tablelen must be power of 2 and new_tablelen == (1 <<
+   new_tablelenbits) must hold. */
+static int map_resize(nghttp2_map *map, uint32_t new_tablelen,
+                      uint32_t new_tablelenbits) {
+  uint32_t i;
+  nghttp2_map_bucket *new_table;
+  nghttp2_map_bucket *bkt;
+  int rv;
+  (void)rv;
 
   new_table =
-      nghttp2_mem_calloc(map->mem, new_tablelen, sizeof(nghttp2_map_entry *));
+      nghttp2_mem_calloc(map->mem, new_tablelen, sizeof(nghttp2_map_bucket));
   if (new_table == NULL) {
     return NGHTTP2_ERR_NOMEM;
   }
 
   for (i = 0; i < map->tablelen; ++i) {
-    nghttp2_map_entry *entry;
-    for (entry = map->table[i]; entry;) {
-      nghttp2_map_entry *next = entry->next;
-      entry->next = NULL;
-      /* This function must succeed */
-      insert(new_table, new_tablelen, entry);
-      entry = next;
+    bkt = &map->table[i];
+    if (bkt->data == NULL) {
+      continue;
     }
+    rv = insert(new_table, new_tablelen, new_tablelenbits, bkt->hash, bkt->key,
+                bkt->data);
+
+    assert(0 == rv);
   }
+
   nghttp2_mem_free(map->mem, map->table);
   map->tablelen = new_tablelen;
+  map->tablelenbits = new_tablelenbits;
   map->table = new_table;
 
   return 0;
 }
 
-int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_entry *new_entry) {
+int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_key_type key, void *data) {
   int rv;
+
+  assert(data);
+
   /* Load factor is 0.75 */
   if ((map->size + 1) * 4 > map->tablelen * 3) {
-    rv = resize(map, map->tablelen * 2);
+    rv = map_resize(map, map->tablelen * 2, map->tablelenbits + 1);
     if (rv != 0) {
       return rv;
     }
   }
-  rv = insert(map->table, map->tablelen, new_entry);
+
+  rv = insert(map->table, map->tablelen, map->tablelenbits, hash(key), key,
+              data);
   if (rv != 0) {
     return rv;
   }
@@ -156,34 +238,76 @@
   return 0;
 }
 
-nghttp2_map_entry *nghttp2_map_find(nghttp2_map *map, key_type key) {
-  uint32_t h;
-  nghttp2_map_entry *entry;
-  h = hash(key, map->tablelen);
-  for (entry = map->table[h]; entry; entry = entry->next) {
-    if (entry->key == key) {
-      return entry;
+void *nghttp2_map_find(nghttp2_map *map, nghttp2_map_key_type key) {
+  uint32_t h = hash(key);
+  size_t idx = h2idx(h, map->tablelenbits);
+  nghttp2_map_bucket *bkt;
+  size_t d = 0;
+
+  for (;;) {
+    bkt = &map->table[idx];
+
+    if (bkt->data == NULL ||
+        d > distance(map->tablelen, map->tablelenbits, bkt, idx)) {
+      return NULL;
     }
+
+    if (bkt->key == key) {
+      return bkt->data;
+    }
+
+    ++d;
+    idx = (idx + 1) & (map->tablelen - 1);
   }
-  return NULL;
 }
 
-int nghttp2_map_remove(nghttp2_map *map, key_type key) {
-  uint32_t h;
-  nghttp2_map_entry **dst;
+int nghttp2_map_remove(nghttp2_map *map, nghttp2_map_key_type key) {
+  uint32_t h = hash(key);
+  size_t idx = h2idx(h, map->tablelenbits), didx;
+  nghttp2_map_bucket *bkt;
+  size_t d = 0;
 
-  h = hash(key, map->tablelen);
+  for (;;) {
+    bkt = &map->table[idx];
 
-  for (dst = &map->table[h]; *dst; dst = &(*dst)->next) {
-    if ((*dst)->key != key) {
-      continue;
+    if (bkt->data == NULL ||
+        d > distance(map->tablelen, map->tablelenbits, bkt, idx)) {
+      return NGHTTP2_ERR_INVALID_ARGUMENT;
     }
 
-    *dst = (*dst)->next;
-    --map->size;
-    return 0;
+    if (bkt->key == key) {
+      map_bucket_set_data(bkt, 0, 0, NULL);
+
+      didx = idx;
+      idx = (idx + 1) & (map->tablelen - 1);
+
+      for (;;) {
+        bkt = &map->table[idx];
+        if (bkt->data == NULL ||
+            distance(map->tablelen, map->tablelenbits, bkt, idx) == 0) {
+          break;
+        }
+
+        map->table[didx] = *bkt;
+        map_bucket_set_data(bkt, 0, 0, NULL);
+        didx = idx;
+
+        idx = (idx + 1) & (map->tablelen - 1);
+      }
+
+      --map->size;
+
+      return 0;
+    }
+
+    ++d;
+    idx = (idx + 1) & (map->tablelen - 1);
   }
-  return NGHTTP2_ERR_INVALID_ARGUMENT;
+}
+
+void nghttp2_map_clear(nghttp2_map *map) {
+  memset(map->table, 0, sizeof(*map->table) * map->tablelen);
+  map->size = 0;
 }
 
 size_t nghttp2_map_size(nghttp2_map *map) { return map->size; }
diff --git a/Utilities/cmnghttp2/lib/nghttp2_map.h b/Utilities/cmnghttp2/lib/nghttp2_map.h
index f6e29e3..1419a09 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_map.h
+++ b/Utilities/cmnghttp2/lib/nghttp2_map.h
@@ -1,7 +1,8 @@
 /*
  * nghttp2 - HTTP/2 C Library
  *
- * Copyright (c) 2012 Tatsuhiro Tsujikawa
+ * Copyright (c) 2017 ngtcp2 contributors
+ * Copyright (c) 2012 nghttp2 contributors
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -30,27 +31,25 @@
 #endif /* HAVE_CONFIG_H */
 
 #include <nghttp2/nghttp2.h>
-#include "nghttp2_int.h"
+
 #include "nghttp2_mem.h"
 
 /* Implementation of unordered map */
 
-typedef int32_t key_type;
+typedef int32_t nghttp2_map_key_type;
 
-typedef struct nghttp2_map_entry {
-  struct nghttp2_map_entry *next;
-  key_type key;
-#if SIZEOF_INT_P == 4
-  /* we requires 8 bytes aligment */
-  int64_t pad;
-#endif
-} nghttp2_map_entry;
+typedef struct nghttp2_map_bucket {
+  uint32_t hash;
+  nghttp2_map_key_type key;
+  void *data;
+} nghttp2_map_bucket;
 
-typedef struct {
-  nghttp2_map_entry **table;
+typedef struct nghttp2_map {
+  nghttp2_map_bucket *table;
   nghttp2_mem *mem;
   size_t size;
   uint32_t tablelen;
+  uint32_t tablelenbits;
 } nghttp2_map;
 
 /*
@@ -74,21 +73,14 @@
 /*
  * Deallocates each entries using |func| function and any resources
  * allocated for |map|. The |func| function is responsible for freeing
- * given the |entry| object. The |ptr| will be passed to the |func| as
+ * given the |data| object. The |ptr| will be passed to the |func| as
  * send argument. The return value of the |func| will be ignored.
  */
-void nghttp2_map_each_free(nghttp2_map *map,
-                           int (*func)(nghttp2_map_entry *entry, void *ptr),
+void nghttp2_map_each_free(nghttp2_map *map, int (*func)(void *data, void *ptr),
                            void *ptr);
 
 /*
- * Initializes the |entry| with the |key|. All entries to be inserted
- * to the map must be initialized with this function.
- */
-void nghttp2_map_entry_init(nghttp2_map_entry *entry, key_type key);
-
-/*
- * Inserts the new |entry| with the key |entry->key| to the map |map|.
+ * Inserts the new |data| with the |key| to the map |map|.
  *
  * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
@@ -98,25 +90,30 @@
  * NGHTTP2_ERR_NOMEM
  *   Out of memory
  */
-int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_entry *entry);
+int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_key_type key, void *data);
 
 /*
- * Returns the entry associated by the key |key|.  If there is no such
- * entry, this function returns NULL.
+ * Returns the data associated by the key |key|.  If there is no such
+ * data, this function returns NULL.
  */
-nghttp2_map_entry *nghttp2_map_find(nghttp2_map *map, key_type key);
+void *nghttp2_map_find(nghttp2_map *map, nghttp2_map_key_type key);
 
 /*
- * Removes the entry associated by the key |key| from the |map|.  The
- * removed entry is not freed by this function.
+ * Removes the data associated by the key |key| from the |map|.  The
+ * removed data is not freed by this function.
  *
  * This function returns 0 if it succeeds, or one of the following
  * negative error codes:
  *
  * NGHTTP2_ERR_INVALID_ARGUMENT
- *     The entry associated by |key| does not exist.
+ *     The data associated by |key| does not exist.
  */
-int nghttp2_map_remove(nghttp2_map *map, key_type key);
+int nghttp2_map_remove(nghttp2_map *map, nghttp2_map_key_type key);
+
+/*
+ * Removes all entries from |map|.
+ */
+void nghttp2_map_clear(nghttp2_map *map);
 
 /*
  * Returns the number of items stored in the map |map|.
@@ -124,21 +121,22 @@
 size_t nghttp2_map_size(nghttp2_map *map);
 
 /*
- * Applies the function |func| to each entry in the |map| with the
+ * Applies the function |func| to each data in the |map| with the
  * optional user supplied pointer |ptr|.
  *
  * If the |func| returns 0, this function calls the |func| with the
- * next entry. If the |func| returns nonzero, it will not call the
+ * next data.  If the |func| returns nonzero, it will not call the
  * |func| for further entries and return the return value of the
  * |func| immediately.  Thus, this function returns 0 if all the
  * invocations of the |func| return 0, or nonzero value which the last
  * invocation of |func| returns.
  *
- * Don't use this function to free each entry. Use
+ * Don't use this function to free each data. Use
  * nghttp2_map_each_free() instead.
  */
-int nghttp2_map_each(nghttp2_map *map,
-                     int (*func)(nghttp2_map_entry *entry, void *ptr),
+int nghttp2_map_each(nghttp2_map *map, int (*func)(void *data, void *ptr),
                      void *ptr);
 
+void nghttp2_map_print_distance(nghttp2_map *map);
+
 #endif /* NGHTTP2_MAP_H */
diff --git a/Utilities/cmnghttp2/lib/nghttp2_net.h b/Utilities/cmnghttp2/lib/nghttp2_net.h
index 95ffee7..345f6c8 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_net.h
+++ b/Utilities/cmnghttp2/lib/nghttp2_net.h
@@ -42,7 +42,7 @@
 #if defined(WIN32)
 /* Windows requires ws2_32 library for ntonl family functions.  We
    define inline functions for those function so that we don't have
-   dependeny on that lib. */
+   dependency on that lib. */
 
 #  ifdef _MSC_VER
 #    define STIN static __inline
@@ -53,7 +53,7 @@
 STIN uint32_t htonl(uint32_t hostlong) {
   uint32_t res;
   unsigned char *p = (unsigned char *)&res;
-  *p++ = hostlong >> 24;
+  *p++ = (unsigned char)(hostlong >> 24);
   *p++ = (hostlong >> 16) & 0xffu;
   *p++ = (hostlong >> 8) & 0xffu;
   *p = hostlong & 0xffu;
@@ -63,7 +63,7 @@
 STIN uint16_t htons(uint16_t hostshort) {
   uint16_t res;
   unsigned char *p = (unsigned char *)&res;
-  *p++ = hostshort >> 8;
+  *p++ = (unsigned char)(hostshort >> 8);
   *p = hostshort & 0xffu;
   return res;
 }
diff --git a/Utilities/cmnghttp2/lib/nghttp2_option.c b/Utilities/cmnghttp2/lib/nghttp2_option.c
index e53f22d..ee0cd0f 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_option.c
+++ b/Utilities/cmnghttp2/lib/nghttp2_option.c
@@ -90,6 +90,10 @@
     option->opt_set_mask |= NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES;
     option->builtin_recv_ext_types |= NGHTTP2_TYPEMASK_ORIGIN;
     return;
+  case NGHTTP2_PRIORITY_UPDATE:
+    option->opt_set_mask |= NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES;
+    option->builtin_recv_ext_types |= NGHTTP2_TYPEMASK_PRIORITY_UPDATE;
+    return;
   default:
     return;
   }
@@ -121,3 +125,21 @@
   option->opt_set_mask |= NGHTTP2_OPT_MAX_OUTBOUND_ACK;
   option->max_outbound_ack = val;
 }
+
+void nghttp2_option_set_max_settings(nghttp2_option *option, size_t val) {
+  option->opt_set_mask |= NGHTTP2_OPT_MAX_SETTINGS;
+  option->max_settings = val;
+}
+
+void nghttp2_option_set_server_fallback_rfc7540_priorities(
+    nghttp2_option *option, int val) {
+  option->opt_set_mask |= NGHTTP2_OPT_SERVER_FALLBACK_RFC7540_PRIORITIES;
+  option->server_fallback_rfc7540_priorities = val;
+}
+
+void nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation(
+    nghttp2_option *option, int val) {
+  option->opt_set_mask |=
+      NGHTTP2_OPT_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION;
+  option->no_rfc9113_leading_and_trailing_ws_validation = val;
+}
diff --git a/Utilities/cmnghttp2/lib/nghttp2_option.h b/Utilities/cmnghttp2/lib/nghttp2_option.h
index 1f740aa..b228a07 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_option.h
+++ b/Utilities/cmnghttp2/lib/nghttp2_option.h
@@ -67,6 +67,9 @@
   NGHTTP2_OPT_MAX_DEFLATE_DYNAMIC_TABLE_SIZE = 1 << 9,
   NGHTTP2_OPT_NO_CLOSED_STREAMS = 1 << 10,
   NGHTTP2_OPT_MAX_OUTBOUND_ACK = 1 << 11,
+  NGHTTP2_OPT_MAX_SETTINGS = 1 << 12,
+  NGHTTP2_OPT_SERVER_FALLBACK_RFC7540_PRIORITIES = 1 << 13,
+  NGHTTP2_OPT_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION = 1 << 14,
 } nghttp2_option_flag;
 
 /**
@@ -86,6 +89,10 @@
    */
   size_t max_outbound_ack;
   /**
+   * NGHTTP2_OPT_MAX_SETTINGS
+   */
+  size_t max_settings;
+  /**
    * Bitwise OR of nghttp2_option_flag to determine that which fields
    * are specified.
    */
@@ -123,6 +130,14 @@
    */
   int no_closed_streams;
   /**
+   * NGHTTP2_OPT_SERVER_FALLBACK_RFC7540_PRIORITIES
+   */
+  int server_fallback_rfc7540_priorities;
+  /**
+   * NGHTTP2_OPT_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION
+   */
+  int no_rfc9113_leading_and_trailing_ws_validation;
+  /**
    * NGHTTP2_OPT_USER_RECV_EXT_TYPES
    */
   uint8_t user_recv_ext_types[32];
diff --git a/Utilities/cmnghttp2/lib/nghttp2_outbound_item.c b/Utilities/cmnghttp2/lib/nghttp2_outbound_item.c
index f651c80..2a3041d 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_outbound_item.c
+++ b/Utilities/cmnghttp2/lib/nghttp2_outbound_item.c
@@ -89,6 +89,9 @@
     case NGHTTP2_ORIGIN:
       nghttp2_frame_origin_free(&frame->ext, mem);
       break;
+    case NGHTTP2_PRIORITY_UPDATE:
+      nghttp2_frame_priority_update_free(&frame->ext, mem);
+      break;
     default:
       assert(0);
       break;
diff --git a/Utilities/cmnghttp2/lib/nghttp2_outbound_item.h b/Utilities/cmnghttp2/lib/nghttp2_outbound_item.h
index b5f503a..bd4611b 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_outbound_item.h
+++ b/Utilities/cmnghttp2/lib/nghttp2_outbound_item.h
@@ -111,7 +111,7 @@
      to this structure to avoid frequent memory allocation. */
   nghttp2_ext_frame_payload ext_frame_payload;
   nghttp2_aux_data aux_data;
-  /* The priority used in priority comparion.  Smaller is served
+  /* The priority used in priority comparison.  Smaller is served
      earlier.  For PING, SETTINGS and non-DATA frames (excluding
      response HEADERS frame) have dedicated cycle value defined above.
      For DATA frame, cycle is computed by taking into account of
diff --git a/Utilities/cmnghttp2/lib/nghttp2_pq.c b/Utilities/cmnghttp2/lib/nghttp2_pq.c
index bebccc7..64353ac 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_pq.c
+++ b/Utilities/cmnghttp2/lib/nghttp2_pq.c
@@ -29,13 +29,12 @@
 
 #include "nghttp2_helper.h"
 
-int nghttp2_pq_init(nghttp2_pq *pq, nghttp2_less less, nghttp2_mem *mem) {
+void nghttp2_pq_init(nghttp2_pq *pq, nghttp2_less less, nghttp2_mem *mem) {
   pq->mem = mem;
   pq->capacity = 0;
   pq->q = NULL;
   pq->length = 0;
   pq->less = less;
-  return 0;
 }
 
 void nghttp2_pq_free(nghttp2_pq *pq) {
diff --git a/Utilities/cmnghttp2/lib/nghttp2_pq.h b/Utilities/cmnghttp2/lib/nghttp2_pq.h
index 2d7b702..c8d90ef 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_pq.h
+++ b/Utilities/cmnghttp2/lib/nghttp2_pq.h
@@ -55,14 +55,8 @@
 
 /*
  * Initializes priority queue |pq| with compare function |cmp|.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGHTTP2_ERR_NOMEM
- *     Out of memory.
  */
-int nghttp2_pq_init(nghttp2_pq *pq, nghttp2_less less, nghttp2_mem *mem);
+void nghttp2_pq_init(nghttp2_pq *pq, nghttp2_less less, nghttp2_mem *mem);
 
 /*
  * Deallocates any resources allocated for |pq|.  The stored items are
@@ -114,7 +108,7 @@
 void nghttp2_pq_update(nghttp2_pq *pq, nghttp2_pq_item_cb fun, void *arg);
 
 /*
- * Applys |fun| to each item in |pq|.  The |arg| is passed as arg
+ * Applies |fun| to each item in |pq|.  The |arg| is passed as arg
  * parameter to callback function.  This function must not change the
  * ordering key.  If the return value from callback is nonzero, this
  * function returns 1 immediately without iterating remaining items.
diff --git a/Utilities/cmnghttp2/lib/nghttp2_session.c b/Utilities/cmnghttp2/lib/nghttp2_session.c
index 9df3d6f..93f3f07 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_session.c
+++ b/Utilities/cmnghttp2/lib/nghttp2_session.c
@@ -36,6 +36,7 @@
 #include "nghttp2_option.h"
 #include "nghttp2_http.h"
 #include "nghttp2_pq.h"
+#include "nghttp2_extpri.h"
 #include "nghttp2_debug.h"
 
 /*
@@ -143,6 +144,11 @@
   return 0;
 }
 
+static int session_no_rfc7540_pri_no_fallback(nghttp2_session *session) {
+  return session->pending_no_rfc7540_priorities == 1 &&
+         !session->fallback_rfc7540_priorities;
+}
+
 static int check_ext_type_set(const uint8_t *ext_types, uint8_t type) {
   return (ext_types[type / 8] & (1 << (type & 0x7))) > 0;
 }
@@ -354,6 +360,14 @@
         }
         nghttp2_frame_origin_free(&iframe->frame.ext, mem);
         break;
+      case NGHTTP2_PRIORITY_UPDATE:
+        if ((session->builtin_recv_ext_types &
+             NGHTTP2_TYPEMASK_PRIORITY_UPDATE) == 0) {
+          break;
+        }
+        /* Do not call nghttp2_frame_priority_update_free, because all
+           fields point to sbuf. */
+        break;
       }
     }
 
@@ -385,6 +399,7 @@
   settings->initial_window_size = NGHTTP2_INITIAL_WINDOW_SIZE;
   settings->max_frame_size = NGHTTP2_MAX_FRAME_SIZE_MIN;
   settings->max_header_list_size = UINT32_MAX;
+  settings->no_rfc7540_priorities = UINT32_MAX;
 }
 
 static void active_outbound_item_reset(nghttp2_active_outbound_item *aob,
@@ -398,6 +413,21 @@
   aob->state = NGHTTP2_OB_POP_ITEM;
 }
 
+#define NGHTTP2_STREAM_MAX_CYCLE_GAP ((uint64_t)NGHTTP2_MAX_FRAME_SIZE_MAX)
+
+static int stream_less(const void *lhsx, const void *rhsx) {
+  const nghttp2_stream *lhs, *rhs;
+
+  lhs = nghttp2_struct_of(lhsx, nghttp2_stream, pq_entry);
+  rhs = nghttp2_struct_of(rhsx, nghttp2_stream, pq_entry);
+
+  if (lhs->cycle == rhs->cycle) {
+    return lhs->seq < rhs->seq;
+  }
+
+  return rhs->cycle - lhs->cycle <= NGHTTP2_STREAM_MAX_CYCLE_GAP;
+}
+
 int nghttp2_enable_strict_preface = 1;
 
 static int session_new(nghttp2_session **session_ptr,
@@ -408,6 +438,7 @@
   size_t nbuffer;
   size_t max_deflate_dynamic_table_size =
       NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE;
+  size_t i;
 
   if (mem == NULL) {
     mem = nghttp2_mem_default();
@@ -442,6 +473,7 @@
   (*session_ptr)->pending_local_max_concurrent_stream =
       NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS;
   (*session_ptr)->pending_enable_push = 1;
+  (*session_ptr)->pending_no_rfc7540_priorities = UINT8_MAX;
 
   if (server) {
     (*session_ptr)->server = 1;
@@ -458,6 +490,7 @@
 
   (*session_ptr)->max_send_header_block_length = NGHTTP2_MAX_HEADERSLEN;
   (*session_ptr)->max_outbound_ack = NGHTTP2_DEFAULT_MAX_OBQ_FLOOD_ITEM;
+  (*session_ptr)->max_settings = NGHTTP2_DEFAULT_MAX_SETTINGS;
 
   if (option) {
     if ((option->opt_set_mask & NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE) &&
@@ -521,6 +554,25 @@
     if (option->opt_set_mask & NGHTTP2_OPT_MAX_OUTBOUND_ACK) {
       (*session_ptr)->max_outbound_ack = option->max_outbound_ack;
     }
+
+    if ((option->opt_set_mask & NGHTTP2_OPT_MAX_SETTINGS) &&
+        option->max_settings) {
+      (*session_ptr)->max_settings = option->max_settings;
+    }
+
+    if ((option->opt_set_mask &
+         NGHTTP2_OPT_SERVER_FALLBACK_RFC7540_PRIORITIES) &&
+        option->server_fallback_rfc7540_priorities) {
+      (*session_ptr)->opt_flags |=
+          NGHTTP2_OPTMASK_SERVER_FALLBACK_RFC7540_PRIORITIES;
+    }
+
+    if ((option->opt_set_mask &
+         NGHTTP2_OPT_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) &&
+        option->no_rfc9113_leading_and_trailing_ws_validation) {
+      (*session_ptr)->opt_flags |=
+          NGHTTP2_OPTMASK_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION;
+    }
   }
 
   rv = nghttp2_hd_deflate_init2(&(*session_ptr)->hd_deflater,
@@ -578,6 +630,10 @@
     }
   }
 
+  for (i = 0; i < NGHTTP2_EXTPRI_URGENCY_LEVELS; ++i) {
+    nghttp2_pq_init(&(*session_ptr)->sched[i].ob_data, stream_less, mem);
+  }
+
   return 0;
 
 fail_aob_framebuf:
@@ -660,7 +716,7 @@
   return 0;
 }
 
-static int free_streams(nghttp2_map_entry *entry, void *ptr) {
+static int free_streams(void *entry, void *ptr) {
   nghttp2_session *session;
   nghttp2_stream *stream;
   nghttp2_outbound_item *item;
@@ -729,6 +785,7 @@
 void nghttp2_session_del(nghttp2_session *session) {
   nghttp2_mem *mem;
   nghttp2_inflight_settings *settings;
+  size_t i;
 
   if (session == NULL) {
     return;
@@ -742,6 +799,9 @@
     settings = next;
   }
 
+  for (i = 0; i < NGHTTP2_EXTPRI_URGENCY_LEVELS; ++i) {
+    nghttp2_pq_free(&session->sched[i].ob_data);
+  }
   nghttp2_stream_free(&session->root);
 
   /* Have to free streams first, so that we can check
@@ -769,6 +829,8 @@
   nghttp2_priority_spec pri_spec_default;
   const nghttp2_priority_spec *pri_spec = pri_spec_in;
 
+  assert((!session->server && session->pending_no_rfc7540_priorities != 1) ||
+         (session->server && !session_no_rfc7540_pri_no_fallback(session)));
   assert(pri_spec->stream_id != stream->stream_id);
 
   if (!nghttp2_stream_in_dep_tree(stream)) {
@@ -836,6 +898,214 @@
   return 0;
 }
 
+static uint64_t pq_get_first_cycle(nghttp2_pq *pq) {
+  nghttp2_stream *stream;
+
+  if (nghttp2_pq_empty(pq)) {
+    return 0;
+  }
+
+  stream = nghttp2_struct_of(nghttp2_pq_top(pq), nghttp2_stream, pq_entry);
+  return stream->cycle;
+}
+
+static int session_ob_data_push(nghttp2_session *session,
+                                nghttp2_stream *stream) {
+  int rv;
+  uint32_t urgency;
+  int inc;
+  nghttp2_pq *pq;
+
+  assert(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES);
+  assert(stream->queued == 0);
+
+  urgency = nghttp2_extpri_uint8_urgency(stream->extpri);
+  inc = nghttp2_extpri_uint8_inc(stream->extpri);
+
+  assert(urgency < NGHTTP2_EXTPRI_URGENCY_LEVELS);
+
+  pq = &session->sched[urgency].ob_data;
+
+  stream->cycle = pq_get_first_cycle(pq);
+  if (inc) {
+    stream->cycle += stream->last_writelen;
+  }
+
+  rv = nghttp2_pq_push(pq, &stream->pq_entry);
+  if (rv != 0) {
+    return rv;
+  }
+
+  stream->queued = 1;
+
+  return 0;
+}
+
+static int session_ob_data_remove(nghttp2_session *session,
+                                  nghttp2_stream *stream) {
+  uint32_t urgency;
+
+  assert(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES);
+  assert(stream->queued == 1);
+
+  urgency = nghttp2_extpri_uint8_urgency(stream->extpri);
+
+  assert(urgency < NGHTTP2_EXTPRI_URGENCY_LEVELS);
+
+  nghttp2_pq_remove(&session->sched[urgency].ob_data, &stream->pq_entry);
+
+  stream->queued = 0;
+
+  return 0;
+}
+
+static int session_attach_stream_item(nghttp2_session *session,
+                                      nghttp2_stream *stream,
+                                      nghttp2_outbound_item *item) {
+  int rv;
+
+  rv = nghttp2_stream_attach_item(stream, item);
+  if (rv != 0) {
+    return rv;
+  }
+
+  if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES)) {
+    return 0;
+  }
+
+  return session_ob_data_push(session, stream);
+}
+
+static int session_detach_stream_item(nghttp2_session *session,
+                                      nghttp2_stream *stream) {
+  int rv;
+
+  rv = nghttp2_stream_detach_item(stream);
+  if (rv != 0) {
+    return rv;
+  }
+
+  if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) ||
+      !stream->queued) {
+    return 0;
+  }
+
+  return session_ob_data_remove(session, stream);
+}
+
+static int session_defer_stream_item(nghttp2_session *session,
+                                     nghttp2_stream *stream, uint8_t flags) {
+  int rv;
+
+  rv = nghttp2_stream_defer_item(stream, flags);
+  if (rv != 0) {
+    return rv;
+  }
+
+  if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) ||
+      !stream->queued) {
+    return 0;
+  }
+
+  return session_ob_data_remove(session, stream);
+}
+
+static int session_resume_deferred_stream_item(nghttp2_session *session,
+                                               nghttp2_stream *stream,
+                                               uint8_t flags) {
+  int rv;
+
+  rv = nghttp2_stream_resume_deferred_item(stream, flags);
+  if (rv != 0) {
+    return rv;
+  }
+
+  if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) ||
+      (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL)) {
+    return 0;
+  }
+
+  return session_ob_data_push(session, stream);
+}
+
+static nghttp2_outbound_item *
+session_sched_get_next_outbound_item(nghttp2_session *session) {
+  size_t i;
+  nghttp2_pq_entry *ent;
+  nghttp2_stream *stream;
+
+  for (i = 0; i < NGHTTP2_EXTPRI_URGENCY_LEVELS; ++i) {
+    ent = nghttp2_pq_top(&session->sched[i].ob_data);
+    if (!ent) {
+      continue;
+    }
+
+    stream = nghttp2_struct_of(ent, nghttp2_stream, pq_entry);
+    return stream->item;
+  }
+
+  return NULL;
+}
+
+static int session_sched_empty(nghttp2_session *session) {
+  size_t i;
+
+  for (i = 0; i < NGHTTP2_EXTPRI_URGENCY_LEVELS; ++i) {
+    if (!nghttp2_pq_empty(&session->sched[i].ob_data)) {
+      return 0;
+    }
+  }
+
+  return 1;
+}
+
+static void session_sched_reschedule_stream(nghttp2_session *session,
+                                            nghttp2_stream *stream) {
+  nghttp2_pq *pq;
+  uint32_t urgency = nghttp2_extpri_uint8_urgency(stream->extpri);
+  int inc = nghttp2_extpri_uint8_inc(stream->extpri);
+  uint64_t penalty = (uint64_t)stream->last_writelen;
+  int rv;
+
+  (void)rv;
+
+  assert(urgency < NGHTTP2_EXTPRI_URGENCY_LEVELS);
+
+  pq = &session->sched[urgency].ob_data;
+
+  if (!inc || nghttp2_pq_size(pq) == 1) {
+    return;
+  }
+
+  nghttp2_pq_remove(pq, &stream->pq_entry);
+
+  stream->cycle += penalty;
+
+  rv = nghttp2_pq_push(pq, &stream->pq_entry);
+
+  assert(0 == rv);
+}
+
+static int session_update_stream_priority(nghttp2_session *session,
+                                          nghttp2_stream *stream,
+                                          uint8_t u8extpri) {
+  if (stream->extpri == u8extpri) {
+    return 0;
+  }
+
+  if (stream->queued) {
+    session_ob_data_remove(session, stream);
+
+    stream->extpri = u8extpri;
+
+    return session_ob_data_push(session, stream);
+  }
+
+  stream->extpri = u8extpri;
+
+  return 0;
+}
+
 int nghttp2_session_add_item(nghttp2_session *session,
                              nghttp2_outbound_item *item) {
   /* TODO Return error if stream is not found for the frame requiring
@@ -857,7 +1127,7 @@
       return NGHTTP2_ERR_DATA_EXIST;
     }
 
-    rv = nghttp2_stream_attach_item(stream, item);
+    rv = session_attach_stream_item(session, stream, item);
 
     if (rv != 0) {
       return rv;
@@ -953,6 +1223,18 @@
     return 0;
   }
 
+  /* Sending RST_STREAM to an idle stream is subject to protocol
+     violation.  Historically, nghttp2 allows this.  In order not to
+     disrupt the existing applications, we don't error out this case
+     and simply ignore it. */
+  if (nghttp2_session_is_my_stream_id(session, stream_id)) {
+    if ((uint32_t)stream_id >= session->next_stream_id) {
+      return 0;
+    }
+  } else if (session->last_recv_stream_id < stream_id) {
+    return 0;
+  }
+
   /* Cancel pending request HEADERS in ob_syn if this RST_STREAM
      refers to that stream. */
   if (!session->server && nghttp2_session_is_my_stream_id(session, stream_id) &&
@@ -963,8 +1245,7 @@
     headers_frame = &nghttp2_outbound_queue_top(&session->ob_syn)->frame;
     assert(headers_frame->hd.type == NGHTTP2_HEADERS);
 
-    if (headers_frame->hd.stream_id <= stream_id &&
-        (uint32_t)stream_id < session->next_stream_id) {
+    if (headers_frame->hd.stream_id <= stream_id) {
 
       for (item = session->ob_syn.head; item; item = item->qnext) {
         aux_data = &item->aux_data.headers;
@@ -1022,13 +1303,27 @@
   mem = &session->mem;
   stream = nghttp2_session_get_stream_raw(session, stream_id);
 
+  if (session->opt_flags &
+      NGHTTP2_OPTMASK_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) {
+    flags |= NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION;
+  }
+
   if (stream) {
     assert(stream->state == NGHTTP2_STREAM_IDLE);
-    assert(nghttp2_stream_in_dep_tree(stream));
-    nghttp2_session_detach_idle_stream(session, stream);
-    rv = nghttp2_stream_dep_remove(stream);
-    if (rv != 0) {
-      return NULL;
+    assert((stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) ||
+           nghttp2_stream_in_dep_tree(stream));
+
+    if (nghttp2_stream_in_dep_tree(stream)) {
+      assert(!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES));
+      nghttp2_session_detach_idle_stream(session, stream);
+      rv = nghttp2_stream_dep_remove(stream);
+      if (rv != 0) {
+        return NULL;
+      }
+
+      if (session_no_rfc7540_pri_no_fallback(session)) {
+        stream->flags |= NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES;
+      }
     }
   } else {
     stream = nghttp2_mem_malloc(mem, sizeof(nghttp2_stream));
@@ -1039,7 +1334,21 @@
     stream_alloc = 1;
   }
 
-  if (pri_spec->stream_id != 0) {
+  if (session_no_rfc7540_pri_no_fallback(session) ||
+      session->remote_settings.no_rfc7540_priorities == 1) {
+    /* For client which has not received server
+       SETTINGS_NO_RFC7540_PRIORITIES = 1, send a priority signal
+       opportunistically. */
+    if (session->server ||
+        session->remote_settings.no_rfc7540_priorities == 1) {
+      nghttp2_priority_spec_default_init(&pri_spec_default);
+      pri_spec = &pri_spec_default;
+    }
+
+    if (session->pending_no_rfc7540_priorities == 1) {
+      flags |= NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES;
+    }
+  } else if (pri_spec->stream_id != 0) {
     dep_stream = nghttp2_session_get_stream_raw(session, pri_spec->stream_id);
 
     if (!dep_stream &&
@@ -1085,7 +1394,11 @@
                         (int32_t)session->local_settings.initial_window_size,
                         stream_user_data, mem);
 
-    rv = nghttp2_map_insert(&session->streams, &stream->map_entry);
+    if (session_no_rfc7540_pri_no_fallback(session)) {
+      stream->seq = session->stream_seq++;
+    }
+
+    rv = nghttp2_map_insert(&session->streams, stream_id, stream);
     if (rv != 0) {
       nghttp2_stream_free(stream);
       nghttp2_mem_free(mem, stream);
@@ -1124,6 +1437,10 @@
     }
   }
 
+  if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) {
+    return stream;
+  }
+
   if (pri_spec->stream_id == 0) {
     dep_stream = &session->root;
   }
@@ -1163,7 +1480,7 @@
 
     item = stream->item;
 
-    rv = nghttp2_stream_detach_item(stream);
+    rv = session_detach_stream_item(session, stream);
 
     if (rv != 0) {
       return rv;
@@ -1213,6 +1530,10 @@
   /* Closes both directions just in case they are not closed yet */
   stream->flags |= NGHTTP2_STREAM_FLAG_CLOSED;
 
+  if (session->pending_no_rfc7540_priorities == 1) {
+    return nghttp2_session_destroy_stream(session, stream);
+  }
+
   if ((session->opt_flags & NGHTTP2_OPTMASK_NO_CLOSED_STREAMS) == 0 &&
       session->server && !is_my_stream_id &&
       nghttp2_stream_in_dep_tree(stream)) {
@@ -1767,6 +2088,28 @@
   return 0;
 }
 
+static int session_predicate_priority_update_send(nghttp2_session *session,
+                                                  int32_t stream_id) {
+  nghttp2_stream *stream;
+
+  if (session_is_closing(session)) {
+    return NGHTTP2_ERR_SESSION_CLOSING;
+  }
+
+  stream = nghttp2_session_get_stream(session, stream_id);
+  if (stream == NULL) {
+    return 0;
+  }
+  if (stream->state == NGHTTP2_STREAM_CLOSING) {
+    return NGHTTP2_ERR_STREAM_CLOSING;
+  }
+  if (stream->shut_flags & NGHTTP2_SHUT_RD) {
+    return NGHTTP2_ERR_INVALID_STREAM_STATE;
+  }
+
+  return 0;
+}
+
 /* Take into account settings max frame size and both connection-level
    flow control here */
 static ssize_t
@@ -1996,7 +2339,7 @@
       if (stream) {
         int rv2;
 
-        rv2 = nghttp2_stream_detach_item(stream);
+        rv2 = session_detach_stream_item(session, stream);
 
         if (nghttp2_is_fatal(rv2)) {
           return rv2;
@@ -2015,7 +2358,7 @@
          queue when session->remote_window_size > 0 */
       assert(session->remote_window_size > 0);
 
-      rv = nghttp2_stream_defer_item(stream,
+      rv = session_defer_stream_item(session, stream,
                                      NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL);
 
       if (nghttp2_is_fatal(rv)) {
@@ -2034,7 +2377,8 @@
       return rv;
     }
     if (rv == NGHTTP2_ERR_DEFERRED) {
-      rv = nghttp2_stream_defer_item(stream, NGHTTP2_STREAM_FLAG_DEFERRED_USER);
+      rv = session_defer_stream_item(session, stream,
+                                     NGHTTP2_STREAM_FLAG_DEFERRED_USER);
 
       if (nghttp2_is_fatal(rv)) {
         return rv;
@@ -2045,7 +2389,7 @@
       return NGHTTP2_ERR_DEFERRED;
     }
     if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) {
-      rv = nghttp2_stream_detach_item(stream);
+      rv = session_detach_stream_item(session, stream);
 
       if (nghttp2_is_fatal(rv)) {
         return rv;
@@ -2061,7 +2405,7 @@
     if (rv != 0) {
       int rv2;
 
-      rv2 = nghttp2_stream_detach_item(stream);
+      rv2 = session_detach_stream_item(session, stream);
 
       if (nghttp2_is_fatal(rv2)) {
         return rv2;
@@ -2311,6 +2655,18 @@
       }
 
       return 0;
+    case NGHTTP2_PRIORITY_UPDATE: {
+      nghttp2_ext_priority_update *priority_update = frame->ext.payload;
+      rv = session_predicate_priority_update_send(session,
+                                                  priority_update->stream_id);
+      if (rv != 0) {
+        return rv;
+      }
+
+      nghttp2_frame_pack_priority_update(&session->aob.framebufs, &frame->ext);
+
+      return 0;
+    }
     default:
       /* Unreachable here */
       assert(0);
@@ -2322,6 +2678,8 @@
 
 nghttp2_outbound_item *
 nghttp2_session_get_next_ob_item(nghttp2_session *session) {
+  nghttp2_outbound_item *item;
+
   if (nghttp2_outbound_queue_top(&session->ob_urgent)) {
     return nghttp2_outbound_queue_top(&session->ob_urgent);
   }
@@ -2337,7 +2695,12 @@
   }
 
   if (session->remote_window_size > 0) {
-    return nghttp2_stream_next_outbound_item(&session->root);
+    item = nghttp2_stream_next_outbound_item(&session->root);
+    if (item) {
+      return item;
+    }
+
+    return session_sched_get_next_outbound_item(session);
   }
 
   return NULL;
@@ -2371,7 +2734,12 @@
   }
 
   if (session->remote_window_size > 0) {
-    return nghttp2_stream_next_outbound_item(&session->root);
+    item = nghttp2_stream_next_outbound_item(&session->root);
+    if (item) {
+      return item;
+    }
+
+    return session_sched_get_next_outbound_item(session);
   }
 
   return NULL;
@@ -2407,7 +2775,7 @@
   return 0;
 }
 
-static int find_stream_on_goaway_func(nghttp2_map_entry *entry, void *ptr) {
+static int find_stream_on_goaway_func(void *entry, void *ptr) {
   nghttp2_close_stream_on_goaway_arg *arg;
   nghttp2_stream *stream;
 
@@ -2481,10 +2849,20 @@
   return 0;
 }
 
-static void reschedule_stream(nghttp2_stream *stream) {
+static void session_reschedule_stream(nghttp2_session *session,
+                                      nghttp2_stream *stream) {
   stream->last_writelen = stream->item->frame.hd.length;
 
-  nghttp2_stream_reschedule(stream);
+  if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES)) {
+    nghttp2_stream_reschedule(stream);
+    return;
+  }
+
+  if (!session->server) {
+    return;
+  }
+
+  session_sched_reschedule_stream(session, stream);
 }
 
 static int session_update_stream_consumed_size(nghttp2_session *session,
@@ -2494,14 +2872,6 @@
 static int session_update_connection_consumed_size(nghttp2_session *session,
                                                    size_t delta_size);
 
-static int session_update_recv_connection_window_size(nghttp2_session *session,
-                                                      size_t delta_size);
-
-static int session_update_recv_stream_window_size(nghttp2_session *session,
-                                                  nghttp2_stream *stream,
-                                                  size_t delta_size,
-                                                  int send_window_update);
-
 /*
  * Called after a frame is sent.  This function runs
  * on_frame_send_callback and handles stream closure upon END_STREAM
@@ -2541,7 +2911,7 @@
     }
 
     if (stream && aux_data->eof) {
-      rv = nghttp2_stream_detach_item(stream);
+      rv = session_detach_stream_item(session, stream);
       if (nghttp2_is_fatal(rv)) {
         return rv;
       }
@@ -2666,9 +3036,8 @@
     }
   }
   case NGHTTP2_PRIORITY:
-    if (session->server) {
+    if (session->server || session->pending_no_rfc7540_priorities == 1) {
       return 0;
-      ;
     }
 
     stream = nghttp2_session_get_stream_raw(session, frame->hd.stream_id);
@@ -2735,7 +3104,7 @@
       if (session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) {
         rv = session_update_connection_consumed_size(session, 0);
       } else {
-        rv = session_update_recv_connection_window_size(session, 0);
+        rv = nghttp2_session_update_recv_connection_window_size(session, 0);
       }
 
       if (nghttp2_is_fatal(rv)) {
@@ -2761,7 +3130,8 @@
     if (session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) {
       rv = session_update_stream_consumed_size(session, stream, 0);
     } else {
-      rv = session_update_recv_stream_window_size(session, stream, 0, 1);
+      rv =
+          nghttp2_session_update_recv_stream_window_size(session, stream, 0, 1);
     }
 
     if (nghttp2_is_fatal(rv)) {
@@ -2842,7 +3212,7 @@
      further data. */
   if (nghttp2_session_predicate_data_send(session, stream) != 0) {
     if (stream) {
-      rv = nghttp2_stream_detach_item(stream);
+      rv = session_detach_stream_item(session, stream);
 
       if (nghttp2_is_fatal(rv)) {
         return rv;
@@ -3140,7 +3510,7 @@
       }
 
       if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) {
-        rv = nghttp2_stream_detach_item(stream);
+        rv = session_detach_stream_item(session, stream);
 
         if (nghttp2_is_fatal(rv)) {
           return rv;
@@ -3720,6 +4090,21 @@
                                                nghttp2_frame *frame,
                                                nghttp2_stream *stream) {
   int rv;
+
+  assert(frame->hd.type == NGHTTP2_HEADERS);
+
+  if (session->server && session_enforce_http_messaging(session) &&
+      frame->headers.cat == NGHTTP2_HCAT_REQUEST &&
+      (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) &&
+      !(stream->flags & NGHTTP2_STREAM_FLAG_IGNORE_CLIENT_PRIORITIES) &&
+      (stream->http_flags & NGHTTP2_HTTP_FLAG_PRIORITY)) {
+    rv = session_update_stream_priority(session, stream, stream->http_extpri);
+    if (rv != 0) {
+      assert(nghttp2_is_fatal(rv));
+      return rv;
+    }
+  }
+
   if ((frame->hd.flags & NGHTTP2_FLAG_END_STREAM) == 0) {
     return 0;
   }
@@ -4081,6 +4466,8 @@
   int rv;
   nghttp2_stream *stream;
 
+  assert(!session_no_rfc7540_pri_no_fallback(session));
+
   if (frame->hd.stream_id == 0) {
     return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO,
                                              "PRIORITY: stream_id == 0");
@@ -4138,6 +4525,8 @@
   nghttp2_inbound_frame *iframe = &session->iframe;
   nghttp2_frame *frame = &iframe->frame;
 
+  assert(!session_no_rfc7540_pri_no_fallback(session));
+
   nghttp2_frame_unpack_priority_payload(&frame->priority, iframe->sbuf.pos);
 
   return nghttp2_session_on_priority_received(session, frame);
@@ -4184,8 +4573,7 @@
   return nghttp2_session_on_rst_stream_received(session, frame);
 }
 
-static int update_remote_initial_window_size_func(nghttp2_map_entry *entry,
-                                                  void *ptr) {
+static int update_remote_initial_window_size_func(void *entry, void *ptr) {
   int rv;
   nghttp2_update_window_size_arg *arg;
   nghttp2_stream *stream;
@@ -4205,8 +4593,8 @@
   if (stream->remote_window_size > 0 &&
       nghttp2_stream_check_deferred_by_flow_control(stream)) {
 
-    rv = nghttp2_stream_resume_deferred_item(
-        stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL);
+    rv = session_resume_deferred_stream_item(
+        arg->session, stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL);
 
     if (nghttp2_is_fatal(rv)) {
       return rv;
@@ -4238,8 +4626,7 @@
                           update_remote_initial_window_size_func, &arg);
 }
 
-static int update_local_initial_window_size_func(nghttp2_map_entry *entry,
-                                                 void *ptr) {
+static int update_local_initial_window_size_func(void *entry, void *ptr) {
   int rv;
   nghttp2_update_window_size_arg *arg;
   nghttp2_stream *stream;
@@ -4251,9 +4638,16 @@
     return nghttp2_session_add_rst_stream(arg->session, stream->stream_id,
                                           NGHTTP2_FLOW_CONTROL_ERROR);
   }
-  if (!(arg->session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) &&
-      stream->window_update_queued == 0 &&
-      nghttp2_should_send_window_update(stream->local_window_size,
+
+  if (stream->window_update_queued) {
+    return 0;
+  }
+
+  if (arg->session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) {
+    return session_update_stream_consumed_size(arg->session, stream, 0);
+  }
+
+  if (nghttp2_should_send_window_update(stream->local_window_size,
                                         stream->recv_window_size)) {
 
     rv = nghttp2_session_add_window_update(arg->session, NGHTTP2_FLAG_NONE,
@@ -4374,6 +4768,9 @@
     case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL:
       session->local_settings.enable_connect_protocol = iv[i].value;
       break;
+    case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES:
+      session->local_settings.no_rfc7540_priorities = iv[i].value;
+      break;
     }
   }
 
@@ -4533,6 +4930,34 @@
       session->remote_settings.enable_connect_protocol = entry->value;
 
       break;
+    case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES:
+
+      if (entry->value != 0 && entry->value != 1) {
+        return session_handle_invalid_connection(
+            session, frame, NGHTTP2_ERR_PROTO,
+            "SETTINGS: invalid SETTINGS_NO_RFC7540_PRIORITIES");
+      }
+
+      if (session->remote_settings.no_rfc7540_priorities != UINT32_MAX &&
+          session->remote_settings.no_rfc7540_priorities != entry->value) {
+        return session_handle_invalid_connection(
+            session, frame, NGHTTP2_ERR_PROTO,
+            "SETTINGS: SETTINGS_NO_RFC7540_PRIORITIES cannot be changed");
+      }
+
+      session->remote_settings.no_rfc7540_priorities = entry->value;
+
+      break;
+    }
+  }
+
+  if (session->remote_settings.no_rfc7540_priorities == UINT32_MAX) {
+    session->remote_settings.no_rfc7540_priorities = 0;
+
+    if (session->server && session->pending_no_rfc7540_priorities &&
+        (session->opt_flags &
+         NGHTTP2_OPTMASK_SERVER_FALLBACK_RFC7540_PRIORITIES)) {
+      session->fallback_rfc7540_priorities = 1;
     }
   }
 
@@ -4818,8 +5243,8 @@
   if (stream->remote_window_size > 0 &&
       nghttp2_stream_check_deferred_by_flow_control(stream)) {
 
-    rv = nghttp2_stream_resume_deferred_item(
-        stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL);
+    rv = session_resume_deferred_stream_item(
+        session, stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL);
 
     if (nghttp2_is_fatal(rv)) {
       return rv;
@@ -4890,6 +5315,80 @@
   return session_call_on_frame_received(session, frame);
 }
 
+int nghttp2_session_on_priority_update_received(nghttp2_session *session,
+                                                nghttp2_frame *frame) {
+  nghttp2_ext_priority_update *priority_update;
+  nghttp2_stream *stream;
+  nghttp2_priority_spec pri_spec;
+  nghttp2_extpri extpri;
+  int rv;
+
+  assert(session->server);
+
+  priority_update = frame->ext.payload;
+
+  if (frame->hd.stream_id != 0) {
+    return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO,
+                                             "PRIORITY_UPDATE: stream_id == 0");
+  }
+
+  if (nghttp2_session_is_my_stream_id(session, priority_update->stream_id)) {
+    if (session_detect_idle_stream(session, priority_update->stream_id)) {
+      return session_handle_invalid_connection(
+          session, frame, NGHTTP2_ERR_PROTO,
+          "PRIORITY_UPDATE: prioritizing idle push is not allowed");
+    }
+
+    /* TODO Ignore priority signal to a push stream for now */
+    return session_call_on_frame_received(session, frame);
+  }
+
+  stream = nghttp2_session_get_stream_raw(session, priority_update->stream_id);
+  if (stream) {
+    /* Stream already exists. */
+    if (stream->flags & NGHTTP2_STREAM_FLAG_IGNORE_CLIENT_PRIORITIES) {
+      return session_call_on_frame_received(session, frame);
+    }
+  } else if (session_detect_idle_stream(session, priority_update->stream_id)) {
+    if (session->num_idle_streams + session->num_incoming_streams >=
+        session->local_settings.max_concurrent_streams) {
+      return session_handle_invalid_connection(
+          session, frame, NGHTTP2_ERR_PROTO,
+          "PRIORITY_UPDATE: max concurrent streams exceeded");
+    }
+
+    nghttp2_priority_spec_default_init(&pri_spec);
+    stream = nghttp2_session_open_stream(session, priority_update->stream_id,
+                                         NGHTTP2_FLAG_NONE, &pri_spec,
+                                         NGHTTP2_STREAM_IDLE, NULL);
+    if (!stream) {
+      return NGHTTP2_ERR_NOMEM;
+    }
+  } else {
+    return session_call_on_frame_received(session, frame);
+  }
+
+  extpri.urgency = NGHTTP2_EXTPRI_DEFAULT_URGENCY;
+  extpri.inc = 0;
+
+  rv = nghttp2_http_parse_priority(&extpri, priority_update->field_value,
+                                   priority_update->field_value_len);
+  if (rv != 0) {
+    /* Just ignore field_value if it cannot be parsed. */
+    return session_call_on_frame_received(session, frame);
+  }
+
+  rv = session_update_stream_priority(session, stream,
+                                      nghttp2_extpri_to_uint8(&extpri));
+  if (rv != 0) {
+    if (nghttp2_is_fatal(rv)) {
+      return rv;
+    }
+  }
+
+  return session_call_on_frame_received(session, frame);
+}
+
 static int session_process_altsvc_frame(nghttp2_session *session) {
   nghttp2_inbound_frame *iframe = &session->iframe;
   nghttp2_frame *frame = &iframe->frame;
@@ -4924,6 +5423,16 @@
   return nghttp2_session_on_origin_received(session, frame);
 }
 
+static int session_process_priority_update_frame(nghttp2_session *session) {
+  nghttp2_inbound_frame *iframe = &session->iframe;
+  nghttp2_frame *frame = &iframe->frame;
+
+  nghttp2_frame_unpack_priority_update_payload(&frame->ext, iframe->sbuf.pos,
+                                               nghttp2_buf_len(&iframe->sbuf));
+
+  return nghttp2_session_on_priority_update_received(session, frame);
+}
+
 static int session_process_extension_frame(nghttp2_session *session) {
   int rv;
   nghttp2_inbound_frame *iframe = &session->iframe;
@@ -5019,22 +5528,10 @@
   return 0;
 }
 
-/*
- * Accumulates received bytes |delta_size| for stream-level flow
- * control and decides whether to send WINDOW_UPDATE to that stream.
- * If NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE is set, WINDOW_UPDATE will not
- * be sent.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGHTTP2_ERR_NOMEM
- *     Out of memory.
- */
-static int session_update_recv_stream_window_size(nghttp2_session *session,
-                                                  nghttp2_stream *stream,
-                                                  size_t delta_size,
-                                                  int send_window_update) {
+int nghttp2_session_update_recv_stream_window_size(nghttp2_session *session,
+                                                   nghttp2_stream *stream,
+                                                   size_t delta_size,
+                                                   int send_window_update) {
   int rv;
   rv = adjust_recv_window_size(&stream->recv_window_size, delta_size,
                                stream->local_window_size);
@@ -5063,20 +5560,8 @@
   return 0;
 }
 
-/*
- * Accumulates received bytes |delta_size| for connection-level flow
- * control and decides whether to send WINDOW_UPDATE to the
- * connection.  If NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE is set,
- * WINDOW_UPDATE will not be sent.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGHTTP2_ERR_NOMEM
- *     Out of memory.
- */
-static int session_update_recv_connection_window_size(nghttp2_session *session,
-                                                      size_t delta_size) {
+int nghttp2_session_update_recv_connection_window_size(nghttp2_session *session,
+                                                       size_t delta_size) {
   int rv;
   rv = adjust_recv_window_size(&session->recv_window_size, delta_size,
                                session->local_window_size);
@@ -5285,6 +5770,7 @@
   case NGHTTP2_SETTINGS_MAX_FRAME_SIZE:
   case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE:
   case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL:
+  case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES:
     break;
   default:
     DEBUGF("recv: unknown settings id=0x%02x\n", iv.settings_id);
@@ -5357,7 +5843,7 @@
 
 /*
  * This function returns the effective payload length in the data of
- * length |readlen| when the remaning payload is |payloadleft|. The
+ * length |readlen| when the remaining payload is |payloadleft|. The
  * |payloadleft| does not include |readlen|. If padding was started
  * strictly before this data chunk, this function returns -1.
  */
@@ -5378,9 +5864,11 @@
   return (ssize_t)(readlen);
 }
 
+static const uint8_t static_in[] = {0};
+
 ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
                                  size_t inlen) {
-  const uint8_t *first = in, *last = in + inlen;
+  const uint8_t *first, *last;
   nghttp2_inbound_frame *iframe = &session->iframe;
   size_t readlen;
   ssize_t padlen;
@@ -5391,6 +5879,14 @@
   size_t pri_fieldlen;
   nghttp2_mem *mem;
 
+  if (in == NULL) {
+    assert(inlen == 0);
+    in = static_in;
+  }
+
+  first = in;
+  last = in + inlen;
+
   DEBUGF("recv: connection recv_window_size=%d, local_window=%d\n",
          session->recv_window_size, session->local_window_size);
 
@@ -5678,6 +6174,12 @@
           break;
         }
 
+        /* Check the settings flood counter early to be safe */
+        if (session->obq_flood_counter_ >= session->max_outbound_ack &&
+            !(iframe->frame.hd.flags & NGHTTP2_FLAG_ACK)) {
+          return NGHTTP2_ERR_FLOODED;
+        }
+
         iframe->state = NGHTTP2_IB_READ_SETTINGS;
 
         if (iframe->payloadleft) {
@@ -5688,6 +6190,16 @@
           iframe->max_niv =
               iframe->frame.hd.length / NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH + 1;
 
+          if (iframe->max_niv - 1 > session->max_settings) {
+            rv = nghttp2_session_terminate_session_with_reason(
+                session, NGHTTP2_ENHANCE_YOUR_CALM,
+                "SETTINGS: too many setting entries");
+            if (nghttp2_is_fatal(rv)) {
+              return rv;
+            }
+            return (ssize_t)inlen;
+          }
+
           iframe->iv = nghttp2_mem_malloc(mem, sizeof(nghttp2_settings_entry) *
                                                    iframe->max_niv);
 
@@ -5873,6 +6385,49 @@
             iframe->state = NGHTTP2_IB_READ_ORIGIN_PAYLOAD;
 
             break;
+          case NGHTTP2_PRIORITY_UPDATE:
+            if ((session->builtin_recv_ext_types &
+                 NGHTTP2_TYPEMASK_PRIORITY_UPDATE) == 0) {
+              busy = 1;
+              iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
+              break;
+            }
+
+            DEBUGF("recv: PRIORITY_UPDATE\n");
+
+            iframe->frame.hd.flags = NGHTTP2_FLAG_NONE;
+            iframe->frame.ext.payload =
+                &iframe->ext_frame_payload.priority_update;
+
+            if (!session->server) {
+              rv = nghttp2_session_terminate_session_with_reason(
+                  session, NGHTTP2_PROTOCOL_ERROR,
+                  "PRIORITY_UPDATE is received from server");
+              if (nghttp2_is_fatal(rv)) {
+                return rv;
+              }
+              return (ssize_t)inlen;
+            }
+
+            if (iframe->payloadleft < 4) {
+              busy = 1;
+              iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR;
+              break;
+            }
+
+            if (!session_no_rfc7540_pri_no_fallback(session) ||
+                iframe->payloadleft > sizeof(iframe->raw_sbuf)) {
+              busy = 1;
+              iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
+              break;
+            }
+
+            busy = 1;
+
+            iframe->state = NGHTTP2_IB_READ_NBYTE;
+            inbound_frame_set_mark(iframe, iframe->payloadleft);
+
+            break;
           default:
             busy = 1;
 
@@ -5978,13 +6533,16 @@
 
         break;
       case NGHTTP2_PRIORITY:
-        rv = session_process_priority_frame(session);
-        if (nghttp2_is_fatal(rv)) {
-          return rv;
-        }
+        if (!session_no_rfc7540_pri_no_fallback(session) &&
+            session->remote_settings.no_rfc7540_priorities != 1) {
+          rv = session_process_priority_frame(session);
+          if (nghttp2_is_fatal(rv)) {
+            return rv;
+          }
 
-        if (iframe->state == NGHTTP2_IB_IGN_ALL) {
-          return (ssize_t)inlen;
+          if (iframe->state == NGHTTP2_IB_IGN_ALL) {
+            return (ssize_t)inlen;
+          }
         }
 
         session_inbound_frame_reset(session);
@@ -6141,6 +6699,18 @@
         iframe->state = NGHTTP2_IB_READ_ALTSVC_PAYLOAD;
 
         break;
+      case NGHTTP2_PRIORITY_UPDATE:
+        DEBUGF("recv: prioritized_stream_id=%d\n",
+               nghttp2_get_uint32(iframe->sbuf.pos) & NGHTTP2_STREAM_ID_MASK);
+
+        rv = session_process_priority_update_frame(session);
+        if (nghttp2_is_fatal(rv)) {
+          return rv;
+        }
+
+        session_inbound_frame_reset(session);
+
+        break;
       }
       default:
         /* This is unknown frame */
@@ -6420,8 +6990,9 @@
 
       /* CONTINUATION won't bear NGHTTP2_PADDED flag */
 
-      iframe->frame.hd.flags = (uint8_t)(
-          iframe->frame.hd.flags | (cont_hd.flags & NGHTTP2_FLAG_END_HEADERS));
+      iframe->frame.hd.flags =
+          (uint8_t)(iframe->frame.hd.flags |
+                    (cont_hd.flags & NGHTTP2_FLAG_END_HEADERS));
       iframe->frame.hd.length += cont_hd.length;
 
       busy = 1;
@@ -6454,7 +7025,7 @@
       }
 
       /* Pad Length field is subject to flow control */
-      rv = session_update_recv_connection_window_size(session, readlen);
+      rv = nghttp2_session_update_recv_connection_window_size(session, readlen);
       if (nghttp2_is_fatal(rv)) {
         return rv;
       }
@@ -6477,7 +7048,7 @@
 
       stream = nghttp2_session_get_stream(session, iframe->frame.hd.stream_id);
       if (stream) {
-        rv = session_update_recv_stream_window_size(
+        rv = nghttp2_session_update_recv_stream_window_size(
             session, stream, readlen,
             iframe->payloadleft ||
                 (iframe->frame.hd.flags & NGHTTP2_FLAG_END_STREAM) == 0);
@@ -6524,7 +7095,8 @@
       if (readlen > 0) {
         ssize_t data_readlen;
 
-        rv = session_update_recv_connection_window_size(session, readlen);
+        rv = nghttp2_session_update_recv_connection_window_size(session,
+                                                                readlen);
         if (nghttp2_is_fatal(rv)) {
           return rv;
         }
@@ -6533,7 +7105,7 @@
           return (ssize_t)inlen;
         }
 
-        rv = session_update_recv_stream_window_size(
+        rv = nghttp2_session_update_recv_stream_window_size(
             session, stream, readlen,
             iframe->payloadleft ||
                 (iframe->frame.hd.flags & NGHTTP2_FLAG_END_STREAM) == 0);
@@ -6634,7 +7206,8 @@
       if (readlen > 0) {
         /* Update connection-level flow control window for ignored
            DATA frame too */
-        rv = session_update_recv_connection_window_size(session, readlen);
+        rv = nghttp2_session_update_recv_connection_window_size(session,
+                                                                readlen);
         if (nghttp2_is_fatal(rv)) {
           return rv;
         }
@@ -6850,7 +7423,8 @@
    */
   return session->aob.item || nghttp2_outbound_queue_top(&session->ob_urgent) ||
          nghttp2_outbound_queue_top(&session->ob_reg) ||
-         (!nghttp2_pq_empty(&session->root.obq) &&
+         ((!nghttp2_pq_empty(&session->root.obq) ||
+           !session_sched_empty(session)) &&
           session->remote_window_size > 0) ||
          (nghttp2_outbound_queue_top(&session->ob_syn) &&
           !session_is_outgoing_concurrent_streams_max(session));
@@ -7003,6 +7577,7 @@
   int rv;
   nghttp2_mem *mem;
   nghttp2_inflight_settings *inflight_settings = NULL;
+  uint8_t no_rfc7540_pri = session->pending_no_rfc7540_priorities;
 
   mem = &session->mem;
 
@@ -7020,6 +7595,21 @@
     return NGHTTP2_ERR_INVALID_ARGUMENT;
   }
 
+  for (i = 0; i < niv; ++i) {
+    if (iv[i].settings_id != NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES) {
+      continue;
+    }
+
+    if (no_rfc7540_pri == UINT8_MAX) {
+      no_rfc7540_pri = (uint8_t)iv[i].value;
+      continue;
+    }
+
+    if (iv[i].value != (uint32_t)no_rfc7540_pri) {
+      return NGHTTP2_ERR_INVALID_ARGUMENT;
+    }
+  }
+
   item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
   if (item == NULL) {
     return NGHTTP2_ERR_NOMEM;
@@ -7094,6 +7684,12 @@
     }
   }
 
+  if (no_rfc7540_pri == UINT8_MAX) {
+    session->pending_no_rfc7540_priorities = 0;
+  } else {
+    session->pending_no_rfc7540_priorities = no_rfc7540_pri;
+  }
+
   return 0;
 }
 
@@ -7222,7 +7818,7 @@
     return rv;
   }
 
-  reschedule_stream(stream);
+  session_reschedule_stream(session, stream);
 
   if (frame->hd.length == 0 && (data_flags & NGHTTP2_DATA_FLAG_EOF) &&
       (data_flags & NGHTTP2_DATA_FLAG_NO_END_STREAM)) {
@@ -7296,7 +7892,7 @@
     return NGHTTP2_ERR_INVALID_ARGUMENT;
   }
 
-  rv = nghttp2_stream_resume_deferred_item(stream,
+  rv = session_resume_deferred_stream_item(session, stream,
                                            NGHTTP2_STREAM_FLAG_DEFERRED_USER);
 
   if (nghttp2_is_fatal(rv)) {
@@ -7404,6 +8000,8 @@
     return session->remote_settings.max_header_list_size;
   case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL:
     return session->remote_settings.enable_connect_protocol;
+  case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES:
+    return session->remote_settings.no_rfc7540_priorities;
   }
 
   assert(0);
@@ -7427,6 +8025,8 @@
     return session->local_settings.max_header_list_size;
   case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL:
     return session->local_settings.enable_connect_protocol;
+  case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES:
+    return session->local_settings.no_rfc7540_priorities;
   }
 
   assert(0);
@@ -7454,6 +8054,11 @@
   if (settings_payloadlen % NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH) {
     return NGHTTP2_ERR_INVALID_ARGUMENT;
   }
+  /* SETTINGS frame contains too many settings */
+  if (settings_payloadlen / NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH >
+      session->max_settings) {
+    return NGHTTP2_ERR_TOO_MANY_SETTINGS;
+  }
   rv = nghttp2_frame_unpack_settings_payload2(&iv, &niv, settings_payload,
                                               settings_payloadlen, mem);
   if (rv != 0) {
@@ -7705,6 +8310,10 @@
   nghttp2_stream *stream;
   nghttp2_priority_spec pri_spec_copy;
 
+  if (session->pending_no_rfc7540_priorities == 1) {
+    return 0;
+  }
+
   if (stream_id == 0 || stream_id == pri_spec->stream_id) {
     return NGHTTP2_ERR_INVALID_ARGUMENT;
   }
@@ -7737,6 +8346,10 @@
   nghttp2_stream *stream;
   nghttp2_priority_spec pri_spec_copy;
 
+  if (session->pending_no_rfc7540_priorities == 1) {
+    return 0;
+  }
+
   if (stream_id == 0 || stream_id == pri_spec->stream_id ||
       !session_detect_idle_stream(session, stream_id)) {
     return NGHTTP2_ERR_INVALID_ARGUMENT;
@@ -7778,3 +8391,38 @@
 void nghttp2_session_set_user_data(nghttp2_session *session, void *user_data) {
   session->user_data = user_data;
 }
+
+int nghttp2_session_change_extpri_stream_priority(
+    nghttp2_session *session, int32_t stream_id,
+    const nghttp2_extpri *extpri_in, int ignore_client_signal) {
+  nghttp2_stream *stream;
+  nghttp2_extpri extpri = *extpri_in;
+
+  if (!session->server) {
+    return NGHTTP2_ERR_INVALID_STATE;
+  }
+
+  if (session->pending_no_rfc7540_priorities != 1) {
+    return 0;
+  }
+
+  if (stream_id == 0) {
+    return NGHTTP2_ERR_INVALID_ARGUMENT;
+  }
+
+  stream = nghttp2_session_get_stream_raw(session, stream_id);
+  if (!stream) {
+    return NGHTTP2_ERR_INVALID_ARGUMENT;
+  }
+
+  if (extpri.urgency > NGHTTP2_EXTPRI_URGENCY_LOW) {
+    extpri.urgency = NGHTTP2_EXTPRI_URGENCY_LOW;
+  }
+
+  if (ignore_client_signal) {
+    stream->flags |= NGHTTP2_STREAM_FLAG_IGNORE_CLIENT_PRIORITIES;
+  }
+
+  return session_update_stream_priority(session, stream,
+                                        nghttp2_extpri_to_uint8(&extpri));
+}
diff --git a/Utilities/cmnghttp2/lib/nghttp2_session.h b/Utilities/cmnghttp2/lib/nghttp2_session.h
index 90ead9c..34d2d58 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_session.h
+++ b/Utilities/cmnghttp2/lib/nghttp2_session.h
@@ -52,7 +52,9 @@
   NGHTTP2_OPTMASK_NO_RECV_CLIENT_MAGIC = 1 << 1,
   NGHTTP2_OPTMASK_NO_HTTP_MESSAGING = 1 << 2,
   NGHTTP2_OPTMASK_NO_AUTO_PING_ACK = 1 << 3,
-  NGHTTP2_OPTMASK_NO_CLOSED_STREAMS = 1 << 4
+  NGHTTP2_OPTMASK_NO_CLOSED_STREAMS = 1 << 4,
+  NGHTTP2_OPTMASK_SERVER_FALLBACK_RFC7540_PRIORITIES = 1 << 5,
+  NGHTTP2_OPTMASK_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION = 1 << 6,
 } nghttp2_optmask;
 
 /*
@@ -62,7 +64,8 @@
 typedef enum {
   NGHTTP2_TYPEMASK_NONE = 0,
   NGHTTP2_TYPEMASK_ALTSVC = 1 << 0,
-  NGHTTP2_TYPEMASK_ORIGIN = 1 << 1
+  NGHTTP2_TYPEMASK_ORIGIN = 1 << 1,
+  NGHTTP2_TYPEMASK_PRIORITY_UPDATE = 1 << 2
 } nghttp2_typemask;
 
 typedef enum {
@@ -151,10 +154,8 @@
   /* padding length for the current frame */
   size_t padlen;
   nghttp2_inbound_state state;
-  /* Small buffer.  Currently the largest contiguous chunk to buffer
-     is frame header.  We buffer part of payload, but they are smaller
-     than frame header. */
-  uint8_t raw_sbuf[NGHTTP2_FRAME_HDLEN];
+  /* Small fixed sized buffer. */
+  uint8_t raw_sbuf[32];
 } nghttp2_inbound_frame;
 
 typedef struct {
@@ -165,6 +166,7 @@
   uint32_t max_frame_size;
   uint32_t max_header_list_size;
   uint32_t enable_connect_protocol;
+  uint32_t no_rfc7540_priorities;
 } nghttp2_settings_storage;
 
 typedef enum {
@@ -202,6 +204,12 @@
      response) frame, which are subject to
      SETTINGS_MAX_CONCURRENT_STREAMS limit. */
   nghttp2_outbound_queue ob_syn;
+  /* Queues for DATA frames which is used when
+     SETTINGS_NO_RFC7540_PRIORITIES is enabled.  This implements RFC
+     9218 extensible prioritization scheme. */
+  struct {
+    nghttp2_pq ob_data;
+  } sched[NGHTTP2_EXTPRI_URGENCY_LEVELS];
   nghttp2_active_outbound_item aob;
   nghttp2_inbound_frame iframe;
   nghttp2_hd_deflater hd_deflater;
@@ -227,6 +235,9 @@
   /* Queue of In-flight SETTINGS values.  SETTINGS bearing ACK is not
      considered as in-flight. */
   nghttp2_inflight_settings *inflight_settings_head;
+  /* Sequential number across all streams to process streams in
+     FIFO. */
+  uint64_t stream_seq;
   /* The number of outgoing streams. This will be capped by
      remote_settings.max_concurrent_streams. */
   size_t num_outgoing_streams;
@@ -267,6 +278,8 @@
   /* The maximum length of header block to send.  Calculated by the
      same way as nghttp2_hd_deflate_bound() does. */
   size_t max_send_header_block_length;
+  /* The maximum number of settings accepted per SETTINGS frame. */
+  size_t max_settings;
   /* Next Stream ID. Made unsigned int to detect >= (1 << 31). */
   uint32_t next_stream_id;
   /* The last stream ID this session initiated.  For client session,
@@ -326,6 +339,11 @@
   /* Unacked local ENABLE_CONNECT_PROTOCOL value.  We use this to
      accept :protocol header field before SETTINGS_ACK is received. */
   uint8_t pending_enable_connect_protocol;
+  /* Unacked local SETTINGS_NO_RFC7540_PRIORITIES value, which is
+     effective before it is acknowledged. */
+  uint8_t pending_no_rfc7540_priorities;
+  /* Turn on fallback to RFC 7540 priorities; for server use only. */
+  uint8_t fallback_rfc7540_priorities;
   /* Nonzero if the session is server side. */
   uint8_t server;
   /* Flags indicating GOAWAY is sent and/or received. The flags are
@@ -406,7 +424,7 @@
                                    uint32_t error_code);
 
 /*
- * Adds PING frame. This is a convenient functin built on top of
+ * Adds PING frame. This is a convenient function built on top of
  * nghttp2_session_add_frame() to add PING easily.
  *
  * If the |opaque_data| is not NULL, it must point to 8 bytes memory
@@ -772,6 +790,19 @@
                                        nghttp2_frame *frame);
 
 /*
+ * Called when PRIORITY_UPDATE is received, assuming |frame| is
+ * properly initialized.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_CALLBACK_FAILURE
+ *     The callback function failed.
+ */
+int nghttp2_session_on_priority_update_received(nghttp2_session *session,
+                                                nghttp2_frame *frame);
+
+/*
  * Called when DATA is received, assuming |frame| is properly
  * initialized.
  *
@@ -898,4 +929,36 @@
                                                   uint32_t error_code,
                                                   const char *reason);
 
+/*
+ * Accumulates received bytes |delta_size| for connection-level flow
+ * control and decides whether to send WINDOW_UPDATE to the
+ * connection.  If NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE is set,
+ * WINDOW_UPDATE will not be sent.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ */
+int nghttp2_session_update_recv_connection_window_size(nghttp2_session *session,
+                                                       size_t delta_size);
+
+/*
+ * Accumulates received bytes |delta_size| for stream-level flow
+ * control and decides whether to send WINDOW_UPDATE to that stream.
+ * If NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE is set, WINDOW_UPDATE will not
+ * be sent.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ */
+int nghttp2_session_update_recv_stream_window_size(nghttp2_session *session,
+                                                   nghttp2_stream *stream,
+                                                   size_t delta_size,
+                                                   int send_window_update);
+
 #endif /* NGHTTP2_SESSION_H */
diff --git a/Utilities/cmnghttp2/lib/nghttp2_stream.c b/Utilities/cmnghttp2/lib/nghttp2_stream.c
index dc3a6b1..b3614a0 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_stream.c
+++ b/Utilities/cmnghttp2/lib/nghttp2_stream.c
@@ -33,7 +33,7 @@
 #include "nghttp2_frame.h"
 
 /* Maximum distance between any two stream's cycle in the same
-   prirority queue.  Imagine stream A's cycle is A, and stream B's
+   priority queue.  Imagine stream A's cycle is A, and stream B's
    cycle is B, and A < B.  The cycle is unsigned 32 bit integer, it
    may get overflow.  Because of how we calculate the next cycle
    value, if B - A is less than or equals to
@@ -62,7 +62,6 @@
                          int32_t weight, int32_t remote_initial_window_size,
                          int32_t local_initial_window_size,
                          void *stream_user_data, nghttp2_mem *mem) {
-  nghttp2_map_entry_init(&stream->map_entry, (key_type)stream_id);
   nghttp2_pq_init(&stream->obq, stream_less, mem);
 
   stream->stream_id = stream_id;
@@ -101,6 +100,8 @@
   stream->descendant_next_seq = 0;
   stream->seq = 0;
   stream->last_writelen = 0;
+
+  stream->extpri = stream->http_extpri = NGHTTP2_EXTPRI_DEFAULT_URGENCY;
 }
 
 void nghttp2_stream_free(nghttp2_stream *stream) {
@@ -485,6 +486,10 @@
 
   stream->item = item;
 
+  if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) {
+    return 0;
+  }
+
   rv = stream_update_dep_on_attach_item(stream);
   if (rv != 0) {
     /* This may relave stream->queued == 1, but stream->item == NULL.
@@ -504,6 +509,10 @@
   stream->item = NULL;
   stream->flags = (uint8_t)(stream->flags & ~NGHTTP2_STREAM_FLAG_DEFERRED_ALL);
 
+  if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) {
+    return 0;
+  }
+
   return stream_update_dep_on_detach_item(stream);
 }
 
@@ -515,6 +524,10 @@
 
   stream->flags |= flags;
 
+  if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) {
+    return 0;
+  }
+
   return stream_update_dep_on_detach_item(stream);
 }
 
@@ -530,6 +543,10 @@
     return 0;
   }
 
+  if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) {
+    return 0;
+  }
+
   return stream_update_dep_on_attach_item(stream);
 }
 
diff --git a/Utilities/cmnghttp2/lib/nghttp2_stream.h b/Utilities/cmnghttp2/lib/nghttp2_stream.h
index a1b807d..7a8e4c6 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_stream.h
+++ b/Utilities/cmnghttp2/lib/nghttp2_stream.h
@@ -90,8 +90,15 @@
   NGHTTP2_STREAM_FLAG_DEFERRED_USER = 0x08,
   /* bitwise OR of NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL and
      NGHTTP2_STREAM_FLAG_DEFERRED_USER. */
-  NGHTTP2_STREAM_FLAG_DEFERRED_ALL = 0x0c
-
+  NGHTTP2_STREAM_FLAG_DEFERRED_ALL = 0x0c,
+  /* Indicates that this stream is not subject to RFC7540
+     priorities scheme. */
+  NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES = 0x10,
+  /* Ignore client RFC 9218 priority signal. */
+  NGHTTP2_STREAM_FLAG_IGNORE_CLIENT_PRIORITIES = 0x20,
+  /* Indicates that RFC 9113 leading and trailing white spaces
+     validation against a field value is not performed. */
+  NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION = 0x40,
 } nghttp2_stream_flag;
 
 /* HTTP related flags to enforce HTTP semantics */
@@ -132,11 +139,14 @@
   /* set if final response is expected */
   NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE = 1 << 14,
   NGHTTP2_HTTP_FLAG__PROTOCOL = 1 << 15,
+  /* set if priority header field is received */
+  NGHTTP2_HTTP_FLAG_PRIORITY = 1 << 16,
+  /* set if an error is encountered while parsing priority header
+     field */
+  NGHTTP2_HTTP_FLAG_BAD_PRIORITY = 1 << 17,
 } nghttp2_http_flag;
 
 struct nghttp2_stream {
-  /* Intrusive Map */
-  nghttp2_map_entry map_entry;
   /* Entry for dep_prev->obq */
   nghttp2_pq_entry pq_entry;
   /* Priority Queue storing direct descendant (nghttp2_stream).  Only
@@ -206,7 +216,7 @@
   /* status code from remote server */
   int16_t status_code;
   /* Bitwise OR of zero or more nghttp2_http_flag values */
-  uint16_t http_flags;
+  uint32_t http_flags;
   /* This is bitwise-OR of 0 or more of nghttp2_stream_flag. */
   uint8_t flags;
   /* Bitwise OR of zero or more nghttp2_shut_flag values */
@@ -220,6 +230,12 @@
      this stream.  The nonzero does not necessarily mean WINDOW_UPDATE
      is not queued. */
   uint8_t window_update_queued;
+  /* extpri is a stream priority produced by nghttp2_extpri_to_uint8
+     used by RFC 9218 extensible priorities. */
+  uint8_t extpri;
+  /* http_extpri is a stream priority received in HTTP request header
+     fields and produced by nghttp2_extpri_to_uint8. */
+  uint8_t http_extpri;
 };
 
 void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
diff --git a/Utilities/cmnghttp2/lib/nghttp2_submit.c b/Utilities/cmnghttp2/lib/nghttp2_submit.c
index f604eff..f5554eb 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_submit.c
+++ b/Utilities/cmnghttp2/lib/nghttp2_submit.c
@@ -196,7 +196,8 @@
 
   flags &= NGHTTP2_FLAG_END_STREAM;
 
-  if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec)) {
+  if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec) &&
+      session->remote_settings.no_rfc7540_priorities != 1) {
     rv = detect_self_dependency(session, stream_id, pri_spec);
     if (rv != 0) {
       return rv;
@@ -229,6 +230,10 @@
 
   mem = &session->mem;
 
+  if (session->remote_settings.no_rfc7540_priorities == 1) {
+    return 0;
+  }
+
   if (stream_id == 0 || pri_spec == NULL) {
     return NGHTTP2_ERR_INVALID_ARGUMENT;
   }
@@ -450,6 +455,13 @@
     if (rv != 0) {
       return rv;
     }
+
+    if (window_size_increment > 0) {
+      return nghttp2_session_add_window_update(session, 0, stream_id,
+                                               window_size_increment);
+    }
+
+    return nghttp2_session_update_recv_connection_window_size(session, 0);
   } else {
     stream = nghttp2_session_get_stream(session, stream_id);
 
@@ -476,14 +488,15 @@
     if (rv != 0) {
       return rv;
     }
-  }
 
-  if (window_size_increment > 0) {
-    return nghttp2_session_add_window_update(session, 0, stream_id,
-                                             window_size_increment);
-  }
+    if (window_size_increment > 0) {
+      return nghttp2_session_add_window_update(session, 0, stream_id,
+                                               window_size_increment);
+    }
 
-  return 0;
+    return nghttp2_session_update_recv_stream_window_size(session, stream, 0,
+                                                          1);
+  }
 }
 
 int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags,
@@ -654,6 +667,78 @@
   return rv;
 }
 
+int nghttp2_submit_priority_update(nghttp2_session *session, uint8_t flags,
+                                   int32_t stream_id,
+                                   const uint8_t *field_value,
+                                   size_t field_value_len) {
+  nghttp2_mem *mem;
+  uint8_t *buf, *p;
+  nghttp2_outbound_item *item;
+  nghttp2_frame *frame;
+  nghttp2_ext_priority_update *priority_update;
+  int rv;
+  (void)flags;
+
+  mem = &session->mem;
+
+  if (session->server) {
+    return NGHTTP2_ERR_INVALID_STATE;
+  }
+
+  if (session->remote_settings.no_rfc7540_priorities == 0) {
+    return 0;
+  }
+
+  if (stream_id == 0 || 4 + field_value_len > NGHTTP2_MAX_PAYLOADLEN) {
+    return NGHTTP2_ERR_INVALID_ARGUMENT;
+  }
+
+  if (field_value_len) {
+    buf = nghttp2_mem_malloc(mem, field_value_len + 1);
+    if (buf == NULL) {
+      return NGHTTP2_ERR_NOMEM;
+    }
+
+    p = nghttp2_cpymem(buf, field_value, field_value_len);
+    *p = '\0';
+  } else {
+    buf = NULL;
+  }
+
+  item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
+  if (item == NULL) {
+    rv = NGHTTP2_ERR_NOMEM;
+    goto fail_item_malloc;
+  }
+
+  nghttp2_outbound_item_init(item);
+
+  item->aux_data.ext.builtin = 1;
+
+  priority_update = &item->ext_frame_payload.priority_update;
+
+  frame = &item->frame;
+  frame->ext.payload = priority_update;
+
+  nghttp2_frame_priority_update_init(&frame->ext, stream_id, buf,
+                                     field_value_len);
+
+  rv = nghttp2_session_add_item(session, item);
+  if (rv != 0) {
+    nghttp2_frame_priority_update_free(&frame->ext, mem);
+    nghttp2_mem_free(mem, item);
+
+    return rv;
+  }
+
+  return 0;
+
+fail_item_malloc:
+  free(buf);
+
+  return rv;
+}
+
 static uint8_t set_request_flags(const nghttp2_priority_spec *pri_spec,
                                  const nghttp2_data_provider *data_prd) {
   uint8_t flags = NGHTTP2_FLAG_NONE;
@@ -680,7 +765,8 @@
     return NGHTTP2_ERR_PROTO;
   }
 
-  if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec)) {
+  if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec) &&
+      session->remote_settings.no_rfc7540_priorities != 1) {
     rv = detect_self_dependency(session, -1, pri_spec);
     if (rv != 0) {
       return rv;