mieps_http-2 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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