/// <summary> /// Generates a string from the given absolute or relative Uri that is appropriately encoded for use in /// HTTP headers. Note that a unicode host name will be encoded as punycode. /// </summary> /// <param name="uri">The Uri to encode.</param> /// <returns></returns> public static string Encode(Uri uri) { if (uri.IsAbsoluteUri) { return(BuildAbsolute( scheme: uri.Scheme, host: HostString.FromUriComponent(uri), pathBase: PathString.FromUriComponent(uri), query: QueryString.FromUriComponent(uri), fragment: FragmentString.FromUriComponent(uri))); } else { return(uri.GetComponents(UriComponents.SerializationInfoString, UriFormat.UriEscaped)); } }
/// <summary> /// Seperates the given absolute URI string into components. Assumes no PathBase. /// </summary> /// <param name="uri">A string representation of the uri.</param> /// <param name="scheme">http, https, etc.</param> /// <param name="host">The host portion of the uri normally included in the Host header. This may include the port.</param> /// <param name="path">The portion of the request path that identifies the requested resource.</param> /// <param name="query">The query, if any.</param> /// <param name="fragment">The fragment, if any.</param> public static void FromAbsolute(string uri, out string scheme, out HostString host, out PathString path, out QueryString query, out FragmentString fragment) { if (uri == null) { throw new ArgumentNullException(nameof(uri)); } // Satisfy the out parameters path = new PathString(); query = new QueryString(); fragment = new FragmentString(); var startIndex = uri.IndexOf(SchemeDelimiter); if (startIndex < 0) { throw new FormatException("No scheme delimiter in uri."); } scheme = uri.Substring(0, startIndex); // PERF: Calculate the end of the scheme for next IndexOf startIndex += SchemeDelimiter.Length; var searchIndex = -1; var limit = uri.Length; if ((searchIndex = uri.IndexOf(Pound, startIndex)) >= 0 && searchIndex < limit) { fragment = FragmentString.FromUriComponent(uri.Substring(searchIndex)); limit = searchIndex; } if ((searchIndex = uri.IndexOf(QuestionMark, startIndex)) >= 0 && searchIndex < limit) { query = QueryString.FromUriComponent(uri.Substring(searchIndex, limit - searchIndex)); limit = searchIndex; } if ((searchIndex = uri.IndexOf(ForwardSlash, startIndex)) >= 0 && searchIndex < limit) { path = PathString.FromUriComponent(uri.Substring(searchIndex, limit - searchIndex)); limit = searchIndex; } host = HostString.FromUriComponent(uri.Substring(startIndex, limit - startIndex)); }
/// <summary> /// Combines the given URI components into a string that is properly encoded for use in HTTP headers. /// Note that unicode in the HostString will be encoded as punycode. /// </summary> /// <param name="scheme">http, https, etc.</param> /// <param name="host">The host portion of the uri normally included in the Host header. This may include the port.</param> /// <param name="pathBase">The first portion of the request path associated with application root.</param> /// <param name="path">The portion of the request path that identifies the requested resource.</param> /// <param name="query">The query, if any.</param> /// <param name="fragment">The fragment, if any.</param> /// <returns></returns> public static string BuildAbsolute(string scheme, HostString host, PathString pathBase = new PathString(), PathString path = new PathString(), QueryString query = new QueryString(), FragmentString fragment = new FragmentString()) { var combinedPath = (pathBase.HasValue || path.HasValue) ? (pathBase + path).ToString() : "/"; var encodedHost = host.ToString(); var encodedQuery = query.ToString(); var encodedFragment = fragment.ToString(); // PERF: Calculate string length to allocate correct buffer size for StringBuilder. var length = scheme.Length + SchemeDelimiter.Length + encodedHost.Length + combinedPath.Length + encodedQuery.Length + encodedFragment.Length; return(new StringBuilder(length) .Append(scheme) .Append(SchemeDelimiter) .Append(encodedHost) .Append(combinedPath) .Append(encodedQuery) .Append(encodedFragment) .ToString()); }