protected LinkValidationResult VerifyLink(string docFilePath, string linkUrl, string docSetBasePath, out string relativeFileName) { relativeFileName = null; Uri parsedUri; var validUrl = Uri.TryCreate(linkUrl, UriKind.RelativeOrAbsolute, out parsedUri); FileInfo sourceFile = new FileInfo(docFilePath); if (validUrl) { if (parsedUri.IsAbsoluteUri && (parsedUri.Scheme == "http" || parsedUri.Scheme == "https")) { // TODO: verify an external URL is valid by making a HEAD request return(LinkValidationResult.ExternalSkipped); } else if (linkUrl.StartsWith("#")) { string bookmarkName = linkUrl.Substring(1); if (this.bookmarks.Contains(bookmarkName)) { return(LinkValidationResult.Valid); } else { var suggestion = StringSuggestions.SuggestStringFromCollection(bookmarkName, this.bookmarks); if (suggestion != null) { relativeFileName = "#" + suggestion; } return(LinkValidationResult.BookmarkMissing); } } else { return(this.VerifyRelativeLink(sourceFile, linkUrl, docSetBasePath, out relativeFileName)); } } else { return(LinkValidationResult.UrlFormatInvalid); } }
protected virtual LinkValidationResult VerifyRelativeLink(FileInfo sourceFile, string originalLinkUrl, string docSetBasePath, out string relativeFileName) { if (sourceFile == null) { throw new ArgumentNullException("sourceFile"); } if (string.IsNullOrEmpty(originalLinkUrl)) { throw new ArgumentNullException("linkUrl"); } if (string.IsNullOrEmpty(docSetBasePath)) { throw new ArgumentNullException("docSetBasePath"); } if (originalLinkUrl.StartsWith("mailto:", StringComparison.OrdinalIgnoreCase)) { // TODO: Verify that this is an actual email address relativeFileName = null; return(LinkValidationResult.Valid); } relativeFileName = null; var rootPath = sourceFile.DirectoryName; string bookmarkName = null; var workingLinkUrl = originalLinkUrl; if (workingLinkUrl.Contains("#")) { int indexOfHash = workingLinkUrl.IndexOf('#'); bookmarkName = workingLinkUrl.Substring(indexOfHash + 1); workingLinkUrl = workingLinkUrl.Substring(0, indexOfHash); } if (workingLinkUrl.StartsWith("/")) { // URL is relative to the base for the documentation rootPath = docSetBasePath; workingLinkUrl = workingLinkUrl.Substring(1); } while (workingLinkUrl.StartsWith("../")) { var nextLevelParent = new DirectoryInfo(rootPath).Parent; if (null != nextLevelParent) { rootPath = nextLevelParent.FullName; workingLinkUrl = workingLinkUrl.Substring(3); } else { break; } } if (rootPath.Length < docSetBasePath.Length) { return(LinkValidationResult.ParentAboveDocSetPath); } try { workingLinkUrl = workingLinkUrl.Replace('/', Path.DirectorySeparatorChar); // normalize the path syntax between local file system and web var pathToFile = Path.Combine(rootPath, workingLinkUrl); FileInfo info = new FileInfo(pathToFile); if (!info.Exists) { if (info.Directory.Exists) { var candidateFiles = from f in info.Directory.GetFiles() select f.Name; relativeFileName = StringSuggestions.SuggestStringFromCollection(info.Name, candidateFiles); } return(LinkValidationResult.FileNotFound); } relativeFileName = this.Parent.RelativePathToFile(info.FullName, urlStyle: true); if (bookmarkName != null) { // See if that bookmark exists in the target document, assuming we know about it var otherDocFile = this.Parent.LookupFileForPath(relativeFileName); if (otherDocFile == null) { return(LinkValidationResult.BookmarkSkippedDocFileNotFound); } else if (!otherDocFile.bookmarks.Contains(bookmarkName)) { var suggestion = StringSuggestions.SuggestStringFromCollection(bookmarkName, otherDocFile.bookmarks); if (null != suggestion) { relativeFileName = "#" + suggestion; } return(LinkValidationResult.BookmarkMissing); } } return(LinkValidationResult.Valid); } catch (Exception) { return(LinkValidationResult.UrlFormatInvalid); } }