32

I'm working on a data transfer for a gateway which requires me to send data in UrlEncoded form. However, .net's UrlEncode creates lowercase tags, and it breaks the transfer (Java creates uppercase).

Any thoughts how can I force .net to do uppercase UrlEncoding?

update1:

.net out:

dltz7UK2pzzdCWJ6QOvWXyvnIJwihPdmAioZ%2fENVuAlDQGRNCp1F

vs Java's:

dltz7UK2pzzdCWJ6QOvWXyvnIJwihPdmAioZ%2FENVuAlDQGRNCp1F

(it is a base64d 3DES string, i need to maintain it's case).

4
  • What is the input string for the output that you show? Commented May 27, 2009 at 21:41
  • @Fredrik: URL Encoding returns the original string with invalid characters replaced by %xx, where xx is the hexadecimal value of the invalid character in ISO-8859-1. Hence, the original string is what is shown, but with %2F changed to a '/' character. Commented May 27, 2009 at 22:07
  • +1 Thanks for asking this question. The answer helped me. This issue was causing a lot of headaches for me. Commented May 26, 2011 at 16:28
  • This is a great question! I know this is an old one, but @GreysonTyrus's answer is by far the easiest these days--just use WebUtility.UrlEncode. Commented Jul 22, 2016 at 23:27

7 Answers 7

48

I think you're stuck with what C# gives you, and getting errors suggests a poorly implemented UrlDecode function on the other end.

With that said, you should just need to loop through the string and uppercase only the two characters following a % sign. That'll keep your base64 data intact while massaging the encoded characters into the right format:

public static string UpperCaseUrlEncode(string s)
{
  char[] temp = HttpUtility.UrlEncode(s).ToCharArray();
  for (int i = 0; i < temp.Length - 2; i++)
  {
    if (temp[i] == '%')
    {
      temp[i + 1] = char.ToUpper(temp[i + 1]);
      temp[i + 2] = char.ToUpper(temp[i + 2]);
    }
  }
  return new string(temp);
}
Sign up to request clarification or add additional context in comments.

7 Comments

thanks, but the question was rather about RFC compliance and implementation.
@balint, the relevant RFCs say that you can use upper or lower case for escaped characters in the URL, which is why errors with lower case suggest a bad implementation on the decoding end. However, the above C# code will produce the same results as Java's UrlEncode, so unless I misunderstand the question it should be exactly what you need.
Even though the spec says either is ok, It still makes a huge difference when the encoded string is part of an input into a Hashing routine :-(
This is of relevance to me since I am using HMAC. Took me a full two hours to discover the subtle difference was causing this to fail for me.
I had a similar issue as @frostymarvelous, I needed to generate an HMAC signature of the rest of a query string, and while URIs aren't case-sensitive, HMACs are. According to RFC 3986, both uppercase and lowercase hexadecimal codes are legal in "percent-encoding" (meaning servers and browsers should accept either), but uppercase is recommended for consistency.
|
28

I know this is very old and maybe this solution didn't exist, but this was one of the top pages I found on google when trying to solve this.

System.Net.WebUtility.UrlEncode(posResult);

This encodes to uppercase.

2 Comments

Confirmed, this is the most straight forward solution.
I tried it, but here is a problem with ( and ) they after encoding are left, but must be %28 and %29. How to solve thsi problem?
15

Replace the lowercase percent encoding from HttpUtility.UrlEncode with a Regex:

static string UrlEncodeUpperCase(string value) {
    value = HttpUtility.UrlEncode(value);
    return Regex.Replace(value, "(%[0-9a-f][0-9a-f])", c => c.Value.ToUpper());
}

var value = "SomeWords 123 #=/ äöü";

var encodedValue = HttpUtility.UrlEncode(value);
// SomeWords+123+%23%3d%2f+%c3%a4%c3%b6%c3%bc

var encodedValueUpperCase = UrlEncodeUpperCase(value);
// now the hex chars after % are uppercase:
// SomeWords+123+%23%3D%2F+%C3%A4%C3%B6%C3%BC

Comments

4

This is very easy

Regex.Replace( encodedString, @"%[a-f\d]{2}", m => m.Value.ToUpper() )

I.e. replace all hex letter-digit combinations to upper case

1 Comment

shouldn't it be %[\da-f]{2}
2

if anyone else gets here in search for perl code or a PCRE (perl-compatible regular expression) to solve the issue, a (candidate for the shortest possible) perl-expression to convert url-encoding to lowercase hex is:

s/%(\X{2})/%\L$1\E/go

and the other way around (lowercase to uppercase)

s/%(\x{2})/%\U$1\E/go

Comments

0

This is the code that I'm using in a Twitter application for OAuth...

    Public Function OAuthUrlEncode(ByVal value As String) As String
    Dim result As New StringBuilder()
    Dim unreservedChars As String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~"
    For Each symbol As Char In value
        If unreservedChars.IndexOf(symbol) <> -1 Then
            result.Append(symbol)
        Else
            result.Append("%"c + [String].Format("{0:X2}", AscW(symbol)))
        End If
    Next

    Return result.ToString()
End Function

Hope this helps!

2 Comments

be aware that the code (OAuthUrlEncode) in DWRoelands' answer will cause You problems with international characters!
Be careful with this. It will cause problems with international characters. For example, try encoding this: õ. System.Web.HttpUtility.UrlEncode("õ") will return the correct "%c3%b5", but your method will return "%F5". And when posting this as a Twitter status update, Twitter will return this error: {"errors":[{"code":91,"message":"One or more parameters contains an invalid UTF-8 sequence"}]}
0

Here's my VB.NET conversion of the public OAuth.OAuthBase version of UrlEncode (for .NET 2.0/3.5):

' MEH: Made this ReadOnly because the range of unreserved characters is specified in the OAuth spec. Inheritors ought not change it.
Protected Shared ReadOnly unreservedChars As String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~"
' MEH: Added. These are the other characters HttpUtility.UrlEncode does not convert to percent encoding itself.
Protected Shared ReadOnly reservedChars As String = " !'()*" ' If this moves to .NET 4+ ' can be removed.


''' <summary>
''' This is a different Url Encode implementation since the default .NET one outputs the percent encoding in lower case.
''' While this is not a problem with the percent encoding spec, it is used in upper case throughout OAuth.
''' Also the OAuth spec explicitly requires some characters to be unencoded.
''' </summary>
''' <param name="Value">The value to Url encode</param>
''' <returns>Returns a Url encoded string</returns>
''' <revisionhistory>
'''   140313 MEH Fixed to correctly cater for any characters between %80 and %ff, and the O(n^2) IndexOf call.
''' </revisionhistory>
Public Shared Function UrlEncode(ByVal Value As String) As String
    Dim result, buffer As New StringBuilder()

    For Each symbol As Char In Value
        If unreservedChars.IndexOf(symbol) <> -1 Then
            UrlEncodeAppendClear(result, buffer).Append(symbol)
        ElseIf reservedChars.IndexOf(symbol) = -1 Then
            'some symbols produce 2 or more octets in UTF8 so the system urlencoder must be used to get the correct data
            ' but this is best done over a full sequence of characters, so just store this one in a buffer.
            buffer.Append(symbol)
        Else ' These characters are not converted to percent encoding by UrlEncode.
            UrlEncodeAppendClear(result, buffer).AppendFormat(Globalization.CultureInfo.InvariantCulture, "%{0:X2}", AscW(symbol))
        End If
    Next
    UrlEncodeAppendClear(result, buffer)
    Return result.ToString()
End Function


Private Shared percentHex As New RegularExpressions.Regex("(%[0-9a-f][0-9a-f])", RegularExpressions.RegexOptions.Compiled)

''' <summary>
'''  Actually performs the UrlEncode on any buffered characters, ensuring the resulting percents are uppercased and clears the buffer.
''' </summary>
''' 
''' <param name="Result">The result of the UrlEncode is appended here.</param>
''' <param name="Buffer">The current buffer of characters to be encoded. Cleared on return.</param>
''' 
''' <returns>The <paramref name="Result">Result</paramref>, as passed in, with the UrlEncoding of the <paramref name="Buffer">buffer of characters</paramref> appended.</returns>
''' 
''' <remarks>Would like to be an extension method.</remarks>
''' 
''' <revisionhistory>
'''   140313 MEH Created.
''' </revisionhistory>
Private Shared Function UrlEncodeAppendClear(ByVal Result As StringBuilder, ByVal Buffer As StringBuilder) As StringBuilder
    If Buffer.Length > 0 Then
        Result.Append(percentHex.Replace(HttpUtility.UrlEncode(Buffer.ToString), Function(c) c.Value.ToUpperInvariant()))
        Buffer.Length = 0
    End If
    Return Result
End Function

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.