static String canonicalPath(String path) {
        List<String> r = new ArrayList<String>(Arrays.asList(path.split("/+")));
        for (int i=0; i<r.size(); ) {
            if (r.get(i).length()==0 || r.get(i).equals(".")) {
                // empty token occurs for example, "".split("/+") is [""]
                r.remove(i);
            } else
            if (r.get(i).equals("..")) {
                // i==0 means this is a broken URI.
                r.remove(i);
                if (i>0) {
                    r.remove(i-1);
                    i--;
                }
            } else {
                i++;
            }
        }

        StringBuilder buf = new StringBuilder();
        if (path.startsWith("/"))
            buf.append('/');
        boolean first = true;
        for (String token : r) {
            if (!first)     buf.append('/');
            else            first = false;
            buf.append(token);
        }
        // translation: if (path.endsWith("/") && !buf.endsWith("/"))
        if (path.endsWith("/") && (buf.length()==0 || buf.charAt(buf.length()-1)!='/'))
            buf.append('/');
        return buf.toString();
    }
static String canonicalPath ( String path ) { List < String > r = new ArrayList < String > ( Arrays . asList ( path . split ( "/+" ) ) ) ; for ( int i = 0 ; i < r . size ( ) ; ) { if ( r . get ( i ) . length ( ) == 0 || r . get ( i ) . equals ( "." ) ) { r . remove ( i ) ; } else if ( r . get ( i ) . equals ( ".." ) ) { r . remove ( i ) ; if ( i > 0 ) { r . remove ( i - 1 ) ; i -- ; } } else { i ++ ; } } StringBuilder buf = new StringBuilder ( ) ; if ( path . startsWith ( "/" ) ) buf . append ( '/' ) ; boolean first = true ; for ( String token : r ) { if ( ! first ) buf . append ( '/' ) ; else first = false ; buf . append ( token ) ; } if ( path . endsWith ( "/" ) && ( buf . length ( ) == 0 || buf . charAt ( buf . length ( ) - 1 ) != '/' ) ) buf . append ( '/' ) ; return buf . toString ( ) ; }
Some web containers (e.g., Winstone) leaves ".." and "." in the request URL,
which is a security risk. Fix that by normalizing them.