int jk_servlet_normalize()

in native/common/jk_util.c [2192:2295]


int jk_servlet_normalize(char *path, jk_log_context_t *log_ctx)
{
    int l, w;

    if (JK_IS_DEBUG_LEVEL(log_ctx)) {
        jk_log(log_ctx, JK_LOG_DEBUG, "URI on entering jk_servlet_normalize: [%s]", path);
    }

    // This test allows the loops below to start at index 1 rather than 0.
    if (path[0] != '/') {
        if (path[0] == '*' && path[1] == '\0') {
            /* Most likely an "OPTIONS *" request */
            return 0;
        }
        jk_log(log_ctx, JK_LOG_WARNING, "Uri [%s] does not start with '/'.", path);
        return JK_NORMALIZE_BAD_PATH;
    }

    /* First pass.
     * Remove path parameters ;foo=bar/ from any path segment
     */
    for (l = 1, w = 1; path[l] != '\0';) {
        if (path[l] == ';') {
            l++;
            while (path[l] != '/' && path[l] != '\0') {
                l++;
            }
        }
        else
            path[w++] = path[l++];
    }
    path[w] = '\0';

    /*
     * Second pass.
     * Collapse ///// sequences to /
     */
    for (l = 1, w = 1; path[l] != '\0';) {
        if (path[w - 1] == '/' && (path[l] == '/')) {
            l++;
        }
        else
            path[w++] = path[l++];
    }
    path[w] = '\0';

    /* Third pass.
     * Remove /./ segments
     * Both leading and trailing segments will be removed.
     */
    for (l = 1, w = 1; path[l] != '\0';) {
        if (path[l] == '.' &&
                (path[l + 1] == '/' || path[l + 1] == '\0') &&
                (l == 0 || path[l - 1] == '/')) {
            l++;
            if (path[l] == '/') {
                l++;
            }
        }
        else
            path[w++] = path[l++];
    }
    path[w] = '\0';

    /* Fourth pass.
     * Remove /xx/../ segments
     * Trailing segments will be removed but leading /../ segments are an error
     * condition.
     */
    for (l = 1, w = 1; path[l] != '\0';) {
        if (path[l] == '.' && path[l + 1] == '.' &&
                (path[l + 2] == '/' || path[l + 2] == '\0') &&
                (l == 0 || path[l - 1] == '/')) {

            // Wind w back to remove the previous segment
            if (w == 1) {
                jk_log(log_ctx,
                       JK_LOG_EMERG,
                       "[%s] contains a '/../' sequence that tries to escape above the root.",
                       path);
                return JK_NORMALIZE_TRAVERSAL;
            }
            do {
                w--;
            } while (w != 0 && path[w - 1] != '/');

            // Move l forward to the next segment
            l += 2;

            if (path[l] == '/') {
                l++;
            }
        }
        else
            path[w++] = path[l++];
    }
    path[w] = '\0';

    if (JK_IS_DEBUG_LEVEL(log_ctx)) {
        jk_log(log_ctx, JK_LOG_DEBUG, "URI on exiting jk_servlet_normalize: [%s]", path);
    }

    return 0;
}