mieps_http-2 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,27 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ MIIEowIBAAKCAQEAzG/uarM0xVUWgGOo5JTLZw0z1zrqBOBUuv2yygtTRMLhuJjU
3
+ H8qgPsb0i97o/B92mKmAZj6248d8TMEIIcPt7ERHU0uelZq6jovCHfA6O6jkSvqS
4
+ WAEYW4djHyMnaMHAIW9NwbbMlF51T89vLoVrbtfppzB9oC1F4blg4ezxhGaDgSta
5
+ p9G5ygzfOPy+8xae6yEyFhDGjURUsnYS+9scSSKnhqmmuj7ZCXQpjhdPcSgxNEcg
6
+ JuiUr+5Bih7Sa6wqfAIY+DY0vp7bu6+Ljsbsasilx/cc3gdkyg7Mny2LsggSQXR9
7
+ VOBARWSW4id+d53r1YLDF5wxBmzmx0G7ATcqHQIDAQABAoIBACybj85AZBdaxZom
8
+ JMgbn3ZQ7yrbdAy0Vkim6sgjSHwMeewpjL+TGvwXtWx/qx64Tsxoz9d/f7Cb6odk
9
+ 5z1W3ydajqWiLmw+Ys6PuD+IF2zFIWsq2ZvSQVpXZE17AjJddGrXOoQ2OtV09uv/
10
+ OydPfW2mNxl//ylgN4tVQ8qIRPq6b1GWWZvjTw4K3jPrlAifobYBBR+BSk446O7F
11
+ iGvax5lNNCDMN2y+6hlnhlTHuvc0DXQA0XBhWTNYu8BNNrvC3I31RmxdY7Frm7IA
12
+ RUGy/l2kLHCRCTF8Q0C4ydpE5ZFgpxkWK7p3QEv/gnVAwsOSN/nThdoorWWHTbNl
13
+ pA5l1RECgYEA/ASaS9mqWWthUkOW51L6c7IIiRPAhrbPnx1mkAtUPeehHn1+G8Qu
14
+ upUEXslWokhmQ3UAGhrId6FVYsfftNPMNck9mv4ntW7MoZLXZqTiFSqx4pQTjoYg
15
+ PQ4c/jrQLsmislcKTiVx6kFYFcnI1ayXXEtaby0lri8XsAR5F90OpycCgYEAz6re
16
+ DR5EZZKx61wyEfuPWE6aACWlEqlbTa8nTMddxnZUZXtzbwRFapGfs+uHCURF0dGj
17
+ 37cl4q8JdGbbYePk9nlOC4RoSw8Zh3fB4yRSZocB4yB047ofpBmt4BigGtgZ5BLZ
18
+ zqVREgBUI+tFPPHkMmBY4lCaUsCe11SEwyZFzxsCgYEA3nRNonBy/tVbJZtFw9Eq
19
+ BB/9isolooQRxrjUBIgLh01Dmj9ZprbILKhHIEgGsd7IbfkD6wcDNx3w2e3mGJ7v
20
+ 3fZR69M2R9+Sv3h3rEIU0mxKct8UWDUqldo0W3CcvP/9HgDYttw0rnuZfjoMjhf3
21
+ z18wZ3xpi1RES3nXTeox+fcCgYBlPxkjrC4Ml4jHBxwiSFOK6keK6s+gWZF6Pnsa
22
+ o9jEecyL7bRJ2/s8CeOjBKHBkte3hE4xNEn0SwKBDeTHxSRMRrgWRWfTsHjx4yFU
23
+ bND/y7LP2XMj1Aq5JwvuxhLJA7Mbz1UBuvfbnu1m1b3cCNMI/JBZRpL25ZKLyVkx
24
+ C+fdIQKBgA+tLeF10zqGGc4269b6nQWplc5E/qnIRK0cfnKb9BtffmA4FbjUpZKj
25
+ +cGmbtbw7ySkAIKLp4HoJmzkXJageGTSEb/sQIodxMiJCGvvgJmPPnGzU8OiUGAl
26
+ VmRjuAQ2eCcsUyvrJYgKW9UWskqSe6z5w/Uxo/sZdHlaGljNdKcn
27
+ -----END RSA PRIVATE KEY-----
data/example/server.rb ADDED
@@ -0,0 +1,97 @@
1
+ require_relative 'helper'
2
+
3
+ options = { port: 8080 }
4
+ OptionParser.new do |opts|
5
+ opts.banner = 'Usage: server.rb [options]'
6
+
7
+ opts.on('-s', '--secure', 'HTTPS mode') do |v|
8
+ options[:secure] = v
9
+ end
10
+
11
+ opts.on('-p', '--port [Integer]', 'listen port') do |v|
12
+ options[:port] = v
13
+ end
14
+ end.parse!
15
+
16
+ puts "Starting server on port #{options[:port]}"
17
+ server = TCPServer.new(options[:port])
18
+
19
+ if options[:secure]
20
+ ctx = OpenSSL::SSL::SSLContext.new
21
+ ctx.cert = OpenSSL::X509::Certificate.new(File.open('keys/mycert.pem'))
22
+ ctx.key = OpenSSL::PKey::RSA.new(File.open('keys/mykey.pem'))
23
+ ctx.npn_protocols = [DRAFT]
24
+
25
+ server = OpenSSL::SSL::SSLServer.new(server, ctx)
26
+ end
27
+
28
+ loop do
29
+ sock = server.accept
30
+ puts 'New TCP connection!'
31
+
32
+ conn = HTTP2::Server.new
33
+ conn.on(:frame) do |bytes|
34
+ # puts "Writing bytes: #{bytes.unpack("H*").first}"
35
+ sock.write bytes
36
+ end
37
+ conn.on(:frame_sent) do |frame|
38
+ puts "Sent frame: #{frame.inspect}"
39
+ end
40
+ conn.on(:frame_received) do |frame|
41
+ puts "Received frame: #{frame.inspect}"
42
+ end
43
+
44
+ conn.on(:stream) do |stream|
45
+ log = Logger.new(stream.id)
46
+ req, buffer = {}, ''
47
+
48
+ stream.on(:active) { log.info 'cliend opened new stream' }
49
+ stream.on(:close) { log.info 'stream closed' }
50
+
51
+ stream.on(:headers) do |h|
52
+ req = Hash[*h.flatten]
53
+ log.info "request headers: #{h}"
54
+ end
55
+
56
+ stream.on(:data) do |d|
57
+ log.info "payload chunk: <<#{d}>>"
58
+ buffer << d
59
+ end
60
+
61
+ stream.on(:half_close) do
62
+ log.info 'client closed its end of the stream'
63
+
64
+ response = nil
65
+ if req[':method'] == 'POST'
66
+ log.info "Received POST request, payload: #{buffer}"
67
+ response = "Hello HTTP 2.0! POST payload: #{buffer}"
68
+ else
69
+ log.info 'Received GET request'
70
+ response = 'Hello HTTP 2.0! GET request'
71
+ end
72
+
73
+ stream.headers({
74
+ ':status' => '200',
75
+ 'content-length' => response.bytesize.to_s,
76
+ 'content-type' => 'text/plain',
77
+ }, end_stream: false)
78
+
79
+ # split response into multiple DATA frames
80
+ stream.data(response.slice!(0, 5), end_stream: false)
81
+ stream.data(response)
82
+ end
83
+ end
84
+
85
+ while !sock.closed? && !(sock.eof? rescue true) # rubocop:disable Style/RescueModifier
86
+ data = sock.readpartial(1024)
87
+ # puts "Received bytes: #{data.unpack("H*").first}"
88
+
89
+ begin
90
+ conn << data
91
+ rescue => e
92
+ puts "#{e.class} exception: #{e.message} - closing socket."
93
+ e.backtrace.each { |l| puts "\t" + l }
94
+ sock.close
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,193 @@
1
+ require_relative 'helper'
2
+ require 'http_parser'
3
+ require 'base64'
4
+
5
+ options = { port: 8080 }
6
+ OptionParser.new do |opts|
7
+ opts.banner = 'Usage: server.rb [options]'
8
+
9
+ opts.on('-s', '--secure', 'HTTPS mode') do |v|
10
+ options[:secure] = v
11
+ end
12
+
13
+ opts.on('-p', '--port [Integer]', 'listen port') do |v|
14
+ options[:port] = v
15
+ end
16
+ end.parse!
17
+
18
+ puts "Starting server on port #{options[:port]}"
19
+ server = TCPServer.new(options[:port])
20
+
21
+ if options[:secure]
22
+ ctx = OpenSSL::SSL::SSLContext.new
23
+ ctx.cert = OpenSSL::X509::Certificate.new(File.open('keys/mycert.pem'))
24
+ ctx.key = OpenSSL::PKey::RSA.new(File.open('keys/mykey.pem'))
25
+ ctx.npn_protocols = [DRAFT]
26
+
27
+ server = OpenSSL::SSL::SSLServer.new(server, ctx)
28
+ end
29
+
30
+ class UpgradeHandler
31
+ VALID_UPGRADE_METHODS = %w(GET OPTIONS)
32
+ UPGRADE_RESPONSE = <<-RESP
33
+ HTTP/1.1 101 Switching Protocols
34
+ Connection: Upgrade
35
+ Upgrade: h2c
36
+
37
+ RESP
38
+
39
+ attr_reader :complete, :headers, :body, :parsing
40
+
41
+ def initialize(conn, sock)
42
+ @conn, @sock = conn, sock
43
+ @complete, @parsing = false, false
44
+ @body = ''
45
+ @parser = ::HTTP::Parser.new(self)
46
+ end
47
+
48
+ def <<(data)
49
+ @parsing ||= true
50
+ @parser << data
51
+ return unless complete
52
+
53
+ @sock.write UPGRADE_RESPONSE
54
+
55
+ settings = headers['http2-settings']
56
+ request = {
57
+ ':scheme' => 'http',
58
+ ':method' => @parser.http_method,
59
+ ':authority' => headers['Host'],
60
+ ':path' => @parser.request_url,
61
+ }.merge(headers)
62
+
63
+ @conn.upgrade(settings, request, @body)
64
+ end
65
+
66
+ def complete!
67
+ @complete = true
68
+ end
69
+
70
+ def on_headers_complete(headers)
71
+ @headers = headers
72
+ end
73
+
74
+ def on_body(chunk)
75
+ @body << chunk
76
+ end
77
+
78
+ def on_message_complete
79
+ fail unless VALID_UPGRADE_METHODS.include?(@parser.http_method)
80
+ @parsing = false
81
+ complete!
82
+ end
83
+ end
84
+
85
+ loop do
86
+ sock = server.accept
87
+ puts 'New TCP connection!'
88
+
89
+ conn = HTTP2::Server.new
90
+ conn.on(:frame) do |bytes|
91
+ # puts "Writing bytes: #{bytes.unpack("H*").first}"
92
+ sock.write bytes
93
+ end
94
+ conn.on(:frame_sent) do |frame|
95
+ puts "Sent frame: #{frame.inspect}"
96
+ end
97
+ conn.on(:frame_received) do |frame|
98
+ puts "Received frame: #{frame.inspect}"
99
+ end
100
+
101
+ conn.on(:stream) do |stream|
102
+ log = Logger.new(stream.id)
103
+ req, buffer = {}, ''
104
+
105
+ stream.on(:active) { log.info 'client opened new stream' }
106
+ stream.on(:close) do
107
+ log.info 'stream closed'
108
+ end
109
+
110
+ stream.on(:headers) do |h|
111
+ req = Hash[*h.flatten]
112
+ log.info "request headers: #{h}"
113
+ end
114
+
115
+ stream.on(:data) do |d|
116
+ log.info "payload chunk: <<#{d}>>"
117
+ buffer << d
118
+ end
119
+
120
+ stream.on(:half_close) do
121
+ log.info 'client closed its end of the stream'
122
+
123
+ if req['Upgrade']
124
+ log.info "Processing h2c Upgrade request: #{req}"
125
+
126
+ # Don't respond to OPTIONS...
127
+ if req[':method'] != 'OPTIONS'
128
+ response = 'Hello h2c world!'
129
+ stream.headers({
130
+ ':status' => '200',
131
+ 'content-length' => response.bytesize.to_s,
132
+ 'content-type' => 'text/plain',
133
+ }, end_stream: false)
134
+ stream.data(response)
135
+ end
136
+ else
137
+
138
+ response = nil
139
+ if req[':method'] == 'POST'
140
+ log.info "Received POST request, payload: #{buffer}"
141
+ response = "Hello HTTP 2.0! POST payload: #{buffer}"
142
+ else
143
+ log.info 'Received GET request'
144
+ response = 'Hello HTTP 2.0! GET request'
145
+ end
146
+
147
+ stream.headers({
148
+ ':status' => '200',
149
+ 'content-length' => response.bytesize.to_s,
150
+ 'content-type' => 'text/plain',
151
+ }, end_stream: false)
152
+
153
+ # split response into multiple DATA frames
154
+ stream.data(response.slice!(0, 5), end_stream: false)
155
+ stream.data(response)
156
+ end
157
+ end
158
+ end
159
+
160
+ uh = UpgradeHandler.new(conn, sock)
161
+
162
+ while !sock.closed? && !(sock.eof? rescue true) # rubocop:disable Style/RescueModifier
163
+ data = sock.readpartial(1024)
164
+ # puts "Received bytes: #{data.unpack("H*").first}"
165
+
166
+ begin
167
+ case
168
+ when !uh.parsing && !uh.complete
169
+
170
+ if data.start_with?(*UpgradeHandler::VALID_UPGRADE_METHODS)
171
+ uh << data
172
+ else
173
+ uh.complete!
174
+ conn << data
175
+ end
176
+
177
+ when uh.parsing && !uh.complete
178
+ uh << data
179
+
180
+ when uh.complete
181
+ conn << data
182
+ end
183
+
184
+ rescue => e
185
+ puts "Exception: #{e}, #{e.message} - closing socket."
186
+ puts e.backtrace.last(10).join("\n")
187
+ sock.close
188
+ end
189
+ end
190
+ end
191
+
192
+ # echo foo=bar | nghttp -d - -t 0 -vu http://127.0.0.1:8080/
193
+ # nghttp -vu http://127.0.0.1:8080/
data/http-2.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'http/2/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'mieps_http-2'
8
+ spec.version = HTTP2::VERSION
9
+ spec.authors = ['Ilya Grigorik', 'Kaoru Maeda']
10
+ spec.email = ['ilya@igvita.com']
11
+ spec.description = 'Fork of Pure-ruby HTTP 2.0 protocol implementation - https://github.com/igrigorik/http-2'
12
+ spec.summary = spec.description
13
+ spec.homepage = ''
14
+ spec.license = 'MIT'
15
+ spec.required_ruby_version = '>=2.1.0'
16
+
17
+ spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = ['lib']
21
+
22
+ spec.add_development_dependency 'bundler', '~> 1.3'
23
+ end
@@ -0,0 +1,34 @@
1
+ module HTTP2
2
+ # Simple binary buffer backed by string.
3
+ #
4
+ class Buffer < String
5
+ UINT32 = 'N'.freeze
6
+ private_constant :UINT32
7
+
8
+ # Forces binary encoding on the string
9
+ def initialize(*)
10
+ super.force_encoding(Encoding::BINARY)
11
+ end
12
+
13
+ # Emulate StringIO#read: slice first n bytes from the buffer.
14
+ #
15
+ # @param n [Integer] number of bytes to slice from the buffer
16
+ def read(n)
17
+ Buffer.new(slice!(0, n))
18
+ end
19
+
20
+ # Alias getbyte to readbyte
21
+ alias_method :readbyte, :getbyte
22
+
23
+ # Emulate StringIO#getbyte: slice first byte from buffer.
24
+ def getbyte
25
+ read(1).ord
26
+ end
27
+
28
+ # Slice unsigned 32-bit integer from buffer.
29
+ # @return [Integer]
30
+ def read_uint32
31
+ read(4).unpack(UINT32).first
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,51 @@
1
+ module HTTP2
2
+ # HTTP 2.0 client connection class that implements appropriate header
3
+ # compression / decompression algorithms and stream management logic.
4
+ #
5
+ # Your code is responsible for driving the client object, which in turn
6
+ # performs all of the necessary HTTP 2.0 encoding / decoding, state
7
+ # management, and the rest. A simple example:
8
+ #
9
+ # @example
10
+ # socket = YourTransport.new
11
+ #
12
+ # conn = HTTP2::Client.new
13
+ # conn.on(:frame) {|bytes| socket << bytes }
14
+ #
15
+ # while bytes = socket.read
16
+ # conn << bytes
17
+ # end
18
+ #
19
+ class Client < Connection
20
+ # Initialize new HTTP 2.0 client object.
21
+ def initialize(**settings)
22
+ @stream_id = 1
23
+ @state = :waiting_connection_preface
24
+
25
+ @local_role = :client
26
+ @remote_role = :server
27
+
28
+ super
29
+ end
30
+
31
+ # Send an outgoing frame. Connection and stream flow control is managed
32
+ # by Connection class.
33
+ #
34
+ # @see Connection
35
+ # @param frame [Hash]
36
+ def send(frame)
37
+ send_connection_preface
38
+ super(frame)
39
+ end
40
+
41
+ # Emit the connection preface if not yet
42
+ def send_connection_preface
43
+ return unless @state == :waiting_connection_preface
44
+ @state = :connected
45
+ emit(:frame, CONNECTION_PREFACE_MAGIC)
46
+
47
+ payload = @local_settings.select { |k, v| v != SPEC_DEFAULT_CONNECTION_SETTINGS[k] }
48
+ settings(payload)
49
+ end
50
+ end
51
+ end