codecov[bot]: # [Codecov](https://codecov.io/gh/falconry/falcon/pull/1682?src=pr&el=h1) Report
> Merging [#1682](https://codecov.io/gh/falconry/falcon/pull/1682?src=pr&el=desc) into [master](https://codecov.io/gh/falconry/falcon/commit/c3e91875f1030c68d17efa27cf8df3d18f337761?src=pr&el=desc) will **not change** coverage.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/falconry/falcon/pull/1682/graphs/tree.svg?width=650&token=zOtkfNQ3h6&height=150&src=pr)](https://codecov.io/gh/falconry/falcon/pull/1682?src=pr&el=tree)

```diff
@@          Coverage Diff           @@
##           master   #1682   +/-   ##
======================================
  Coverage     100%    100%           
======================================
  Files          47      47           
  Lines        3568    3576    +8     
  Branches      545     545           
======================================
+ Hits         3568    3576    +8
```


| [Impacted Files](https://codecov.io/gh/falconry/falcon/pull/1682?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [falcon/util/uri.py](https://codecov.io/gh/falconry/falcon/pull/1682/diff?src=pr&el=tree#diff-ZmFsY29uL3V0aWwvdXJpLnB5) | `100% <100%> (ø)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/falconry/falcon/pull/1682?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/falconry/falcon/pull/1682?src=pr&el=footer). Last update [c3e9187...c6026f5](https://codecov.io/gh/falconry/falcon/pull/1682?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

kgriffs: For noteworthy performance improvements, would it make sense to include a news fragment?
vytas7: @kgriffs It does make sense, I was just unsure what we settled on wrt the naming schema & extension categories.
But I'll add a tentative one, so we can rename later.
kgriffs: What is the impact of this change on performance without Cython? I would check 3.6 as well as 3.8. 
vytas7: I was actually rewriting this from the isascii perspective. The built-in one has better perf than Cython allows me to achieve (it allows semi-efficient unicode char iteration, but I cannot access the string memory in a compatible, non deprecated way. So I cannot process 64-bit or more per cycle). 
vytas7: @kgriffs Ready for-review now, I hope!

I'm still testing that builtin `str.isascii`. It looked like it was outperforming the cythonized version slightly, but 3.5-cythonized actually outdid 3.8 in the results presented above.
I'll add a test comparing those for 3.8.

Either way, the difference should be very insignificant, and IMHO it makes more sense to just use the builtin function. Thoughts?
diff --git a/docs/_newsfragments/1492.newandimproved.rst b/docs/_newsfragments/1492.newandimproved.rst
new file mode 100644
index 0000000..86860b5
--- /dev/null
+++ b/docs/_newsfragments/1492.newandimproved.rst
@@ -0,0 +1,2 @@
+WSGI path decoding in :class:`falcon.Request` was optimized, and is now
+significantly faster than in Falcon 2.0.
diff --git a/falcon/cyutil/misc.pyx b/falcon/cyutil/misc.pyx
new file mode 100644
index 0000000..095dddd
--- /dev/null
+++ b/falcon/cyutil/misc.pyx
@@ -0,0 +1,40 @@
+# Copyright 2020 by Vytautas Liuolia.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+def isascii(unicode string not None):
+    """Return ``True`` if all characters in the string are ASCII.
+
+    ASCII characters have code points in the range U+0000-U+007F.
+
+    Note:
+        On Python 3.7+, this function is just aliased to ``str.isascii``.
+
+    This is a Cython fallback for older CPython versions. For longer strings,
+    it is slightly less performant than the built-in ``str.isascii``.
+
+    Args:
+        string (str): A string to test.
+
+    Returns:
+        ``True`` if all characters are ASCII, ``False`` otherwise.
+    """
+
+    cdef Py_UCS4 ch
+
+    for ch in string:
+        if ch > 0x007F:
+            return False
+
+    return True
diff --git a/falcon/request.py b/falcon/request.py
index 827aaaa..76c5da3 100644
--- a/falcon/request.py
+++ b/falcon/request.py
@@ -24,6 +24,7 @@ from falcon.forwarded import Forwarded  # NOQA
 from falcon.media import Handlers
 from falcon.util import json
 from falcon.util import structures
+from falcon.util.misc import isascii
 from falcon.util.uri import parse_host, parse_query_string
 from falcon.vendor import mimeparse
 
@@ -464,8 +465,11 @@ class Request:
         # ISO-8859-1, e.g.:
         #
         #   tunnelled_path = path.encode('utf-8').decode('iso-8859-1')
-        #
-        path = path.encode('iso-8859-1').decode('utf-8', 'replace')
+
+        # perf(vytas): Only decode the tunnelled path in case it is not ASCII.
+        #   For ASCII-strings, the below decoding chain is a no-op.
+        if not isascii(path):
+            path = path.encode('iso-8859-1').decode('utf-8', 'replace')
 
         if (self.options.strip_url_path_trailing_slash and
                 len(path) != 1 and path.endswith('/')):
diff --git a/falcon/util/misc.py b/falcon/util/misc.py
index 4eea6d6..2287e93 100644
--- a/falcon/util/misc.py
+++ b/falcon/util/misc.py
@@ -36,6 +36,11 @@ import warnings
 
 from falcon import status_codes
 
+try:
+    from falcon.cyutil.misc import isascii as _cy_isascii
+except ImportError:
+    _cy_isascii = None
+
 __all__ = (
     'is_python_func',
     'deprecated',
@@ -508,3 +513,31 @@ def deprecated_args(*, allowed_positional, is_method=True):
         return wraps
 
     return deprecated_args
+
+
+def _isascii(string):
+    """Return ``True`` if all characters in the string are ASCII.
+
+    ASCII characters have code points in the range U+0000-U+007F.
+
+    Note:
+        On Python 3.7+, this function is just aliased to ``str.isascii``.
+
+    This is a pure-Python fallback for older CPython (where Cython is
+    unavailable) and PyPy versions.
+
+    Args:
+        string (str): A string to test.
+
+    Returns:
+        ``True`` if all characters are ASCII, ``False`` otherwise.
+    """
+
+    try:
+        string.encode('ascii')
+        return True
+    except ValueError:
+        return False
+
+
+isascii = getattr(str, 'isascii', _cy_isascii or _isascii)

perf(Request): Short-circuit path encode/decode when possible
See if we can quickly determine if the following is required for a given path and short-circuit it when it is not (from `Request.__init__`):

```py
# PEP 3333 specifies that PATH_INFO variable are always
# "bytes tunneled as latin-1" and must be encoded back
path = path.encode('latin1').decode('utf-8', 'replace')
```

See also this section from `falcon/testing/helpers.py`:

```py
# NOTE(kgriffs): The decoded path may contain UTF-8 characters.
# But according to the WSGI spec, no strings can contain chars
# outside ISO-8859-1. Therefore, to reconcile the URI
# encoding standard that allows UTF-8 with the WSGI spec
# that does not, WSGI servers tunnel the string via
# ISO-8859-1. falcon.testing.create_environ() mimics this
# behavior, e.g.:
#
#   tunnelled_path = path.encode('utf-8').decode('iso-8859-1')
#
# falcon.Request does the following to reverse the process:
#
#   path = tunnelled_path.encode('iso-8859-1').decode('utf-8', 'replace')
#
path = path.encode('utf-8').decode('iso-8859-1')
```
diff --git a/tests/test_utils.py b/tests/test_utils.py
index d393a09..c611c2c 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -498,6 +498,21 @@ class TestFalconUtils:
         with pytest.raises(ValueError):
             misc.secure_filename('')
 
+    @pytest.mark.parametrize('string,expected_ascii', [
+        ('', True),
+        ('/', True),
+        ('/api', True),
+        ('/data/items/something?query=apples%20and%20oranges', True),
+        ('/food?item=ð\x9f\x8d\x94', False),
+        ('\x00\x00\x7F\x00\x00\x7F\x00', True),
+        ('\x00\x00\x7F\x00\x00\x80\x00', False),
+    ])
+    def test_misc_isascii(self, string, expected_ascii):
+        if expected_ascii:
+            assert misc.isascii(string)
+        else:
+            assert not misc.isascii(string)
+
 
 @pytest.mark.parametrize(
     'protocol,method',

pip install -e .[dev]
parse_log_pytest
requirements.txt
testtools requests pyyaml pytest pytest-runner
apt-get update apt-get install -y gcc
3.9
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
certifi==2025.1.31
charset-normalizer==3.4.1
exceptiongroup==1.2.2
-e git+https://github.com/falconry/falcon.git@eed4fc26e0123700f2cc4452b608912d01afff16#egg=falcon
idna==3.10
iniconfig==2.1.0
packaging==24.2
pluggy==1.5.0
pytest==8.3.5
pytest-runner==6.0.1
PyYAML==6.0.2
requests==2.32.3
testtools==2.7.2
tomli==2.2.1
urllib3==2.3.0

name: falcon
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - certifi==2025.1.31
      - charset-normalizer==3.4.1
      - exceptiongroup==1.2.2
      - falcon==3.0.0a1
      - idna==3.10
      - iniconfig==2.1.0
      - packaging==24.2
      - pluggy==1.5.0
      - pytest==8.3.5
      - pytest-runner==6.0.1
      - pyyaml==6.0.2
      - requests==2.32.3
      - testtools==2.7.2
      - tomli==2.2.1
      - urllib3==2.3.0
prefix: /opt/conda/envs/falcon

tests/test_utils.py::TestFalconUtils::test_misc_isascii[-True] tests/test_utils.py::TestFalconUtils::test_misc_isascii[/-True] tests/test_utils.py::TestFalconUtils::test_misc_isascii[/api-True] tests/test_utils.py::TestFalconUtils::test_misc_isascii[/data/items/something?query=apples%20and%20oranges-True] tests/test_utils.py::TestFalconUtils::test_misc_isascii[/food?item=\xf0\x9f\x8d\x94-False] tests/test_utils.py::TestFalconUtils::test_misc_isascii[\x00\x00\x7f\x00\x00\x7f\x00-True] tests/test_utils.py::TestFalconUtils::test_misc_isascii[\x00\x00\x7f\x00\x00\x80\x00-False]
tests/test_utils.py::TestFalconUtils::test_deprecated_decorator tests/test_utils.py::TestFalconTestingUtils::test_default_headers[asgi] tests/test_utils.py::TestFalconTestingUtils::test_default_headers_with_override[asgi] tests/test_utils.py::TestFalconTestingUtils::test_status[asgi] tests/test_utils.py::TestFalconTestingUtils::test_path_must_start_with_slash[asgi] tests/test_utils.py::TestFalconTestingUtils::test_cached_text_in_result[asgi] tests/test_utils.py::TestFalconTestingUtils::test_query_string[asgi] tests/test_utils.py::TestFalconTestingUtils::test_query_string_no_question[asgi] tests/test_utils.py::TestFalconTestingUtils::test_query_string_in_path[asgi] tests/test_utils.py::TestFalconTestingUtils::test_simulate_remote_addr[asgi-None] tests/test_utils.py::TestFalconTestingUtils::test_simulate_remote_addr[asgi-127.0.0.1] tests/test_utils.py::TestFalconTestingUtils::test_simulate_remote_addr[asgi-8.8.8.8] tests/test_utils.py::TestFalconTestingUtils::test_simulate_remote_addr[asgi-104.24.101.85] tests/test_utils.py::TestFalconTestingUtils::test_simulate_remote_addr[asgi-2606:4700:30::6818:6455] tests/test_utils.py::TestFalconTestingUtils::test_simulate_hostname[asgi] tests/test_utils.py::TestFalconTestingUtils::test_override_method_with_extras[asgi]
tests/test_utils.py::TestFalconUtils::test_http_now tests/test_utils.py::TestFalconUtils::test_dt_to_http tests/test_utils.py::TestFalconUtils::test_http_date_to_dt tests/test_utils.py::TestFalconUtils::test_pack_query_params_none tests/test_utils.py::TestFalconUtils::test_pack_query_params_one tests/test_utils.py::TestFalconUtils::test_pack_query_params_several tests/test_utils.py::TestFalconUtils::test_uri_encode tests/test_utils.py::TestFalconUtils::test_uri_encode_double tests/test_utils.py::TestFalconUtils::test_uri_encode_value tests/test_utils.py::TestFalconUtils::test_uri_decode tests/test_utils.py::TestFalconUtils::test_uri_decode_replace_bad_unicode[+%80- tests/test_utils.py::TestFalconUtils::test_uri_decode_replace_bad_unicode[+++%FF+++- tests/test_utils.py::TestFalconUtils::test_uri_decode_replace_bad_unicode[%fc%83%bf%bf%bf%bf-\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd] tests/test_utils.py::TestFalconUtils::test_uri_decode_replace_bad_unicode[%ed%ae%80%ed%b0%80-\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd] tests/test_utils.py::TestFalconUtils::test_uri_decode_unquote_plus tests/test_utils.py::TestFalconUtils::test_prop_uri_encode_models_stdlib_quote tests/test_utils.py::TestFalconUtils::test_prop_uri_encode_value_models_stdlib_quote_safe_tilde tests/test_utils.py::TestFalconUtils::test_prop_uri_decode_models_stdlib_unquote_plus tests/test_utils.py::TestFalconUtils::test_unquote_string tests/test_utils.py::TestFalconUtils::test_parse_query_string tests/test_utils.py::TestFalconUtils::test_parse_query_string_edge_cases[-True-expected0] tests/test_utils.py::TestFalconUtils::test_parse_query_string_edge_cases[-False-expected1] tests/test_utils.py::TestFalconUtils::test_parse_query_string_edge_cases[flag1&&&&&flag2&&&-True-expected2] tests/test_utils.py::TestFalconUtils::test_parse_query_string_edge_cases[flag1&&&&&flag2&&&-False-expected3] tests/test_utils.py::TestFalconUtils::test_parse_query_string_edge_cases[malformed=%FG%1%Hi%%%a-False-expected4] tests/test_utils.py::TestFalconUtils::test_parse_query_string_edge_cases[=-False-expected5] tests/test_utils.py::TestFalconUtils::test_parse_query_string_edge_cases[==-False-expected6] tests/test_utils.py::TestFalconUtils::test_parse_query_string_edge_cases[%==+==&&&&&&&&&%%==+=&&&&&&%0g%=%=-False-expected7] tests/test_utils.py::TestFalconUtils::test_parse_query_string_edge_cases[%=&%%=&&%%%=-False-expected8] tests/test_utils.py::TestFalconUtils::test_parse_query_string_edge_cases[%=&%%=&&%%%=-True-expected9] tests/test_utils.py::TestFalconUtils::test_parse_query_string_edge_cases[+=&%+=&&%++=-True-expected10] tests/test_utils.py::TestFalconUtils::test_parse_query_string_edge_cases[=x=&=x=+1=x=&%=x-False-expected11] tests/test_utils.py::TestFalconUtils::test_parse_query_string_edge_cases[%=+&%=&+%+=&%+&=%&=+%&+==%+&=%&+=+%&=+&%=&%+=&+%+%=&+%&=+=%&+=&%+&%=+&=%&%=+&%+=&=%+&=+%&+%=&+=%-False-expected12] tests/test_utils.py::TestFalconUtils::test_parse_query_string_edge_cases[%%%\x00%\x00==\x00\x00==-True-expected13] tests/test_utils.py::TestFalconUtils::test_parse_query_string_edge_cases[spade=\u2660&spade=\u2660-False-expected14] tests/test_utils.py::TestFalconUtils::test_parse_host tests/test_utils.py::TestFalconUtils::test_get_http_status tests/test_utils.py::TestFalconUtils::test_code_to_http_status[703-703 tests/test_utils.py::TestFalconUtils::test_code_to_http_status[404-404 tests/test_utils.py::TestFalconUtils::test_code_to_http_status[404.9-404 tests/test_utils.py::TestFalconUtils::test_code_to_http_status[123-123] tests/test_utils.py::TestFalconUtils::test_code_to_http_status_neg[not_a_number] tests/test_utils.py::TestFalconUtils::test_code_to_http_status_neg[0_0] tests/test_utils.py::TestFalconUtils::test_code_to_http_status_neg[0_1] tests/test_utils.py::TestFalconUtils::test_code_to_http_status_neg[99_0] tests/test_utils.py::TestFalconUtils::test_code_to_http_status_neg[99_1] tests/test_utils.py::TestFalconUtils::test_code_to_http_status_neg[404.3] tests/test_utils.py::TestFalconUtils::test_code_to_http_status_neg[-404.3_0] tests/test_utils.py::TestFalconUtils::test_code_to_http_status_neg[-404] tests/test_utils.py::TestFalconUtils::test_code_to_http_status_neg[-404.3_1] tests/test_utils.py::TestFalconUtils::test_http_status_to_code[HTTPStatus.HTTP_VERSION_NOT_SUPPORTED-505_0] tests/test_utils.py::TestFalconUtils::test_http_status_to_code[712-712_0] tests/test_utils.py::TestFalconUtils::test_http_status_to_code[712-712_1] tests/test_utils.py::TestFalconUtils::test_http_status_to_code[404 tests/test_utils.py::TestFalconUtils::test_http_status_to_code[712 tests/test_utils.py::TestFalconUtils::test_http_status_to_code[123 tests/test_utils.py::TestFalconUtils::test_http_status_to_code[HTTPStatus.HTTP_VERSION_NOT_SUPPORTED-505_1] tests/test_utils.py::TestFalconUtils::test_http_status_to_code_neg[0] tests/test_utils.py::TestFalconUtils::test_http_status_to_code_neg[ tests/test_utils.py::TestFalconUtils::test_http_status_to_code_neg[1] tests/test_utils.py::TestFalconUtils::test_http_status_to_code_neg[12] tests/test_utils.py::TestFalconUtils::test_http_status_to_code_neg[99] tests/test_utils.py::TestFalconUtils::test_http_status_to_code_neg[catsup] tests/test_utils.py::TestFalconUtils::test_http_status_to_code_neg[2] tests/test_utils.py::TestFalconUtils::test_http_status_to_code_neg[5.2] tests/test_utils.py::TestFalconUtils::test_etag_dumps_to_header_format tests/test_utils.py::TestFalconUtils::test_etag_strong_vs_weak_comparison tests/test_utils.py::TestFalconUtils::test_secure_filename[.-_] tests/test_utils.py::TestFalconUtils::test_secure_filename[..-_.] tests/test_utils.py::TestFalconUtils::test_secure_filename[hello.txt-hello.txt] tests/test_utils.py::TestFalconUtils::test_secure_filename[\u0104\u017euolai tests/test_utils.py::TestFalconUtils::test_secure_filename[/etc/shadow-_etc_shadow] tests/test_utils.py::TestFalconUtils::test_secure_filename[. tests/test_utils.py::TestFalconUtils::test_secure_filename[C:\\Windows\\kernel32.dll-C__Windows_kernel32.dll] tests/test_utils.py::TestFalconUtils::test_secure_filename_empty_value tests/test_utils.py::test_simulate_request_protocol[asgi-https-CONNECT] tests/test_utils.py::test_simulate_request_protocol[asgi-https-DELETE] tests/test_utils.py::test_simulate_request_protocol[asgi-https-GET] tests/test_utils.py::test_simulate_request_protocol[asgi-https-HEAD] tests/test_utils.py::test_simulate_request_protocol[asgi-https-OPTIONS] tests/test_utils.py::test_simulate_request_protocol[asgi-https-PATCH] tests/test_utils.py::test_simulate_request_protocol[asgi-https-POST] tests/test_utils.py::test_simulate_request_protocol[asgi-https-PUT] tests/test_utils.py::test_simulate_request_protocol[asgi-https-TRACE] tests/test_utils.py::test_simulate_request_protocol[asgi-http-CONNECT] tests/test_utils.py::test_simulate_request_protocol[asgi-http-DELETE] tests/test_utils.py::test_simulate_request_protocol[asgi-http-GET] tests/test_utils.py::test_simulate_request_protocol[asgi-http-HEAD] tests/test_utils.py::test_simulate_request_protocol[asgi-http-OPTIONS] tests/test_utils.py::test_simulate_request_protocol[asgi-http-PATCH] tests/test_utils.py::test_simulate_request_protocol[asgi-http-POST] tests/test_utils.py::test_simulate_request_protocol[asgi-http-PUT] tests/test_utils.py::test_simulate_request_protocol[asgi-http-TRACE] tests/test_utils.py::test_simulate_request_protocol[wsgi-https-CONNECT] tests/test_utils.py::test_simulate_request_protocol[wsgi-https-DELETE] tests/test_utils.py::test_simulate_request_protocol[wsgi-https-GET] tests/test_utils.py::test_simulate_request_protocol[wsgi-https-HEAD] tests/test_utils.py::test_simulate_request_protocol[wsgi-https-OPTIONS] tests/test_utils.py::test_simulate_request_protocol[wsgi-https-PATCH] tests/test_utils.py::test_simulate_request_protocol[wsgi-https-POST] tests/test_utils.py::test_simulate_request_protocol[wsgi-https-PUT] tests/test_utils.py::test_simulate_request_protocol[wsgi-https-TRACE] tests/test_utils.py::test_simulate_request_protocol[wsgi-http-CONNECT] tests/test_utils.py::test_simulate_request_protocol[wsgi-http-DELETE] tests/test_utils.py::test_simulate_request_protocol[wsgi-http-GET] tests/test_utils.py::test_simulate_request_protocol[wsgi-http-HEAD] tests/test_utils.py::test_simulate_request_protocol[wsgi-http-OPTIONS] tests/test_utils.py::test_simulate_request_protocol[wsgi-http-PATCH] tests/test_utils.py::test_simulate_request_protocol[wsgi-http-POST] tests/test_utils.py::test_simulate_request_protocol[wsgi-http-PUT] tests/test_utils.py::test_simulate_request_protocol[wsgi-http-TRACE] tests/test_utils.py::test_simulate_free_functions[asgi-simulate_get] tests/test_utils.py::test_simulate_free_functions[asgi-simulate_head] tests/test_utils.py::test_simulate_free_functions[asgi-simulate_post] tests/test_utils.py::test_simulate_free_functions[asgi-simulate_put] tests/test_utils.py::test_simulate_free_functions[asgi-simulate_options] tests/test_utils.py::test_simulate_free_functions[asgi-simulate_patch] tests/test_utils.py::test_simulate_free_functions[asgi-simulate_delete] tests/test_utils.py::test_simulate_free_functions[wsgi-simulate_get] tests/test_utils.py::test_simulate_free_functions[wsgi-simulate_head] tests/test_utils.py::test_simulate_free_functions[wsgi-simulate_post] tests/test_utils.py::test_simulate_free_functions[wsgi-simulate_put] tests/test_utils.py::test_simulate_free_functions[wsgi-simulate_options] tests/test_utils.py::test_simulate_free_functions[wsgi-simulate_patch] tests/test_utils.py::test_simulate_free_functions[wsgi-simulate_delete] tests/test_utils.py::TestFalconTestingUtils::test_path_escape_chars_in_create_environ tests/test_utils.py::TestFalconTestingUtils::test_no_prefix_allowed_for_query_strings_in_create_environ tests/test_utils.py::TestFalconTestingUtils::test_plus_in_path_in_create_environ tests/test_utils.py::TestFalconTestingUtils::test_none_header_value_in_create_environ tests/test_utils.py::TestFalconTestingUtils::test_decode_empty_result[asgi] tests/test_utils.py::TestFalconTestingUtils::test_decode_empty_result[wsgi] tests/test_utils.py::TestFalconTestingUtils::test_httpnow_alias_for_backwards_compat tests/test_utils.py::TestFalconTestingUtils::test_default_headers[wsgi] tests/test_utils.py::TestFalconTestingUtils::test_default_headers_with_override[wsgi] tests/test_utils.py::TestFalconTestingUtils::test_status[wsgi] tests/test_utils.py::TestFalconTestingUtils::test_wsgi_iterable_not_closeable tests/test_utils.py::TestFalconTestingUtils::test_path_must_start_with_slash[wsgi] tests/test_utils.py::TestFalconTestingUtils::test_cached_text_in_result[wsgi] tests/test_utils.py::TestFalconTestingUtils::test_simple_resource_body_json_xor[SimpleTestResource] tests/test_utils.py::TestFalconTestingUtils::test_simple_resource_body_json_xor[SimpleTestResourceAsync] tests/test_utils.py::TestFalconTestingUtils::test_query_string[wsgi] tests/test_utils.py::TestFalconTestingUtils::test_query_string_no_question[wsgi] tests/test_utils.py::TestFalconTestingUtils::test_query_string_in_path[wsgi] tests/test_utils.py::TestFalconTestingUtils::test_simulate_json_body[asgi-16.0625] tests/test_utils.py::TestFalconTestingUtils::test_simulate_json_body[asgi-123456789] tests/test_utils.py::TestFalconTestingUtils::test_simulate_json_body[asgi-True] tests/test_utils.py::TestFalconTestingUtils::test_simulate_json_body[asgi-] tests/test_utils.py::TestFalconTestingUtils::test_simulate_json_body[asgi-I tests/test_utils.py::TestFalconTestingUtils::test_simulate_json_body[asgi-document5] tests/test_utils.py::TestFalconTestingUtils::test_simulate_json_body[asgi-document6] tests/test_utils.py::TestFalconTestingUtils::test_simulate_json_body[asgi-document7] tests/test_utils.py::TestFalconTestingUtils::test_simulate_json_body[wsgi-16.0625] tests/test_utils.py::TestFalconTestingUtils::test_simulate_json_body[wsgi-123456789] tests/test_utils.py::TestFalconTestingUtils::test_simulate_json_body[wsgi-True] tests/test_utils.py::TestFalconTestingUtils::test_simulate_json_body[wsgi-] tests/test_utils.py::TestFalconTestingUtils::test_simulate_json_body[wsgi-I tests/test_utils.py::TestFalconTestingUtils::test_simulate_json_body[wsgi-document5] tests/test_utils.py::TestFalconTestingUtils::test_simulate_json_body[wsgi-document6] tests/test_utils.py::TestFalconTestingUtils::test_simulate_json_body[wsgi-document7] tests/test_utils.py::TestFalconTestingUtils::test_simulate_remote_addr[wsgi-None] tests/test_utils.py::TestFalconTestingUtils::test_simulate_remote_addr[wsgi-127.0.0.1] tests/test_utils.py::TestFalconTestingUtils::test_simulate_remote_addr[wsgi-8.8.8.8] tests/test_utils.py::TestFalconTestingUtils::test_simulate_remote_addr[wsgi-104.24.101.85] tests/test_utils.py::TestFalconTestingUtils::test_simulate_remote_addr[wsgi-2606:4700:30::6818:6455] tests/test_utils.py::TestFalconTestingUtils::test_simulate_hostname[wsgi] tests/test_utils.py::TestFalconTestingUtils::test_simulate_with_environ_extras[extras0-expected_headers0] tests/test_utils.py::TestFalconTestingUtils::test_simulate_with_environ_extras[extras1-expected_headers1] tests/test_utils.py::TestFalconTestingUtils::test_override_method_with_extras[wsgi] tests/test_utils.py::TestNoApiClass::test_something tests/test_utils.py::TestSetupApi::test_something tests/test_utils.py::test_get_argnames tests/test_utils.py::TestContextType::test_attributes[CustomContextType] tests/test_utils.py::TestContextType::test_attributes[Context] tests/test_utils.py::TestContextType::test_items_from_attributes[CustomContextType] tests/test_utils.py::TestContextType::test_items_from_attributes[Context] tests/test_utils.py::TestContextType::test_attributes_from_items[CustomContextType] tests/test_utils.py::TestContextType::test_attributes_from_items[Context] tests/test_utils.py::TestContextType::test_dict_interface[CustomContextType-CustomContextType] tests/test_utils.py::TestContextType::test_dict_interface[Context-Context] tests/test_utils.py::TestContextType::test_keys_and_values[CustomContextType] tests/test_utils.py::TestContextType::test_keys_and_values[Context] tests/test_utils.py::TestDeprecatedArgs::test_method tests/test_utils.py::TestDeprecatedArgs::test_function
falcon/request.py falcon/util/misc.py docs/_newsfragments/1492.newandimproved.rst falcon/cyutil/misc.pyx
falcon/request.py falcon/util/misc.py docs/_newsfragments/1492.newandimproved.rst falcon/cyutil/misc.pyx