Skip to content

Commit 48524ed

Browse files
committed
#231 Support for LinkedIn Field-Selector Notation
Fixes the broken .NET RFC 3986 encoding for Uri.EscapeDataString
1 parent 8d210ec commit 48524ed

File tree

1 file changed

+28
-2
lines changed

1 file changed

+28
-2
lines changed

RestSharp/Authenticators/OAuth/OAuthTools.cs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,16 +83,42 @@ public static string GetTimestamp(DateTime dateTime)
8383
return timestamp.ToString();
8484
}
8585

86+
/// <summary>
87+
/// The set of characters that are unreserved in RFC 2396 but are NOT unreserved in RFC 3986.
88+
/// </summary>
89+
/// <seealso cref="http://stackoverflow.com/questions/846487/how-to-get-uri-escapedatastring-to-comply-with-rfc-3986" />
90+
private static readonly string[] UriRfc3986CharsToEscape = new[] { "!", "*", "'", "(", ")" };
91+
8692
/// <summary>
8793
/// URL encodes a string based on section 5.1 of the OAuth spec.
8894
/// Namely, percent encoding with [RFC3986], avoiding unreserved characters,
8995
/// upper-casing hexadecimal characters, and UTF-8 encoding for text value pairs.
9096
/// </summary>
91-
/// <param name="value"></param>
97+
/// <param name="value">The value to escape.</param>
98+
/// <returns>The escaped value.</returns>
99+
/// <remarks>
100+
/// The <see cref="Uri.EscapeDataString"/> method is <i>supposed</i> to take on
101+
/// RFC 3986 behavior if certain elements are present in a .config file. Even if this
102+
/// actually worked (which in my experiments it <i>doesn't</i>), we can't rely on every
103+
/// host actually having this configuration element present.
104+
/// </remarks>
92105
/// <seealso cref="http://oauth.net/core/1.0#encoding_parameters" />
106+
/// <seealso cref="http://stackoverflow.com/questions/846487/how-to-get-uri-escapedatastring-to-comply-with-rfc-3986" />
93107
public static string UrlEncodeRelaxed(string value)
94108
{
95-
return Uri.EscapeDataString(value);
109+
// Start with RFC 2396 escaping by calling the .NET method to do the work.
110+
// This MAY sometimes exhibit RFC 3986 behavior (according to the documentation).
111+
// If it does, the escaping we do that follows it will be a no-op since the
112+
// characters we search for to replace can't possibly exist in the string.
113+
StringBuilder escaped = new StringBuilder(Uri.EscapeDataString(value));
114+
115+
// Upgrade the escaping to RFC 3986, if necessary.
116+
for (int i = 0; i < UriRfc3986CharsToEscape.Length; i++) {
117+
escaped.Replace(UriRfc3986CharsToEscape[i], Uri.HexEscape(UriRfc3986CharsToEscape[i][0]));
118+
}
119+
120+
// Return the fully-RFC3986-escaped string.
121+
return escaped.ToString();
96122
}
97123

98124
/// <summary>

0 commit comments

Comments
 (0)