Skip to content

Instantly share code, notes, and snippets.

@syusui-s
Created May 12, 2016 07:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save syusui-s/2cd7008466be1666bf31e47787e53bba to your computer and use it in GitHub Desktop.
Save syusui-s/2cd7008466be1666bf31e47787e53bba to your computer and use it in GitHub Desktop.
require 'http/2'
require 'uri'
require 'socket'
require 'openssl'
module H2Client; end
class H2Client::Connection
PROTOCOL = 'h2'
@@clients = []
def initialize(host, port = 443, options = {})
@host = host
@port = port.to_i
@options = options
@socket = nil
@connection = HTTP2::Client.new
@@clients << self
end
private
def start_h2connection
@connection.on(:frame) do |bytes|
@socket << bytes
end
@thread = Thread.new { self.read_loop }
end
def read_loop
until @socket.closed? or @socket.eof
data = @socket.read_nonblock(8192)
begin
@connection << data
rescue => e
puts e
end
end
self.close
end
def setup_stream(stream, request)
res = Response.new
stream.on(:headers) do |header|
res.header << header
end
# when data received
stream.on(:data) do |data|
res.data << data
end
# when response completed
stream.on(:half_close) do |header|
end
return res
end
public
def finish
@thread # TODO kill thread
@socket.close
return @connection.finish
end
def start
tcp = TCPSocket.new(@host, @port)
# if not TLS
unless @port == 443 or options[:use_ssl]
@socket = tcp
@socket.connect()
return true
end
# If TLS
context = OpenSSL::SSL::SSLContext.new
context.verify_mode = OpenSSL::SSL::VERIFY_NONE
context.npn_protocols = [PROTOCOL]
context.npn_select_cb = lambda do |protocols|
PROTOCOL if protocols.include? PROTOCOL
end
ssl = OpenSSL::SSL::SSLSocket.new(tcp, ctx)
ssl.sync_close = true
ssl.hostname = @host
ssl.connect()
@socket = sock
start_h2connection()
end
def request(request)
raise TypeError, 'resquest should be a H2Client::Request' unless request.is_a?(Request)
stream = @connection.new_stream()
self.setup_stream(stream, request)
stream.header(request.header, :end_stream => (!request.has_payload?) )
stream.data(request.payload) if request.has_payload?
end
end
class H2Client::Request
def initialize(method, uri, options = {}, payload = '')
raise ArgumentError, 'method should be valid' unless method.to_s =~ /^(get|head|post|options|put|delete|trace)$/i
raise ArgumentError, 'uri should be an instance of URI' unless uri.is_a?(URI)
raise ArgumentError, 'options should be a Hash' unless options.is_a?(Hash)
@method = method.to_s.upcase
@uri = uri
@options = options
end
def header
end
def data
end
def payload
end
def has_payload?
end
attr_reader :method, :uri, :options
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment