Just spent half the day tearing my hair out over the inability of my code to connect to the Streaming API. Finally fixed it, and I’m a bit miffed.
Allow me to explain.
I’m writing in Java.
I wrote a little OAuth helper class to handle the authentication. I know I know there are plenty of excellent libraries out there I wanted to learn a bit about OAuth I thought it would be fun.
I tested my helper class thoroughly against the output of the OAuth tool here at dev.twitter.com. My helper would always produce identical base signature string and signature and Authorization: header string as the OAuth tool.
But when I tried to use that with the Apache http-client library, the Streaming API would always reject my connection with 401 Unauthorized.
I tried more unit testing of my helper class, convinced that there must be some subtle error in there. But still no joy.
Finally I started doing low-level (wire) logging on the http-client connection, and compared what it was happening with the behaviour of cURL.
Then it became obvious.
cURL was adding a header “Content-Type: application/x-www-form-urlencoded”.
It did this because that’s cURL’s default behaviour for HTTP POST requests that submit an entity.
On the other hand, Apache’s http-client was adding a header “Content-Type: text/plain; charset=UTF-8”, because that was it’s default behaviour given the way I had passed the request body to the library.
The value of the Content-Type header was the only difference.
So, my point is this.
When the Streaming API received a request with a Content-Type header that it didn’t like, it responded with a 401 Unauthorized.
This is completely and utterly wrong.
It is contrary to the documentation (https://dev.twitter.com/docs/streaming-apis/connecting).
It is contrary to the HTTP specification (which clearly states that if the client gives the server and entity of a type the server does not like, the server is to respond with 415 Unsupported Media Type.
Twitter, you should fix that.
Love and kisses,
The Real Cookie Pants.