/// <summary> /// Cleans identifiers from an absolute path, and optionally removes the provided prefix /// </summary> /// <param name="absolutePath">The path to clean</param> /// <param name="virtualPathToRemove">The optional virtual path to remove from the front of the path</param> /// <returns>The cleaned path</returns> public static string GetCleanUriPath(string absolutePath, string virtualPathToRemove) { if (string.IsNullOrWhiteSpace(absolutePath) || (absolutePath.Length == 1 && absolutePath[0] == '/')) { return(absolutePath); } if (!string.IsNullOrEmpty(virtualPathToRemove) && string.Equals(absolutePath, virtualPathToRemove)) { return("/"); } // If the virtual path is "/" then we're hosted at the root, so nothing to remove // If not, it will be of the form "/myapp", so remove whole thing // Make sure we only remove _whole_ segment i.e. /myapp/controller, but not /myappcontroller var hasPrefix = !string.IsNullOrEmpty(virtualPathToRemove) && virtualPathToRemove != "/" && virtualPathToRemove[0] == '/' && absolutePath.StartsWith(virtualPathToRemove, StringComparison.OrdinalIgnoreCase) && absolutePath.Length > virtualPathToRemove.Length && absolutePath[virtualPathToRemove.Length] == '/'; // Sanitized url will be at worse as long as the original, minus a removed virtual path var maxLength = absolutePath.Length - (hasPrefix ? virtualPathToRemove.Length : 0); var sb = StringBuilderCache.Acquire(maxLength); int previousIndex = hasPrefix ? virtualPathToRemove.Length : 0; int index; int segmentLength; int indexOfFileExtension = 0; do { index = absolutePath.IndexOf('/', previousIndex); if (index == -1) { // Last segment // Is this a filename with an extension? if (absolutePath.Length > previousIndex && (indexOfFileExtension = absolutePath.LastIndexOf('.')) != -1 && indexOfFileExtension > previousIndex) { // Only try and clean the filename, excluding the file extension segmentLength = indexOfFileExtension - previousIndex; } else { segmentLength = absolutePath.Length - previousIndex; } } else { segmentLength = index - previousIndex; } if (IsIdentifierSegment(absolutePath, previousIndex, segmentLength)) { sb.Append('?'); } else { sb.Append(absolutePath, previousIndex, segmentLength); } if (index == -1) { if (segmentLength > 0 && indexOfFileExtension > previousIndex) { // add the file extension sb.Append(absolutePath, indexOfFileExtension, absolutePath.Length - indexOfFileExtension); } } else { sb.Append('/'); } previousIndex = index + 1; }while (index != -1); return(StringBuilderCache.GetStringAndRelease(sb)); }