    void testDecodePath(boolean isPathParam) throws Exception {
        final Function<String, String> decodeFunc;
        if (isPathParam) {
            decodeFunc = ArmeriaHttpUtil::decodePathParam;
        } else {
            decodeFunc = ArmeriaHttpUtil::decodePath;
        }

        // Fast path
        final String pathThatDoesNotNeedDecode = "/foo_bar_baz";
        assertThat(decodeFunc.apply(pathThatDoesNotNeedDecode)).isSameAs(pathThatDoesNotNeedDecode);

        // Slow path
        assertThat(decodeFunc.apply("/foo%20bar\u007fbaz")).isEqualTo("/foo bar\u007fbaz");
        assertThat(decodeFunc.apply("/%C2%A2")).isEqualTo("/¢"); // Valid UTF-8 sequence
        assertThat(decodeFunc.apply("/%20\u0080")).isEqualTo("/ �"); // Unallowed character
        assertThat(decodeFunc.apply("/%")).isEqualTo("/�"); // No digit
        assertThat(decodeFunc.apply("/%1")).isEqualTo("/�"); // Only a single digit
        assertThat(decodeFunc.apply("/%G0")).isEqualTo("/�"); // First digit is not hex.
        assertThat(decodeFunc.apply("/%0G")).isEqualTo("/�"); // Second digit is not hex.
        assertThat(decodeFunc.apply("/%C3%28")).isEqualTo("/�("); // Invalid UTF-8 sequence

        // %2F (/) must be decoded only for path parameters.
        if (isPathParam) {
            assertThat(decodeFunc.apply("/%2F")).isEqualTo("//");
        } else {
            assertThat(decodeFunc.apply("/%2F")).isEqualTo("/%2F");
        }
    }
The software uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the software does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.