public
Last active

  • Download Gist
gistfile1.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
# API v1.1, HTTPS
# Expected: {\"errors\":[{\"message\":\"Bad Authentication data\",\"code\":215}]}
# Raises: EOFError: end of file reached
require 'net/http'
uri = "https://api.twitter.com/1.1/users/show.json?user_id=33978"
Net::HTTP.get(URI(uri))
 
# API v1, HTTPS
# Expected: {\"errors\":[{\"message\":\"Bad Authentication data\",\"code\":215}]}
# Raises: EOFError: end of file reached
require 'net/http'
uri = "https://api.twitter.com/1/users/show.json?user_id=33978"
Net::HTTP.get(URI(uri))
 
# API v1.1, HTTP
# Expected: {\"errors\":[{\"message\":\"Bad Authentication data\",\"code\":215}]}
# Returns: {\"errors\":[{\"message\":\"Bad Authentication data\",\"code\":215}]}
require 'net/http'
uri = "http://api.twitter.com/1.1/users/show.json?user_id=33978"
Net::HTTP.get(URI(uri))
 
# API v1.0, HTTP
# Expected: {\"errors\":[{\"message\":\"Bad Authentication data\",\"code\":215}]}
# Returns: {\"errors\":[{\"message\":\"Bad Authentication data\",\"code\":215}]}
require 'net/http'
uri = "http://api.twitter.com/1/users/show.json?user_id=33978"
Net::HTTP.get(URI(uri))

Notes

  • The issue is reproducible over HTTPS (but not HTTP).
  • The issue is reproducible on Ruby 1.8.7-p371, 1.9.2-p320, and 1.9.3-p392 but not 2.0.0-p0.
  • The issue is reproducible across both Twitter API v1 and v1.1.
  • This is not demonstrated above, but the issue is reproducible with authenticated requests, as well. For example, if you try to find a non-existent user (e.g. user_id=33978).
  • This issue appears to be isolated to Ruby’s Net::HTTP standard library. If you use Typhoeus or Excon, the problem goes away…however, this wasn’t an issue until relatively recently, so I suspect something has changed in the way that errors are served by the Twitter API.
  • This problem was first reported to me 4 months ago. I then received the second report 1 month ago and now two reports in the past 24 hours.

I'm trying to figure out what Ruby is doing to send the request. I was able to get the following to work:

1.8.7 :001 > require 'net/https' => true
1.8.7 :002 > uri = URI.parse("https://api.twitter.com/1.1/users/show.json?user_id=33978") => #<URI::HTTPS:0x10cf8a090 URL:https://api.twitter.com/1.1/users/show.json?user_id=33978>
1.8.7 :003 > http = Net::HTTP.new(uri.host, uri.port, "localhost", 8080)
 => #<#<Class:0x10cf80388> api.twitter.com:443 open=false>
1.8.7 :004 > http.use_ssl = true
 => true
1.8.7 :005 > http.verify_mode = OpenSSL::SSL::VERIFY_PEER
 => 1
1.8.7 :006 > request = Net::HTTP::Get.new(uri.request_uri) => #<Net::HTTP::Get GET>
1.8.7 :007 > response = http.request(request)
 => #<Net::HTTPBadRequest 400 Bad Request readbody=true>

Note that I'm setting up a proxy using mitmproxy to capture the request. Interestingly, the difference between the request from the snippet above and the failing first example is that the working example sends:

   GET https://api.twitter.com/1.1/users/show.json?user_id=33978
       ← 400 application/json 61B

But the failing ruby test sends:

   GET http://api.twitter.com:443/1.1/users/show.json?user_id=33978
       ← Blank server response.

Note the http/https difference. It seems like Ruby is sending a non-HTTPS request to api.twitter.com:443 and just getting rejected at the SSL handshake part of the request.

Any idea of anything which may have changed recently with regard to how Net::HTTP sends requests?

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.