Permalink
Fetching contributors…
Cannot retrieve contributors at this time
140 lines (111 sloc) 3.58 KB
require_relative 'helper'
options = { port: 8080 }
OptionParser.new do |opts|
opts.banner = 'Usage: server.rb [options]'
opts.on('-s', '--secure', 'HTTPS mode') do |v|
options[:secure] = v
end
opts.on('-p', '--port [Integer]', 'listen port') do |v|
options[:port] = v
end
opts.on('-u', '--push', 'Push message') do |_v|
options[:push] = true
end
end.parse!
puts "Starting server on port #{options[:port]}"
server = TCPServer.new(options[:port])
if options[:secure]
ctx = OpenSSL::SSL::SSLContext.new
ctx.cert = OpenSSL::X509::Certificate.new(File.open('keys/server.crt'))
ctx.key = OpenSSL::PKey::RSA.new(File.open('keys/server.key'))
ctx.ssl_version = :TLSv1_2
ctx.options = OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:options]
ctx.ciphers = OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:ciphers]
ctx.alpn_protocols = ['h2']
ctx.alpn_select_cb = lambda do |protocols|
raise "Protocol #{DRAFT} is required" if protocols.index(DRAFT).nil?
DRAFT
end
ctx.ecdh_curves = 'P-256'
server = OpenSSL::SSL::SSLServer.new(server, ctx)
end
loop do
sock = server.accept
puts 'New TCP connection!'
conn = HTTP2::Server.new
conn.on(:frame) do |bytes|
# puts "Writing bytes: #{bytes.unpack("H*").first}"
sock.is_a?(TCPSocket) ? sock.sendmsg(bytes) : sock.write(bytes)
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
conn.on(:stream) do |stream|
log = Logger.new(stream.id)
req, buffer = {}, ''
stream.on(:active) { log.info 'client opened new stream' }
stream.on(:close) { log.info 'stream closed' }
stream.on(:headers) do |h|
req = Hash[*h.flatten]
log.info "request headers: #{h}"
end
stream.on(:data) do |d|
log.info "payload chunk: <<#{d}>>"
buffer << d
end
stream.on(:half_close) do
log.info 'client closed its end of the stream'
response = nil
if req[':method'] == 'POST'
log.info "Received POST request, payload: #{buffer}"
response = "Hello HTTP 2.0! POST payload: #{buffer}"
else
log.info 'Received GET request'
response = 'Hello HTTP 2.0! GET request'
end
stream.headers({
':status' => '200',
'content-length' => response.bytesize.to_s,
'content-type' => 'text/plain',
}, end_stream: false)
if options[:push]
push_streams = []
# send 10 promises
10.times do |i|
puts 'sending push'
head = { ':method' => 'GET',
':authority' => 'localhost',
':scheme' => 'https',
':path' => "/other_resource/#{i}" }
stream.promise(head) do |push|
push.headers(':status' => '200', 'content-type' => 'text/plain', 'content-length' => '11')
push_streams << push
end
end
end
# split response into multiple DATA frames
stream.data(response.slice!(0, 5), end_stream: false)
stream.data(response)
if options[:push]
push_streams.each_with_index do |push, i|
sleep 1
push.data("push_data #{i}")
end
end
end
end
while !sock.closed? && !(sock.eof? rescue true) # rubocop:disable Style/RescueModifier
data = sock.readpartial(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
end