http-2 0.9.0 → 0.11.0

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: f37bf7f07706136db469b5c188cf13b2995d0c16
4
- data.tar.gz: e51aeb9218b11e3cada90485ba60b5342e89322f
2
+ SHA256:
3
+ metadata.gz: 5617138c0740b55546b79e29a06978a9fcb9aae208ccb2f695c32939eca5f88a
4
+ data.tar.gz: 193880583c0a80aa569f433977af1798c98be25a86fb782a410e16eb38d5116c
5
5
  SHA512:
6
- metadata.gz: 45ca021e60dfe824fcc7bc6bf61d054ce37096a7f0f41ba7c1a5e45f89ad7848f37f4d6638f28d6a93bf6b41f28e8af66abfac28b4fe60d16556d82c1ec78ae3
7
- data.tar.gz: c5bddd633904cd5ff9aef237debbdbcc78a6b901dad857cd5aa770e8d13ea28e26c158c902f9b840185b4a8d7dfe7c8e2acd9b380991426f0b5abdbfa4bc2f2f
6
+ metadata.gz: 46fde2633ab7d074136a32e7ae8cdf90ecd037f3a95bfeabab9557d72a13487a47a3e298339bc74df4d89c6b802537b9c35a1f7709fd6cf1f4fde44eecbe468e
7
+ data.tar.gz: 6eadeb79f3bbf6fa1911933e2dc399bfe50ae08c598cb72278a37e0c42102bf27ccbed77b7acb5e7f1e85a55bd6967e63a8950fa3184fb7c9eef750c8a9e123c
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
@@ -59,6 +62,15 @@ Style/Documentation:
59
62
  - 'example/upgrade_server.rb'
60
63
  - 'lib/tasks/generate_huffman_table.rb'
61
64
 
65
+ # Offense count: 3
66
+ # Cop supports --auto-correct.
67
+ # Configuration parameters: EnforcedStyle.
68
+ # SupportedStyles: braces, no_braces, context_dependent
69
+ Style/BracesAroundHashParameters:
70
+ Exclude:
71
+ - 'spec/connection_spec.rb'
72
+ - 'spec/server_spec.rb'
73
+
62
74
  # Offense count: 1
63
75
  # Cop supports --auto-correct.
64
76
  Style/EmptyCaseCondition:
@@ -75,14 +87,14 @@ Style/GuardClause:
75
87
  # Cop supports --auto-correct.
76
88
  # Configuration parameters: SupportedStyles, IndentationWidth.
77
89
  # SupportedStyles: special_inside_parentheses, consistent, align_brackets
78
- Style/IndentArray:
90
+ Layout/IndentArray:
79
91
  EnforcedStyle: consistent
80
92
 
81
93
  # Offense count: 1
82
94
  # Cop supports --auto-correct.
83
95
  # Configuration parameters: EnforcedStyle, SupportedStyles.
84
96
  # SupportedStyles: symmetrical, new_line, same_line
85
- Style/MultilineArrayBraceLayout:
97
+ Layout/MultilineArrayBraceLayout:
86
98
  Exclude:
87
99
  - 'spec/compressor_spec.rb'
88
100
 
@@ -90,7 +102,7 @@ Style/MultilineArrayBraceLayout:
90
102
  # Cop supports --auto-correct.
91
103
  # Configuration parameters: EnforcedStyle, SupportedStyles.
92
104
  # SupportedStyles: symmetrical, new_line, same_line
93
- Style/MultilineHashBraceLayout:
105
+ Layout/MultilineHashBraceLayout:
94
106
  Exclude:
95
107
  - 'spec/compressor_spec.rb'
96
108
 
@@ -1,11 +1,14 @@
1
- sudo: false
2
1
  language: ruby
2
+ cache: bundler
3
3
  rvm:
4
4
  - 2.1
5
5
  - 2.2
6
- - 2.3.0
7
- - 2.4.0
8
- - jruby-9.1.8.0
6
+ - 2.3
7
+ - 2.4
8
+ - 2.5
9
+ - 2.6
10
+ - 2.7
11
+ - jruby-9.2.0.0 # latest stable
9
12
  - jruby-head
10
13
  - rbx-2
11
14
  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
 
@@ -114,7 +114,7 @@ while !sock.closed? && !sock.eof?
114
114
 
115
115
  begin
116
116
  conn << data
117
- rescue => e
117
+ rescue StandardError => e
118
118
  puts "#{e.class} exception: #{e.message} - closing socket."
119
119
  e.backtrace.each { |l| puts "\t" + l }
120
120
  sock.close
@@ -130,7 +130,7 @@ loop do
130
130
 
131
131
  begin
132
132
  conn << data
133
- rescue => e
133
+ rescue StandardError => e
134
134
  puts "#{e.class} exception: #{e.message} - closing socket."
135
135
  e.backtrace.each { |l| puts "\t" + l }
136
136
  sock.close
@@ -34,7 +34,7 @@ end
34
34
 
35
35
  # upgrader module
36
36
  class UpgradeHandler
37
- UPGRADE_REQUEST = <<-RESP.freeze
37
+ UPGRADE_REQUEST = <<RESP.freeze
38
38
  GET %s HTTP/1.1
39
39
  Connection: Upgrade, HTTP2-Settings
40
40
  HTTP2-Settings: #{HTTP2::Client.settings_header(settings_max_concurrent_streams: 100)}
@@ -73,9 +73,9 @@ RESP
73
73
  @complete = true
74
74
  end
75
75
 
76
- def on_headers_complete(h)
77
- @headers.merge!(h)
78
- puts "received headers: #{h}"
76
+ def on_headers_complete(headers)
77
+ @headers.merge!(headers)
78
+ puts "received headers: #{headers}"
79
79
  end
80
80
 
81
81
  def on_body(chunk)
@@ -144,8 +144,7 @@ while !sock.closed? && !sock.eof?
144
144
  elsif uh.complete
145
145
  conn << data
146
146
  end
147
-
148
- rescue => e
147
+ rescue StandardError => e
149
148
  puts "#{e.class} exception: #{e.message} - closing socket."
150
149
  e.backtrace.each { |l| puts "\t" + l }
151
150
  conn.close
@@ -39,7 +39,7 @@ end
39
39
 
40
40
  class UpgradeHandler
41
41
  VALID_UPGRADE_METHODS = %w(GET OPTIONS).freeze
42
- UPGRADE_RESPONSE = <<-RESP
42
+ UPGRADE_RESPONSE = <<RESP.freeze
43
43
  HTTP/1.1 101 Switching Protocols
44
44
  Connection: Upgrade
45
45
  Upgrade: h2c
@@ -191,7 +191,7 @@ loop do
191
191
  conn << data
192
192
  end
193
193
 
194
- rescue => e
194
+ rescue StandardError => e
195
195
  puts "Exception: #{e}, #{e.message} - closing socket."
196
196
  puts e.backtrace.last(10).join("\n")
197
197
  sock.close
@@ -1,5 +1,4 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
1
+ lib = File.expand_path('./lib', __dir__)
3
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
3
  require 'http/2/version'
5
4
 
@@ -19,5 +18,5 @@ Gem::Specification.new do |spec|
19
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
19
  spec.require_paths = ['lib']
21
20
 
22
- spec.add_development_dependency 'bundler', '~> 1.3'
21
+ spec.add_development_dependency 'bundler'
23
22
  end
@@ -38,6 +38,11 @@ module HTTP2
38
38
  super(frame)
39
39
  end
40
40
 
41
+ def receive(frame)
42
+ send_connection_preface
43
+ super(frame)
44
+ end
45
+
41
46
  # sends the preface and initializes the first stream in half-closed state
42
47
  def upgrade
43
48
  fail ProtocolError unless @stream_id == 1
@@ -51,7 +56,7 @@ module HTTP2
51
56
  @state = :connected
52
57
  emit(:frame, CONNECTION_PREFACE_MAGIC)
53
58
 
54
- payload = @local_settings.select { |k, v| v != SPEC_DEFAULT_CONNECTION_SETTINGS[k] }
59
+ payload = @local_settings.reject { |k, v| v == SPEC_DEFAULT_CONNECTION_SETTINGS[k] }
55
60
  settings(payload)
56
61
  end
57
62
 
@@ -139,12 +139,16 @@ module HTTP2
139
139
  # - http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-10#section-4.1
140
140
  #
141
141
  # @param cmd [Hash] { type:, name:, value:, index: }
142
- # @return [Array] +[name, value]+ header field that is added to the decoded header list
142
+ # @return [Array, nil] +[name, value]+ header field that is added to the decoded header list,
143
+ # or nil if +cmd[:type]+ is +:changetablesize+
143
144
  def process(cmd)
144
145
  emit = nil
145
146
 
146
147
  case cmd[:type]
147
148
  when :changetablesize
149
+ if cmd[:value] > @limit
150
+ fail CompressionError, 'dynamic table size update exceed limit'
151
+ end
148
152
  self.table_size = cmd[:value]
149
153
 
150
154
  when :indexed
@@ -327,7 +331,7 @@ module HTTP2
327
331
  class Compressor
328
332
  # @param options [Hash] encoding options
329
333
  def initialize(**options)
330
- @cc = EncodingContext.new(options)
334
+ @cc = EncodingContext.new(**options)
331
335
  end
332
336
 
333
337
  # Set dynamic table size in EncodingContext
@@ -445,7 +449,8 @@ module HTTP2
445
449
  # @return [Buffer]
446
450
  def encode(headers)
447
451
  buffer = Buffer.new
448
-
452
+ pseudo_headers, regular_headers = headers.partition { |f, _| f.start_with? ':' }
453
+ headers = [*pseudo_headers, *regular_headers]
449
454
  commands = @cc.encode(headers)
450
455
  commands.each do |cmd|
451
456
  buffer << header(cmd)
@@ -465,7 +470,7 @@ module HTTP2
465
470
  class Decompressor
466
471
  # @param options [Hash] decoding options. Only :table_size is effective.
467
472
  def initialize(**options)
468
- @cc = EncodingContext.new(options)
473
+ @cc = EncodingContext.new(**options)
469
474
  end
470
475
 
471
476
  # Set dynamic table size in EncodingContext
@@ -549,8 +554,18 @@ module HTTP2
549
554
  # @return [Array] +[[name, value], ...]+
550
555
  def decode(buf)
551
556
  list = []
552
- list << @cc.process(header(buf)) until buf.empty?
553
- list.compact
557
+ decoding_pseudo_headers = true
558
+ until buf.empty?
559
+ next_header = @cc.process(header(buf))
560
+ next if next_header.nil?
561
+ is_pseudo_header = next_header.first.start_with? ':'
562
+ if !decoding_pseudo_headers && is_pseudo_header
563
+ fail ProtocolError, 'one or more pseudo headers encountered after regular headers'
564
+ end
565
+ decoding_pseudo_headers = is_pseudo_header
566
+ list << next_header
567
+ end
568
+ list
554
569
  end
555
570
  end
556
571
  end