http-2 0.8.4 → 0.10.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: df6b5bd32b2217bebfb3205cfab1bd78f2a5456d
4
- data.tar.gz: eb9d683a528819195bf81d4480549b2d8ac7bab6
2
+ SHA256:
3
+ metadata.gz: 8dd78ba6a3468b6a3ceda2ebabc37ceb895a90d675d9fecc035b74d2f479a457
4
+ data.tar.gz: d70542d69e57050ab9ee3c837b6123fea81424a03bf3b99ffdc889a54a2fd20c
5
5
  SHA512:
6
- metadata.gz: 686e87ef8beeedd1f3ac1371845b759687231ba62e3bab532d3d15d65febc179bc19f44d4a025708ecc62e2f0e7dd0689cfbbeef19e47c8ee52df9d050066228
7
- data.tar.gz: 41b003cfeb4a127efcf9d4709167db3ff40934a175a08bd19d23a3874d6dd7e615f99ab967c5b85b521e54a4cdbfce33b4087c6ddde7eebd0d0fc11d18a4d551
6
+ metadata.gz: f678316f6235ed93ce5a3902ef3bf4c48854605de0875054d1f3e05196fc161bdfe49d149ff930413bef5ca76c61ab2d193092867a383f1f5dbe309cfef0f012
7
+ data.tar.gz: 52fce71379a9299df1cd8c93d44964d668d09c199564482193513b109a6339f220b4ae1e724c5965892b3e53855820a810e95405b8eb198797ea130611d39a05
data/.rspec CHANGED
@@ -2,3 +2,4 @@ autotest
2
2
  --color
3
3
  --format documentation
4
4
  --order rand
5
+ --warnings
@@ -8,25 +8,42 @@ AllCops:
8
8
  - 'vendor/**/*'
9
9
  - '**/huffman_statemachine.rb'
10
10
 
11
+ Layout/IndentHeredoc:
12
+ Exclude:
13
+ - 'lib/tasks/generate_huffman_table.rb'
14
+ - 'example/*'
15
+
11
16
  Metrics/LineLength:
12
17
  Max: 120
13
18
 
14
- Lint/EndAlignment:
15
- AlignWith: variable
19
+ Metrics/BlockLength:
20
+ Max: 700
21
+
22
+ Layout/EndAlignment:
23
+ EnforcedStyleAlignWith: variable
16
24
 
17
- Style/CaseIndentation:
18
- IndentWhenRelativeTo: end
25
+ Layout/CaseIndentation:
26
+ EnforcedStyle: end
19
27
 
20
- Style/IndentHash:
28
+ Layout/IndentHash:
21
29
  EnforcedStyle: consistent
22
30
 
23
- Style/TrailingCommaInLiteral:
31
+ Style/TrailingCommaInArrayLiteral:
24
32
  EnforcedStyleForMultiline: comma
25
33
 
26
- Style/SpaceAroundOperators:
34
+ Style/TrailingCommaInHashLiteral:
35
+ EnforcedStyleForMultiline: comma
36
+
37
+ Layout/SpaceAroundOperators:
27
38
  Enabled: false
28
39
 
29
- Style/ExtraSpacing:
40
+ Layout/ExtraSpacing:
41
+ Enabled: false
42
+
43
+ Layout/EmptyLinesAroundExceptionHandlingKeywords:
44
+ Enabled: false
45
+
46
+ Naming/UncommunicativeMethodParamName:
30
47
  Enabled: false
31
48
 
32
49
  Style/SignalException:
@@ -44,14 +61,33 @@ Style/ParenthesesAroundCondition:
44
61
  Style/IfInsideElse:
45
62
  Enabled: false
46
63
 
64
+ Style/IfUnlessModifier:
65
+ Enabled: false
66
+
67
+ Style/MultilineIfModifier:
68
+ Enabled: false
69
+
70
+ Lint/EmptyWhen:
71
+ Enabled: false
72
+
47
73
  Style/TrailingCommaInArguments:
48
74
  Enabled: false
49
75
 
50
76
  Style/TrailingUnderscoreVariable:
51
77
  Enabled: false
52
78
 
79
+ Style/SymbolArray:
80
+ Enabled: false
81
+
82
+ Style/CommentedKeyword:
83
+ Enabled: false
84
+
85
+ Style/PercentLiteralDelimiters:
86
+ Enabled: false
87
+
53
88
  Performance/TimesMap:
54
89
  Enabled: false
55
90
 
56
91
  Performance/RedundantBlockCall:
57
92
  Enabled: false
93
+
@@ -19,6 +19,9 @@ Metrics/BlockNesting:
19
19
  Metrics/ClassLength:
20
20
  Max: 325
21
21
 
22
+ Metrics/ModuleLength:
23
+ Max: 120
24
+
22
25
  # Offense count: 12
23
26
  Metrics/CyclomaticComplexity:
24
27
  Max: 60
@@ -37,7 +40,7 @@ Metrics/MethodLength:
37
40
  # Offense count: 1
38
41
  # Configuration parameters: CountKeywordArgs.
39
42
  Metrics/ParameterLists:
40
- Max: 6
43
+ Max: 7
41
44
 
42
45
  # Offense count: 10
43
46
  Metrics/PerceivedComplexity:
@@ -75,14 +78,14 @@ Style/GuardClause:
75
78
  # Cop supports --auto-correct.
76
79
  # Configuration parameters: SupportedStyles, IndentationWidth.
77
80
  # SupportedStyles: special_inside_parentheses, consistent, align_brackets
78
- Style/IndentArray:
81
+ Layout/IndentArray:
79
82
  EnforcedStyle: consistent
80
83
 
81
84
  # Offense count: 1
82
85
  # Cop supports --auto-correct.
83
86
  # Configuration parameters: EnforcedStyle, SupportedStyles.
84
87
  # SupportedStyles: symmetrical, new_line, same_line
85
- Style/MultilineArrayBraceLayout:
88
+ Layout/MultilineArrayBraceLayout:
86
89
  Exclude:
87
90
  - 'spec/compressor_spec.rb'
88
91
 
@@ -90,7 +93,7 @@ Style/MultilineArrayBraceLayout:
90
93
  # Cop supports --auto-correct.
91
94
  # Configuration parameters: EnforcedStyle, SupportedStyles.
92
95
  # SupportedStyles: symmetrical, new_line, same_line
93
- Style/MultilineHashBraceLayout:
96
+ Layout/MultilineHashBraceLayout:
94
97
  Exclude:
95
98
  - 'spec/compressor_spec.rb'
96
99
 
@@ -5,7 +5,7 @@ rvm:
5
5
  - 2.2
6
6
  - 2.3.0
7
7
  - 2.4.0
8
- - jruby-9.1.8.0
8
+ - jruby-9.2.0.0 # latest stable
9
9
  - jruby-head
10
10
  - rbx-2
11
11
  matrix:
data/Gemfile CHANGED
@@ -10,7 +10,7 @@ group :test do
10
10
  gem 'pry-byebug', platform: :mri
11
11
  gem 'rspec', '~> 3.4.0'
12
12
  gem 'rspec-autotest'
13
- gem 'rubocop', '0.43.0'
13
+ gem 'rubocop', '0.57.2'
14
14
  end
15
15
 
16
16
  gemspec
data/Guardfile CHANGED
@@ -1,4 +1,3 @@
1
-
2
1
  guard :process, name: 'HTTP/2 Server', command: 'ruby example/server.rb', stop_signal: 'TERM' do
3
2
  watch(%r{^example/(.+)\.rb$})
4
3
  watch(%r{^lib/http/2/(.+)\.rb$})
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2013 Ilya Grigorik
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md CHANGED
@@ -1,16 +1,16 @@
1
1
  # HTTP-2
2
2
 
3
- [![Gem Version](https://badge.fury.io/rb/http-2.png)](http://rubygems.org/gems/http-2)
4
- [![Build Status](https://travis-ci.org/igrigorik/http-2.png?branch=master)](https://travis-ci.org/igrigorik/http-2)
5
- [![Coverage Status](https://coveralls.io/repos/igrigorik/http-2/badge.png)](https://coveralls.io/r/igrigorik/http-2)
3
+ [![Gem Version](https://badge.fury.io/rb/http-2.svg)](http://rubygems.org/gems/http-2)
4
+ [![Build Status](https://travis-ci.org/igrigorik/http-2.svg?branch=master)](https://travis-ci.org/igrigorik/http-2)
5
+ [![Coverage Status](https://coveralls.io/repos/igrigorik/http-2/badge.svg)](https://coveralls.io/r/igrigorik/http-2)
6
6
  [![Analytics](https://ga-beacon.appspot.com/UA-71196-10/http-2/readme)](https://github.com/igrigorik/ga-beacon)
7
7
 
8
8
  Pure Ruby, framework and transport agnostic, implementation of HTTP/2 protocol and HPACK header compression with support for:
9
9
 
10
- * [Binary framing](http://chimera.labs.oreilly.com/books/1230000000545/ch12.html#_binary_framing_layer) parsing and encoding
11
- * [Stream multiplexing](http://chimera.labs.oreilly.com/books/1230000000545/ch12.html#HTTP2_STREAMS_MESSAGES_FRAMES) and [prioritization](http://chimera.labs.oreilly.com/books/1230000000545/ch12.html#HTTP2_PRIORITIZATION)
12
- * Connection and stream [flow control](http://chimera.labs.oreilly.com/books/1230000000545/ch12.html#_flow_control)
13
- * [Header compression](http://chimera.labs.oreilly.com/books/1230000000545/ch12.html#HTTP2_HEADER_COMPRESSION) and [server push](http://chimera.labs.oreilly.com/books/1230000000545/ch12.html#HTTP2_PUSH)
10
+ * [Binary framing](https://hpbn.co/http2/#binary-framing-layer) parsing and encoding
11
+ * [Stream multiplexing](https://hpbn.co/http2/#streams-messages-and-frames) and [prioritization](https://hpbn.co/http2/#stream-prioritization)
12
+ * Connection and stream [flow control](https://hpbn.co/http2/#flow-control)
13
+ * [Header compression](https://hpbn.co/http2/#header-compression) and [server push](https://hpbn.co/http2/#server-push)
14
14
  * Connection and stream management
15
15
  * And more... see [API docs](http://www.rubydoc.info/github/igrigorik/http-2/frames)
16
16
 
@@ -88,7 +88,7 @@ Events emitted by the connection object:
88
88
 
89
89
  ### Stream lifecycle management
90
90
 
91
- A single HTTP/2 connection can [multiplex multiple streams](http://chimera.labs.oreilly.com/books/1230000000545/ch12.html#REQUEST_RESPONSE_MULTIPLEXING) in parallel: multiple requests and responses can be in flight simultaneously and stream data can be interleaved and prioritized. Further, the specification provides a well-defined lifecycle for each stream (see below).
91
+ A single HTTP/2 connection can [multiplex multiple streams](https://hpbn.co/http2/#request-and-response-multiplexing) in parallel: multiple requests and responses can be in flight simultaneously and stream data can be interleaved and prioritized. Further, the specification provides a well-defined lifecycle for each stream (see below).
92
92
 
93
93
  The good news is, all of the stream management, and state transitions, and error checking is handled by the library. All you have to do is subscribe to appropriate events (marked with ":" prefix in diagram below) and provide your application logic to handle request and response processing.
94
94
 
@@ -186,7 +186,7 @@ Events emitted by the [Stream object](http://www.rubydoc.info/github/igrigorik/h
186
186
 
187
187
  ### Prioritization
188
188
 
189
- Each HTTP/2 [stream has a priority value](http://chimera.labs.oreilly.com/books/1230000000545/ch12.html#HTTP2_PRIORITIZATION) that can be sent when the new stream is initialized, and optionally reprioritized later:
189
+ Each HTTP/2 [stream has a priority value](https://hpbn.co/http2/#stream-prioritization) that can be sent when the new stream is initialized, and optionally reprioritized later:
190
190
 
191
191
  ```ruby
192
192
  client = HTTP2::Client.new
@@ -203,7 +203,7 @@ On the opposite side, the server can optimize its stream processing order or res
203
203
 
204
204
  ### Flow control
205
205
 
206
- Multiplexing multiple streams over the same TCP connection introduces contention for shared bandwidth resources. Stream priorities can help determine the relative order of delivery, but priorities alone are insufficient to control how the resource allocation is performed between multiple streams. To address this, HTTP/2 provides a simple mechanism for [stream and connection flow control](http://chimera.labs.oreilly.com/books/1230000000545/ch12.html#_flow_control).
206
+ Multiplexing multiple streams over the same TCP connection introduces contention for shared bandwidth resources. Stream priorities can help determine the relative order of delivery, but priorities alone are insufficient to control how the resource allocation is performed between multiple streams. To address this, HTTP/2 provides a simple mechanism for [stream and connection flow control](https://hpbn.co/http2/#flow-control).
207
207
 
208
208
  Connection and stream flow control is handled by the library: all streams are initialized with the default window size (64KB), and send/receive window updates are automatically processed - i.e. window is decremented on outgoing data transfers, and incremented on receipt of window frames. Similarly, if the window is exceeded, then data frames are automatically buffered until window is updated.
209
209
 
@@ -219,16 +219,10 @@ stream.window # check current window size
219
219
  stream.window_update(2048) # increment stream window by 2048 bytes
220
220
  ```
221
221
 
222
- Alternatively, flow control can be disabled by emitting an appropriate settings frame on the connection:
223
-
224
- ```ruby
225
- # limit number of concurrent streams to 100 and disable flow control
226
- conn.settings(streams: 100, window: Float::INFINITY)
227
- ```
228
222
 
229
223
  ### Server push
230
224
 
231
- An HTTP/2 server can [send multiple replies](http://chimera.labs.oreilly.com/books/1230000000545/ch12.html#HTTP2_PUSH) to a single client request. To do so, first it emits a "push promise" frame which contains the headers of the promised resource, followed by the response to the original request, as well as promised resource payloads (which may be interleaved). A simple example is in order:
225
+ An HTTP/2 server can [send multiple replies](https://hpbn.co/http2/#server-push) to a single client request. To do so, first it emits a "push promise" frame which contains the headers of the promised resource, followed by the response to the original request, as well as promised resource payloads (which may be interleaved). A simple example is in order:
232
226
 
233
227
  ```ruby
234
228
  conn = HTTP2::Server.new
@@ -276,10 +270,10 @@ conn.on(:promise) do |push|
276
270
  end
277
271
  ```
278
272
 
279
- The client can cancel any given push stream (via `.close`), or disable server push entirely by sending the appropriate settings frame (note that below setting only impacts server > client direction):
273
+ The client can cancel any given push stream (via `.close`), or disable server push entirely by sending the appropriate settings frame:
280
274
 
281
275
  ```ruby
282
- client.settings(streams: 0) # setting max limit to 0 disables server push
276
+ client.settings(settings_enable_push: 0)
283
277
  ```
284
278
  ### Specs
285
279
 
@@ -55,6 +55,10 @@ conn.on(:frame_received) do |frame|
55
55
  end
56
56
 
57
57
  conn.on(:promise) do |promise|
58
+ promise.on(:promise_headers) do |h|
59
+ log.info "promise request headers: #{h}"
60
+ end
61
+
58
62
  promise.on(:headers) do |h|
59
63
  log.info "promise headers: #{h}"
60
64
  end
@@ -110,7 +114,7 @@ while !sock.closed? && !sock.eof?
110
114
 
111
115
  begin
112
116
  conn << data
113
- rescue => e
117
+ rescue StandardError => e
114
118
  puts "#{e.class} exception: #{e.message} - closing socket."
115
119
  e.backtrace.each { |l| puts "\t" + l }
116
120
  sock.close
@@ -36,9 +36,7 @@ if options[:secure]
36
36
  DRAFT
37
37
  end
38
38
 
39
- ctx.tmp_ecdh_callback = lambda do |*_args|
40
- OpenSSL::PKey::EC.new 'prime256v1'
41
- end
39
+ ctx.ecdh_curves = 'P-256'
42
40
 
43
41
  server = OpenSSL::SSL::SSLServer.new(server, ctx)
44
42
  end
@@ -132,7 +130,7 @@ loop do
132
130
 
133
131
  begin
134
132
  conn << data
135
- rescue => e
133
+ rescue StandardError => e
136
134
  puts "#{e.class} exception: #{e.message} - closing socket."
137
135
  e.backtrace.each { |l| puts "\t" + l }
138
136
  sock.close
@@ -0,0 +1,153 @@
1
+ # frozen_string_literals: true
2
+
3
+ require_relative 'helper'
4
+ require 'http_parser'
5
+
6
+ OptionParser.new do |opts|
7
+ opts.banner = 'Usage: upgrade_client.rb [options]'
8
+ end.parse!
9
+
10
+ uri = URI.parse(ARGV[0] || 'http://localhost:8080/')
11
+ sock = TCPSocket.new(uri.host, uri.port)
12
+
13
+ conn = HTTP2::Client.new
14
+
15
+ def request_header_hash
16
+ Hash.new do |hash, key|
17
+ k = key.to_s.downcase
18
+ k.tr! '_', '-'
19
+ _, value = hash.find { |header_key, _| header_key.downcase == k }
20
+ hash[key] = value if value
21
+ end
22
+ end
23
+
24
+ conn.on(:frame) do |bytes|
25
+ sock.print bytes
26
+ sock.flush
27
+ end
28
+ conn.on(:frame_sent) do |frame|
29
+ puts "Sent frame: #{frame.inspect}"
30
+ end
31
+ conn.on(:frame_received) do |frame|
32
+ puts "Received frame: #{frame.inspect}"
33
+ end
34
+
35
+ # upgrader module
36
+ class UpgradeHandler
37
+ UPGRADE_REQUEST = <<RESP.freeze
38
+ GET %s HTTP/1.1
39
+ Connection: Upgrade, HTTP2-Settings
40
+ HTTP2-Settings: #{HTTP2::Client.settings_header(settings_max_concurrent_streams: 100)}
41
+ Upgrade: h2c
42
+ Host: %s
43
+ User-Agent: http-2 upgrade
44
+ Accept: */*
45
+
46
+ RESP
47
+
48
+ attr_reader :complete, :parsing
49
+ def initialize(conn, sock)
50
+ @conn = conn
51
+ @sock = sock
52
+ @headers = request_header_hash
53
+ @body = ''.b
54
+ @complete, @parsing = false, false
55
+ @parser = ::HTTP::Parser.new(self)
56
+ end
57
+
58
+ def request(uri)
59
+ host = "#{uri.hostname}#{":#{uri.port}" if uri.port != uri.default_port}"
60
+ req = format(UPGRADE_REQUEST, uri.request_uri, host)
61
+ puts req
62
+ @sock << req
63
+ end
64
+
65
+ def <<(data)
66
+ @parsing ||= true
67
+ @parser << data
68
+ return unless complete
69
+ upgrade
70
+ end
71
+
72
+ def complete!
73
+ @complete = true
74
+ end
75
+
76
+ def on_headers_complete(headers)
77
+ @headers.merge!(headers)
78
+ puts "received headers: #{headers}"
79
+ end
80
+
81
+ def on_body(chunk)
82
+ puts "received chunk: #{chunk}"
83
+ @body << chunk
84
+ end
85
+
86
+ def on_message_complete
87
+ fail 'could not upgrade to h2c' unless @parser.status_code == 101
88
+ @parsing = false
89
+ complete!
90
+ end
91
+
92
+ def upgrade
93
+ stream = @conn.upgrade
94
+ log = Logger.new(stream.id)
95
+
96
+ stream.on(:close) do
97
+ log.info 'stream closed'
98
+ end
99
+
100
+ stream.on(:half_close) do
101
+ log.info 'closing client-end of the stream'
102
+ end
103
+
104
+ stream.on(:headers) do |h|
105
+ log.info "response headers: #{h}"
106
+ end
107
+
108
+ stream.on(:data) do |d|
109
+ log.info "response data chunk: <<#{d}>>"
110
+ end
111
+
112
+ stream.on(:altsvc) do |f|
113
+ log.info "received ALTSVC #{f}"
114
+ end
115
+
116
+ @conn.on(:promise) do |promise|
117
+ promise.on(:headers) do |h|
118
+ log.info "promise headers: #{h}"
119
+ end
120
+
121
+ promise.on(:data) do |d|
122
+ log.info "promise data chunk: <<#{d.size}>>"
123
+ end
124
+ end
125
+
126
+ @conn.on(:altsvc) do |f|
127
+ log.info "received ALTSVC #{f}"
128
+ end
129
+ end
130
+ end
131
+
132
+ uh = UpgradeHandler.new(conn, sock)
133
+ puts 'Sending HTTP/1.1 upgrade request'
134
+ uh.request(uri)
135
+
136
+ while !sock.closed? && !sock.eof?
137
+ data = sock.read_nonblock(1024)
138
+
139
+ begin
140
+ if !uh.parsing && !uh.complete
141
+ uh << data
142
+ elsif uh.parsing && !uh.complete
143
+ uh << data
144
+ elsif uh.complete
145
+ conn << data
146
+ end
147
+ rescue StandardError => e
148
+ puts "#{e.class} exception: #{e.message} - closing socket."
149
+ e.backtrace.each { |l| puts "\t" + l }
150
+ conn.close
151
+ sock.close
152
+ end
153
+ end