RestSharp and Twitter API 1.1: How do I correctly URLEncode status update text?
Asked Answered
S

1

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?

Stagy answered 7/4, 2013 at 11:11 Comment(3)
Did you find a solution or work around? I'm trying to tackle this now.Ionopause
@Michael_B No, sorry: I started looking into it, but didn't get very far before other priorities got in the way.Stagy
I ended up using Linq2Twitter for status updates. It works with v1.1 of the Twitter API. I never found a way around RestSharp's OAuth issues.Ionopause
A
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
Advisement answered 26/9, 2014 at 2:5 Comment(4)
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...Stagy
I've just checked it all out... and yes.. it's a RestSharp issue... Updated my answer above to explain what's going on...Advisement
This is useful, thanks—I'm going to check out the RestSharp source and see if I can figure out a fix.Stagy
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 valueAdvisement

© 2022 - 2024 — McMap. All rights reserved.