| 1875 | */ |
| 1876 | |
| 1877 | static int unescape_url(char *url, const char *forbid, const char *reserved, |
| 1878 | unsigned int flags) |
| 1879 | { |
| 1880 | const int keep_slashes = (flags & AP_UNESCAPE_URL_KEEP_SLASHES) != 0, |
| 1881 | forbid_slashes = (flags & AP_UNESCAPE_URL_FORBID_SLASHES) != 0, |
| 1882 | keep_unreserved = (flags & AP_UNESCAPE_URL_KEEP_UNRESERVED) != 0; |
| 1883 | int badesc, badpath; |
| 1884 | char *x, *y; |
| 1885 | |
| 1886 | badesc = 0; |
| 1887 | badpath = 0; |
| 1888 | /* Initial scan for first '%'. Don't bother writing values before |
| 1889 | * seeing a '%' */ |
| 1890 | y = strchr(url, '%'); |
| 1891 | if (y == NULL) { |
| 1892 | return OK; |
| 1893 | } |
| 1894 | for (x = y; *y; ++x, ++y) { |
| 1895 | if (*y != '%') { |
| 1896 | *x = *y; |
| 1897 | } |
| 1898 | else { |
| 1899 | if (!apr_isxdigit(*(y + 1)) || !apr_isxdigit(*(y + 2))) { |
| 1900 | badesc = 1; |
| 1901 | *x = '%'; |
| 1902 | } |
| 1903 | else { |
| 1904 | char decoded; |
| 1905 | decoded = x2c(y + 1); |
| 1906 | if ((decoded == '\0') |
| 1907 | || (forbid_slashes && AP_IS_SLASH(decoded)) |
| 1908 | || (forbid && ap_strchr_c(forbid, decoded))) { |
| 1909 | badpath = 1; |
| 1910 | *x = decoded; |
| 1911 | y += 2; |
| 1912 | } |
| 1913 | else if ((keep_unreserved && TEST_CHAR(decoded, |
| 1914 | T_URI_UNRESERVED)) |
| 1915 | || (keep_slashes && AP_IS_SLASH(decoded)) |
| 1916 | || (reserved && ap_strchr_c(reserved, decoded))) { |
| 1917 | *x++ = *y++; |
| 1918 | *x++ = *y++; |
| 1919 | *x = *y; |
| 1920 | } |
| 1921 | else { |
| 1922 | *x = decoded; |
| 1923 | y += 2; |
| 1924 | } |
| 1925 | } |
| 1926 | } |
| 1927 | } |
| 1928 | *x = '\0'; |
| 1929 | if (badesc) { |
| 1930 | return HTTP_BAD_REQUEST; |
| 1931 | } |
| 1932 | else if (badpath) { |
| 1933 | return HTTP_NOT_FOUND; |
| 1934 | } |
no test coverage detected