2

I'm trying to use the Ruby gem http-2 to send a GET request to Google.

I've lifted the code directly from the example and simplified it slightly:

require 'http/2'
require 'socket'
require 'openssl'
require 'uri'

uri = URI.parse('http://www.google.com/')
tcp = TCPSocket.new(uri.host, uri.port)
sock = tcp

conn = HTTP2::Client.new
conn.on(:frame) do |bytes|
  # puts "Sending bytes: #{bytes.unpack("H*").first}"
  sock.print bytes
  sock.flush
end
conn.on(:frame_sent) do |frame|
  puts "Sent frame: #{frame.inspect}"
end
conn.on(:frame_received) do |frame|
  puts "Received frame: #{frame.inspect}"
end

stream = conn.new_stream

stream.on(:close) do
  puts 'stream closed'
  sock.close
end

stream.on(:half_close) do
  puts 'closing client-end of the stream'
end

stream.on(:headers) do |h|
  puts "response headers: #{h}"
end

stream.on(:data) do |d|
  puts "response data chunk: <<#{d}>>"
end

head = {
  ':scheme' => uri.scheme,
  ':method' => 'GET',
  ':path' => uri.path
}

puts 'Sending HTTP 2.0 request'
stream.headers(head, end_stream: true)

while !sock.closed? && !sock.eof?
  data = sock.read_nonblock(1024)
  # puts "Received bytes: #{data.unpack("H*").first}"

  begin
    conn << data
  rescue => e
    puts "#{e.class} exception: #{e.message} - closing socket."
    e.backtrace.each { |l| puts "\t" + l }
    sock.close
  end
end

The output is:

Sending HTTP 2.0 request
Sent frame: {:type=>:settings, :stream=>0, :payload=>[[:settings_max_concurrent_streams, 100]]}
Sent frame: {:type=>:headers, :flags=>[:end_headers, :end_stream], :payload=>[[":scheme", "http"], [":method", "GET"], [":path", "/"]], :stream=>1}
closing client-end of the stream

(Note: you get pretty much the same output as above by running the actual example file, i.e., ruby client.rb http://www.google.com/)

Why is no response data being displayed?

Vorpulus Lyphane
  • 660
  • 6
  • 19

1 Answers1

5

Public servers like google.com do not support HTTP/2 in clear text.

You are trying to connect to http://google.com, while you should really connect to https://google.com (note the https scheme).

In order to do that, you may need to wrap the TCP socket using TLS (see for example here), if http-2 does not do it for you.

Note also that HTTP/2 requires strong TLS ciphers and ALPN, so make sure that you have an updated version of OpenSSL (at least 1.0.2).

Given that the author of http-2 is a strong HTTP/2 supporter, I am guessing that your only problem is the fact that you tried clear-text http rather than https, and I expect that TLS cipher strength and ALPN are taken care of by the http-2 library.

Community
  • 1
  • 1
sbordet
  • 16,856
  • 1
  • 50
  • 45
  • Brilliant, thank you. Yes, the library, and even the example that I linked to above, have the code necessary for the encryption. I just wasn't aware that they were always necessary. Just for the sake of anyone else reading: I also had to add back in the http headers that I wrongly removed from the example code linked to above (':authority' => [uri.host, uri.port].join(':'), 'accept' => '*/*',). – Vorpulus Lyphane Sep 20 '16 at 22:39