Created
October 3, 2017 03:55
-
-
Save mikesamuel/b57c92975fc14d8e0bbb4ebfcf2baece to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
private static final boolean DEBUG_RDS = false; | |
static void removeDotSegmentsInPlace(StringBuilder path, int left) { | |
// The code below has excerpts from the spec interspersed. | |
// The "input buffer" and "output buffer" referred to in the spec | |
// are both just regions of path. | |
// The loop deals with the exclusive cases by continuing instead | |
// of proceeding to the bottom. | |
boolean isAbsolute = left < path.length() && path.charAt(left) == '/'; | |
// RFC 3986 Section 5.2.4 | |
// 1. The input buffer is initialized with the now-appended path | |
// components and the output buffer is initialized to the empty | |
// string. | |
int inputBufferStart = left; | |
final int inputBufferEnd = path.length(); | |
final int outputBufferStart = left; | |
int outputBufferEnd = left; | |
// 2. While the input buffer is not empty, loop as follows: | |
while (inputBufferStart < inputBufferEnd) { | |
if (DEBUG_RDS) { | |
System.err.println( | |
"\t[" + path.substring(outputBufferStart, outputBufferEnd) + "]" + | |
path.substring(outputBufferEnd, inputBufferStart) + "[" + | |
path.substring(inputBufferStart, inputBufferEnd) + "]"); | |
} | |
char c0 = path.charAt(inputBufferStart); | |
// A. If the input buffer begins with a prefix of "../" or "./", | |
// then remove that prefix from the input buffer; otherwise, | |
if (c0 == '.') { | |
char c1; | |
if (inputBufferStart + 1 < inputBufferEnd) { | |
if ('/' == (c1 = path.charAt(inputBufferStart + 1))) { | |
inputBufferStart += 2; | |
continue; | |
} | |
if ('.' == c1 && inputBufferStart + 2 < inputBufferEnd | |
&& '/' == path.charAt(inputBufferStart + 2)) { | |
inputBufferStart += 3; | |
continue; | |
} | |
} | |
} | |
// B. if the input buffer begins with a prefix of "/./" or "/.", | |
// where "." is a complete path segment, then replace that | |
// prefix with "/" in the input buffer; otherwise, | |
if (c0 == '/' && inputBufferStart + 1 < inputBufferEnd | |
&& '.' == path.charAt(inputBufferStart + 1)) { | |
if (inputBufferStart + 2 == inputBufferEnd) { | |
inputBufferStart += 1; | |
path.setCharAt(inputBufferStart, '/'); | |
continue; | |
} else if ('/' == path.charAt(inputBufferStart + 2)) { | |
inputBufferStart += 2; | |
continue; | |
} | |
} | |
// C. if the input buffer begins with a prefix of "/../" or "/..", | |
// where ".." is a complete path segment, then replace that | |
// prefix with "/" in the input buffer and remove the last | |
// segment and its preceding "/" (if any) from the output | |
// buffer; otherwise, | |
if (c0 == '/' && inputBufferStart + 2 < inputBufferEnd | |
&& '.' == path.charAt(inputBufferStart + 1) | |
&& '.' == path.charAt(inputBufferStart + 2)) { | |
boolean foundDotDot = false; | |
if (inputBufferStart + 3 == inputBufferEnd) { | |
inputBufferStart += 2; | |
path.setCharAt(inputBufferStart, '/'); | |
foundDotDot = true; | |
} else if ('/' == path.charAt(inputBufferStart + 3)) { | |
inputBufferStart += 3; | |
foundDotDot = true; | |
} | |
if (foundDotDot) { | |
while (outputBufferEnd > outputBufferStart) { | |
--outputBufferEnd; | |
if (path.charAt(outputBufferEnd) == '/') { break; } | |
} | |
if (outputBufferEnd == outputBufferStart && !isAbsolute) { | |
// !!!This differs from spec!!! | |
// Do not convert relative URLs into absolute ones via parent | |
// navigation. | |
inputBufferStart += 1; | |
} | |
continue; | |
} | |
} | |
// D. if the input buffer consists only of "." or "..", then remove | |
// that from the input buffer; otherwise, | |
if (c0 == '.') { | |
if (inputBufferStart + 1 == inputBufferEnd) { | |
inputBufferStart += 1; | |
continue; | |
} else if (inputBufferStart + 2 == inputBufferEnd | |
&& '.' == path.charAt(inputBufferStart + 1)) { | |
inputBufferStart += 2; | |
continue; | |
} | |
} | |
// E. move the first path segment in the input buffer to the end of | |
// the output buffer, including the initial "/" character (if | |
// any) and any subsequent characters up to, but not including, | |
// the next "/" character or the end of the input buffer. | |
do { | |
path.setCharAt(outputBufferEnd++, path.charAt(inputBufferStart++)); | |
} while (inputBufferStart < inputBufferEnd | |
&& path.charAt(inputBufferStart) != '/'); | |
} | |
// 3. Finally, the output buffer is returned as the result of | |
// remove_dot_segments. | |
path.setLength(outputBufferEnd); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment