9

I'm trying to post a Twitter status from my web app, using RestSharp. The following code works perfectly:

var status = "I am fine with posting this status.";

var client = new RestClient("https://api.twitter.com");

// The OAuth keys/tokens/secrets are retrieved elsewhere
client.Authenticator = OAuth1Authenticator.ForProtectedResource(
    _consumerKey, _consumerSecret, _accessToken, _accessTokenSecret
);

var request = new RestRequest("/1.1/statuses/update.json", Method.POST);
request.AddParameter("status", status, ParameterType.GetOrPost);

var response = client.Execute(request);

However, this code fails with an authentication error if I include any of the following characters in the status text: ! * ' ( )

Through a lot of forum trawling, I've deduced that this is something to do with the OAuth signature encoding not matching the encoding of the POST parameters. I found this question on SO, but searching the RestSharp issues on GitHub reveals nothing helpful.

I can see some code in the RestSharp source (UrlEncodeRelaxed) which seems to be manually encoding that particular set of characters to comply with the OAuth encoding specs, so I've tried manually encoding those characters in my status in the same way (with code taken from RestSharp) before passing it in, e.g:

var status = "I'm NOT fine with posting this status.";

string[] UriRfc3986CharsToEscape = new[] { "!", "*", "'", "(", ")" };
string[] UriRfc3968EscapedHex = new[] { "%21", "%2A", "%27", "%28", "%29" };

for (var i = 0; i < UriRfc3986CharsToEscape.Length; i++)
    status = status.Replace(UriRfc3986CharsToEscape[i], UriRfc3968EscapedHex[i]);

But this doesn't work either (I still get the authentication error).

What actually is the problem here, and what should I be doing to correctly encode the status? Or is this a RestSharp bug?

Community
  • 1
  • 1
Mark Bell
  • 28,985
  • 26
  • 118
  • 145

1 Answers1

4

Have you tried using the HttpUtility class built in to the .NET Framework? You can find it in the System.Web namespace.

string urlEncodedText = HttpUtility.UrlEncode("Your text goes here");

MSDN


This is definitely a RestSharp issue... I played around with it for a while and the problem is that there isn't anyway to disable the standard percent encoding...

void Main()
{
    var ProtectedChars = "0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A".Replace(" 0x", "%").Split(',');
    var client = new RestClient("https://api.twitter.com");

    client.Authenticator = OAuth1Authenticator.ForProtectedResource(
        "_consumerKey", "_consumerSecret", "_accessToken", "_accessTokenSecret"
    );

    var status = "Dogs, Cats & Mice";

    string newStatus = string.Empty;

    foreach (char c in status)
    {
        var charBytes = Encoding.UTF8.GetBytes(c.ToString());
        var tempText = string.Empty;

        for (int i = 0; i < charBytes.Count(); i++)
        {
            byte b = charBytes[i];
            string hex = "%" + b.ToString("X2");
            tempText += hex;
        }

        if (ProtectedChars.Any(x => x == tempText))
        {
            newStatus += c;
        }
        else
        {
            newStatus += string.Format("{0:X2}", tempText);
        }
    }

    var request = new RestRequest("/1.1/statuses/update.json", Method.POST);
    request.AddParameter(new Parameter{ Name = "status", Type = ParameterType.GetOrPost, Value = newStatus } );

    var response = client.Execute(request);


}

In Fiddler I've been monitoring the requests going to Twitter... and this is what I found...

POST https://api.twitter.com/1.1/statuses/update.json HTTP/1.1
Authorization: /* auth data */
Accept: application/json, application/xml, text/json, text/x-json, text/javascript, text/xml
User-Agent: RestSharp/104.4.0.0
Content-Type: application/x-www-form-urlencoded
Host: api.twitter.com
Content-Length: 44
Accept-Encoding: gzip, deflate

status=Dogs%252C%2520Cats%2520%2526%2520Mice

The problem with the Http Request, is the body of our request... had the value I had supplied not been touched... then Twitter would have recognised the message and updated our status for us....

status=Dogs%252C%2520Cats%2520%2526%2520Mice  <--- Altered by RestSharp
status=Dogs%2C%20Cats%20%26%20Mice            <--- What I initially sent
Aydin
  • 15,016
  • 4
  • 32
  • 42
  • The point is that *no* method of encoding makes it work: built-in, manual or otherwise. Which leads me to believe that it's an internal RestSharp issue. Still haven't solved it, though... – Mark Bell Sep 26 '14 at 06:21
  • I've just checked it all out... and yes.. it's a RestSharp issue... Updated my answer above to explain what's going on... – Aydin Sep 26 '14 at 09:25
  • This is useful, thanks—I'm going to check out the RestSharp source and see if I can figure out a fix. – Mark Bell Sep 26 '14 at 10:52
  • Try encapsulating the `status` string with a breakpoint on it's mutator / setter.. hopefully that should lead you straight to whichever method it is that's changing the value – Aydin Sep 26 '14 at 10:55