h2 0.6.1 → 0.7.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9a9868c3d9496207683352704cd152a9d5426ff42cd3aa30035a56981596e957
4
- data.tar.gz: 43e60980d431d769835d4bb15de0cacbb5676c250b1e461c31e4f88c89734c48
3
+ metadata.gz: a59b70f55abe247ca3ae333b72031a32f880fa1844bd8058585a4090bcc55969
4
+ data.tar.gz: d28023b7123b0819c1f540070831188fd99460f11fe9914c2d8c00c7e4dd4e6d
5
5
  SHA512:
6
- metadata.gz: 19e4e75141869144f1ed7b6abf8b6faeb61d00db6466d02ec5264ec7d95ddada0de2914b071dc13a5293885189fea5cb9b235515fc8e282218244d19b5eea08a
7
- data.tar.gz: 50a36bbc351d0dca3cc81750800e2a5085e403bc6019a8620cef8ec5d8977c4e227dcd994656365eb9d75ae03d4fdb0dd9d2e740f2eeccbdf636210f8952dd50
6
+ metadata.gz: a7e502860f2f753ed37f419ba41b78c9399fe8a6278cbfe937ccd7c04f8da0c7fd53fdbc960454ac389a3b4a4073d3a39737a643fdf09235aac281b7f15f67eb
7
+ data.tar.gz: 2dfa20d7aafdc0e37cd61aba4c6a2d9696c4efb58de3786f87c628f08c65bb5437baebdc93dd2acd4f27abde49021f2ac82d58d06ea9d133359d6d9098c8c6b4
data/CHANGELOG.md CHANGED
@@ -1,6 +1,14 @@
1
1
  h2 changelog
2
2
  ============
3
3
 
4
+ ### 0.7.0 2 aug 2018
5
+
6
+ * `Server::Stream::Request#path` now removes query string
7
+ * add `H2::Server::Stream::Request#query_string`
8
+ * `H2::Server::Stream::Response` body now accepts any object that `respond_to? :each`
9
+ * remove Reel completely, base from Celluloid::IO
10
+ * add SSE support
11
+
4
12
  ### 0.6.1 27 jul 2018
5
13
 
6
14
  * fix race between reading and sending first frame
data/Gemfile CHANGED
@@ -2,14 +2,12 @@ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'http-2', path: '../http-2'
6
-
7
5
  group :concurrent_ruby do
8
6
  gem 'concurrent-ruby'
9
7
  end
10
8
 
11
9
  group :celluloid do
12
- gem 'celluloid'
10
+ gem 'celluloid', '~> 0.17', '>= 0.17.3'
13
11
  end
14
12
 
15
13
  group :development, :test do
@@ -17,5 +15,5 @@ group :development, :test do
17
15
  gem 'certificate_authority'
18
16
  gem 'guard-rake'
19
17
  gem 'pry-byebug', platforms: [:mri]
20
- gem 'reel', '0.6.1'
18
+ gem 'celluloid-io', '~> 0.17', '>= 0.17.3'
21
19
  end
data/README.md CHANGED
@@ -12,8 +12,8 @@ H2 uses:
12
12
  ## Server Usage
13
13
 
14
14
  Server API is currently optional, and must be required separately. The server
15
- uses [Reel](https://github.com/celluloid/reel), but since this API is optional,
16
- reel must be separately added to `Gemfile`. It is currently based on `reel-0.6.1`.
15
+ uses [Celluloid::IO](https://github.com/celluloid/celluloid-io), but since this API is optional,
16
+ celluloid-io must be separately added to `Gemfile`. It is currently based on `celluloid-io-0.17.3`.
17
17
 
18
18
  ```ruby
19
19
  require 'h2/server'
@@ -135,9 +135,9 @@ require 'h2/client/celluloid'
135
135
 
136
136
  This will lazily fire up a celluloid pool, with defaults defined by Celluloid.
137
137
 
138
- NOTE: if you've added reel and required the 'h2/server' API, Celluloid will be
139
- loaded in your Ruby VM already; however, you must still require this to have
140
- the client use Celluloid actor pools.
138
+ NOTE: if you've added celluloid-io and required the 'h2/server' API, Celluloid
139
+ will be loaded in your Ruby VM already; however, you must still require this to
140
+ have the client use Celluloid actor pools.
141
141
 
142
142
  #### Concurrent-Ruby ThreadPoolExecutor
143
143
 
data/Rakefile CHANGED
@@ -3,7 +3,7 @@ require "rake/testtask"
3
3
 
4
4
  task default: :test
5
5
 
6
- Rake::TestTask.new :test do |t|
6
+ Rake::TestTask.new :test => ['test:certs'] do |t|
7
7
  t.test_files = FileList['test/**/*_test.rb']
8
8
  end
9
9
 
@@ -18,4 +18,19 @@ namespace :test do
18
18
  end
19
19
  end
20
20
 
21
+ task :certs do
22
+ certs_dir = Pathname.new File.expand_path '../tmp/certs', __FILE__
23
+ ca_file = certs_dir.join('ca.crt').to_s
24
+ require_relative 'test/support/create_certs' unless File.exist? ca_file
25
+ end
26
+
27
+ task :nginx => [:certs] do
28
+ system "docker build -t h2_nginx_http2 test/support/nginx"
29
+ puts "\nstarting nginx with http/2 support"
30
+ puts "using document root: test/support/nginx/"
31
+ puts "using TLS certs: tmp/certs/server.*"
32
+ puts "listening at https://localhost:4430/"
33
+ system "docker run --rm -v `pwd`/tmp/certs:/usr/local/nginx/certs -v `pwd`/test/support/nginx:/usr/local/nginx/html -p 4430:443 -it h2_nginx_http2"
34
+ end
35
+
21
36
  end
@@ -7,8 +7,8 @@ require 'h2/server'
7
7
  H2::Logger.level = ::Logger::DEBUG
8
8
  H2.verbose!
9
9
 
10
- port = 1234
11
- addr = Socket.getaddrinfo('localhost', port).first[3]
10
+ port = 4430
11
+ addr = '127.0.0.1' #Socket.getaddrinfo('localhost', port).first[3]
12
12
  certs_dir = File.expand_path '../../../tmp/certs', __FILE__
13
13
  dog_png = File.read File.expand_path '../dog.png', __FILE__
14
14
  push_promise = '<html><body>wait for it...<img src="/dog.png"/><script src="/pushed.js"></script></body></html>'
@@ -19,6 +19,11 @@ sni = {
19
19
  :cert => certs_dir + '/server.crt',
20
20
  :key => certs_dir + '/server.key',
21
21
  # :extra_chain_cert => certs_dir + '/chain.pem'
22
+ },
23
+ 'vux.nakamura.io' => {
24
+ :cert => certs_dir + '/nakamuraio.crt',
25
+ :key => certs_dir + '/nakamuraio.key',
26
+ :extra_chain_cert => certs_dir + '/nakamuraio-chain.pem'
22
27
  }
23
28
  }
24
29
 
@@ -0,0 +1,103 @@
1
+ #!/usr/bin/env ruby
2
+ # Run with: bundle exec examples/server/sse/sse.rb
3
+
4
+ require 'bundler/setup'
5
+ require 'h2/server'
6
+
7
+ H2::Logger.level = ::Logger::DEBUG
8
+ H2.verbose!
9
+
10
+ port = 4430
11
+ addr = Socket.getaddrinfo('localhost', port).first[3]
12
+ certs_dir = File.expand_path '../../../tmp/certs', __FILE__
13
+ data, key = Hash.new {|h,k| h[k] = ''}, nil
14
+
15
+ sni = {
16
+ 'localhost' => {
17
+ :cert => certs_dir + '/server.crt',
18
+ :key => certs_dir + '/server.key',
19
+ # :extra_chain_cert => certs_dir + '/chain.pem'
20
+ }
21
+ }
22
+
23
+ event_sources = []
24
+
25
+ puts "*** Starting server on https://#{addr}:#{port}"
26
+ s = H2::Server::HTTPS.new host: addr, port: port, sni: sni do |connection|
27
+ connection.each_stream do |stream|
28
+ case stream.request.path
29
+ when '/favicon.ico'
30
+ stream.respond status: 404
31
+
32
+ when '/events'
33
+ es = stream.to_eventsource
34
+ event_sources << es
35
+
36
+ when '/msg'
37
+ if stream.request.method == :post
38
+ msg = stream.request.body
39
+ event_sources.each {|es| es.event name: 'msg', data: msg}
40
+ stream.respond status: 201
41
+ else
42
+ stream.respond status: 404
43
+ end
44
+
45
+ when '/sse.js'
46
+ stream.respond status: 404,
47
+ body: "should have been pushed..."
48
+
49
+ else
50
+ stream.push_promise path: '/sse.js',
51
+ headers: { 'content-type' => 'application/javascript' },
52
+ body: data[:javascript]
53
+
54
+ stream.respond status: 200, body: data[:html]
55
+ end
56
+ end
57
+ end
58
+
59
+ DATA.each_line do |l|
60
+ if l.start_with?('@@')
61
+ key = l.strip[2..-1].to_sym
62
+ else
63
+ data[key] << l
64
+ end
65
+ end
66
+
67
+ sleep
68
+
69
+ __END__
70
+ @@html
71
+ <!DOCTYPE html>
72
+ <html lang="en">
73
+ <head>
74
+ <meta charset="UTF-8">
75
+ <title>SSE example</title>
76
+ <script src="/sse.js"></script>
77
+ </head>
78
+ <body>
79
+ <form id="say">
80
+ say: <input type="text" id="words"/>
81
+ </form>
82
+ <br/>
83
+ <div><ol id="list"></ol></div>
84
+ </body>
85
+ </html>
86
+
87
+ @@javascript
88
+ document.addEventListener('DOMContentLoaded', () => {
89
+ let sse = new EventSource('/events');
90
+ sse.addEventListener('msg', (msg) => {
91
+ let item = document.createElement('li');
92
+ item.innerHTML = msg.data;
93
+ document.getElementById('list').appendChild(item);
94
+ });
95
+
96
+ let w = document.getElementById('words');
97
+ document.getElementById('say').onsubmit = (e) => {
98
+ e.preventDefault();
99
+ fetch('/msg', {method: 'post', body: w.value})
100
+ .then(() => { w.value = ''; });
101
+ };
102
+ w.focus();
103
+ });
data/exe/h2 CHANGED
@@ -136,8 +136,11 @@ if options[:verbose]
136
136
  end
137
137
 
138
138
  puts s.body
139
+ c.block! if options[:block] or !s.pushes.empty?
140
+ s.pushes.each do |p|
141
+ puts "push promise: #{p.headers[':path']}"
142
+ end
139
143
 
140
- c.block! if options[:block]
141
144
  c.goaway if options[:goaway]
142
145
  c.close
143
146
 
data/lib/h2.rb CHANGED
@@ -161,6 +161,22 @@ module H2
161
161
 
162
162
  end
163
163
 
164
+ module HeaderStringifier
165
+
166
+ private
167
+ def stringify_headers hash
168
+ hash.keys.each do |k|
169
+ hash[k] = hash[k].to_s unless String === hash[k]
170
+ if Symbol === k
171
+ key = k.to_s.gsub '_', '-'
172
+ hash[key] = hash.delete k
173
+ end
174
+ end
175
+ hash
176
+ end
177
+
178
+ end
179
+
164
180
  end
165
181
 
166
182
  require 'h2/client'
data/lib/h2/server.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  require 'celluloid/current'
2
- require 'reel'
3
- require 'h2/reel/ext'
2
+ require 'celluloid/io'
4
3
  require 'h2'
5
4
 
6
5
  module H2
@@ -20,13 +19,28 @@ module H2
20
19
 
21
20
  end
22
21
 
23
- # base H2 server, a direct subclass of +Reel::Server+
22
+ # base H2 server, a +Celluoid::IO+ production
24
23
  #
25
- class Server < ::Reel::Server
24
+ class Server
25
+ include Celluloid::IO
26
+
27
+ TCP_DEFAULT_BACKLOG = 100
28
+
29
+ execute_block_on_receiver :initialize
30
+ finalizer :shutdown
26
31
 
27
32
  def initialize server, **options, &on_connection
33
+ @server = server
34
+ @options = options
28
35
  @on_connection = on_connection
29
- super server, options
36
+
37
+ backlog = options.fetch :backlog, TCP_DEFAULT_BACKLOG
38
+ @server.listen backlog
39
+ async.run
40
+ end
41
+
42
+ def shutdown
43
+ @server.close if @server
30
44
  end
31
45
 
32
46
  # build a new connection object, run it through the given block, and
@@ -74,6 +88,10 @@ module H2
74
88
  super @tcpserver, options, &on_connection
75
89
  end
76
90
 
91
+ def run
92
+ loop { async.handle_connection @server.accept }
93
+ end
94
+
77
95
  end
78
96
 
79
97
  end
@@ -52,7 +52,7 @@ module H2
52
52
  # closes this connection's socket if attached
53
53
  #
54
54
  def close
55
- socket.close if socket && attached?
55
+ socket.close if socket && attached? && !closed?
56
56
  end
57
57
 
58
58
  # is this connection's socket closed?
@@ -62,7 +62,6 @@ module H2
62
62
  retry
63
63
  end
64
64
 
65
- socket = ::Reel::Spy.new(socket, @spy) if @spy
66
65
  async.handle_connection socket
67
66
  end
68
67
  end
@@ -9,15 +9,9 @@ module H2
9
9
 
10
10
  # build a new +PushPromise+ for the path, with the headers and body given
11
11
  #
12
- def initialize path, body_or_headers = {}, body = nil
12
+ def initialize path:, headers: {}, body: nil
13
13
  @path = path
14
- if Hash === body_or_headers
15
- headers = body_or_headers.dup
16
- @body = body
17
- else
18
- headers = {}
19
- @body = body_or_headers
20
- end
14
+ @body = body
21
15
 
22
16
  @promise_headers = {
23
17
  METHOD_KEY => GET,
@@ -1,3 +1,4 @@
1
+ require 'h2/server/stream/event_source'
1
2
  require 'h2/server/stream/request'
2
3
  require 'h2/server/stream/response'
3
4
  require 'h2/server/push_promise'
@@ -51,8 +52,8 @@ module H2
51
52
  if @closed
52
53
  log :warn, 'stream closed before response sent'
53
54
  else
54
- response.respond_on(stream)
55
55
  log :info, response
56
+ response.respond_on(stream)
56
57
  @responded = true
57
58
  end
58
59
  end
@@ -72,7 +73,7 @@ module H2
72
73
  headers.merge! AUTHORITY_KEY => @request.authority,
73
74
  SCHEME_KEY => @request.scheme
74
75
 
75
- PushPromise.new path, headers, body
76
+ PushPromise.new path: path, headers: headers, body: body
76
77
  end
77
78
 
78
79
  # begin the new push promise stream from this +@stream+ by sending the
@@ -120,6 +121,16 @@ module H2
120
121
  Logger.__send__ level, "[stream #{@stream.id}] #{msg}"
121
122
  end
122
123
 
124
+ # make this stream into an SSE event source
125
+ #
126
+ # raises +StreamError+ if the request's content-type is not valid
127
+ #
128
+ # @return [H2::Server::Stream::EventSource]
129
+ #
130
+ def to_eventsource headers: {}
131
+ EventSource.new stream: self, headers: headers
132
+ end
133
+
123
134
  protected
124
135
 
125
136
  # bind parser events to this instance
@@ -174,5 +185,7 @@ module H2
174
185
  end
175
186
 
176
187
  end
188
+
189
+ class StreamError < StandardError; end
177
190
  end
178
191
  end
@@ -0,0 +1,91 @@
1
+ module H2
2
+ class Server
3
+ class Stream
4
+ class EventSource
5
+ include HeaderStringifier
6
+
7
+ DATA_TEMPL = "data: %s\n\n"
8
+ EVENT_TEMPL = "event: %s\n#{DATA_TEMPL}"
9
+ SSE_HEADER = {
10
+ STATUS_KEY => '200',
11
+ :content_type => 'text/event-stream'
12
+ }
13
+
14
+ # build and return +EventSource+ instance, ready for pushing out data
15
+ # or named events. checks accept header in the request, then responds
16
+ # with valid headers for beginning an SSE stream
17
+ #
18
+ # @param [H2::Server::Stream] stream: the +Stream+ instance
19
+ # @param [Hash] headers: optional headers to add to the intial response
20
+ #
21
+ # @return [H2::Server::Stream::EventSource]
22
+ #
23
+ def initialize stream:, headers: {}
24
+ @closed = false
25
+ @stream = stream
26
+ @parser = @stream.stream
27
+ @headers = headers
28
+
29
+ check_accept_header
30
+ init_response
31
+ end
32
+
33
+ # checks accept header in the request and raises a +StreamError+ if not
34
+ # valid for SSE
35
+ #
36
+ def check_accept_header
37
+ accept = @stream.request.headers['accept']
38
+ unless accept == SSE_HEADER[:content_type]
39
+ raise StreamError, "invalid header accept: #{accept}"
40
+ end
41
+ end
42
+
43
+ # responds with SSE headers on this stream
44
+ #
45
+ def init_response
46
+ headers = SSE_HEADER.merge @headers
47
+ @parser.headers stringify_headers(headers)
48
+ rescue ::HTTP2::Error::StreamClosed => sc
49
+ @stream.log :warn, "stream closed early by client"
50
+ end
51
+
52
+ # send out a named event with the given data
53
+ #
54
+ # this would be handled by `es.addEventListener('name', (msg)=>{})`
55
+ #
56
+ # @param [String] name: the name of the event
57
+ # @param [String] data: data associated with this event
58
+ #
59
+ def event name:, data:
60
+ e = EVENT_TEMPL % [name, data]
61
+ @parser.data e, end_stream: false
62
+ end
63
+
64
+ # send out a message with the given data
65
+ #
66
+ # this would be handled by `es.onmessage((msg)=>{})`
67
+ #
68
+ # @param [String] data associated with this event
69
+ #
70
+ def data str
71
+ d = DATA_TEMPL % str
72
+ @parser.data d, end_stream: false
73
+ end
74
+
75
+ # emit a final frame on this stream with +end_stream+ flag
76
+ #
77
+ def close
78
+ @parser.data ''
79
+ @closed = true
80
+ end
81
+
82
+ # @return [Boolean] true if this stream is closed
83
+ #
84
+ def closed?
85
+ @closed
86
+ end
87
+
88
+ end
89
+ end
90
+ end
91
+ end
@@ -44,7 +44,18 @@ module H2
44
44
  # retreive the path from the stream request headers
45
45
  #
46
46
  def path
47
- @path ||= headers[PATH_KEY]
47
+ return @path if defined?(@path)
48
+ @path = headers[PATH_KEY]
49
+ @path = @path.split('?').first if @path
50
+ end
51
+
52
+ # retreive the query string from the stream request headers
53
+ #
54
+ def query_string
55
+ return @query_string if defined?(@query_string)
56
+ @query_string = headers[PATH_KEY].index '?'
57
+ return if @query_string.nil?
58
+ @query_string = headers[PATH_KEY][(@query_string + 1)..-1]
48
59
  end
49
60
 
50
61
  # retreive the scheme from the stream request headers
@@ -2,16 +2,26 @@ module H2
2
2
  class Server
3
3
  class Stream
4
4
  class Response
5
+ include HeaderStringifier
5
6
 
6
7
  attr_reader :body, :content_length, :headers, :status, :stream
7
8
 
8
9
  # build a new +Response+ object
9
10
  #
11
+ # @param [H2::Server::Stream] stream: Stream instance associated with this response
12
+ # @param [Integer] status: HTTP status code
13
+ # @param [Hash] headers: response headers
14
+ # @param [String,#each] body: response body. NOTE: may be any object that
15
+ # `respond_to? :each` which both yields and returns
16
+ # String objects.
17
+ #
18
+ # @return [H2::Server::Stream::Response]
19
+ #
10
20
  def initialize stream:, status:, headers: {}, body: ''
11
- @stream = stream
12
- @headers = headers
13
- @body = body
14
- self.status = status
21
+ @stream = stream
22
+ @headers = headers
23
+ @body = body
24
+ @status = status
15
25
 
16
26
  init_content_length
17
27
  end
@@ -19,20 +29,18 @@ module H2
19
29
  # sets the content length in the headers by the byte size of +@body+
20
30
  #
21
31
  def init_content_length
22
- @content_length = case @body
23
- when String
32
+ return if @headers.any? {|k,_| k.downcase == CONTENT_LENGTH_KEY}
33
+ return if @body.respond_to?(:each)
34
+ @content_length = case
35
+ when String === @body
24
36
  @body.bytesize
25
- when IO
26
- @body.stat.size
27
37
  when NilClass
28
38
  '0'
29
39
  else
30
40
  raise TypeError, "can't render #{@body.class} as a response body"
31
41
  end
32
42
 
33
- unless @headers.any? {|k,_| k.downcase == CONTENT_LENGTH_KEY}
34
- @headers[CONTENT_LENGTH_KEY] = @content_length
35
- end
43
+ @headers[CONTENT_LENGTH_KEY] = @content_length
36
44
  end
37
45
 
38
46
  # the corresponding +Request+ to this +Response+
@@ -41,38 +49,21 @@ module H2
41
49
  stream.request
42
50
  end
43
51
 
44
- # send the headers and body out on +s+, an +HTTP2::Stream+ object
52
+ # send the headers and body out on +s+, an +HTTP2::Stream+ object, and
53
+ # close the stream when complete.
45
54
  #
46
55
  # NOTE: +:status+ must come first?
47
56
  #
48
57
  def respond_on s
49
58
  headers = { STATUS_KEY => @status.to_s }.merge @headers
50
59
  s.headers stringify_headers(headers)
51
- case @body
52
- when String
60
+ if String === @body
53
61
  s.data @body
54
- when IO
55
- raise NotImplementedError # TODO
56
- else
57
- end
58
- end
59
-
60
- # sets +@status+ either from given integer value (HTTP status code) or by
61
- # mapping a +Symbol+ in +Reel::Response::SYMBOL_TO_STATUS_CODE+ to one
62
- #
63
- def status= status
64
- case status
65
- when Integer
66
- @status = status
67
- when Symbol
68
- if code = ::Reel::Response::SYMBOL_TO_STATUS_CODE[status]
69
- self.status = code
70
- else
71
- raise ArgumentError, "unrecognized status symbol: #{status}"
72
- end
73
62
  else
74
- raise TypeError, "invalid status type: #{status.inspect}"
63
+ stream.log :error, "unexpected @body: #{caller[0]}"
75
64
  end
65
+ rescue ::HTTP2::Error::StreamClosed => sc
66
+ stream.log :warn, "stream closed early by client"
76
67
  end
77
68
 
78
69
  def to_s
@@ -80,19 +71,6 @@ module H2
80
71
  end
81
72
  alias to_str to_s
82
73
 
83
- private
84
-
85
- def stringify_headers hash
86
- hash.keys.each do |k|
87
- hash[k] = hash[k].to_s unless String === hash[k]
88
- if Symbol === k
89
- key = k.to_s.gsub '_', '-'
90
- hash[key] = hash.delete k
91
- end
92
- end
93
- hash
94
- end
95
-
96
74
  end
97
75
  end
98
76
  end
data/lib/h2/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module H2
2
- VERSION = '0.6.1'
2
+ VERSION = '0.7.0'
3
3
 
4
4
  class << self
5
5
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: h2
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kenichi Nakamura
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-07-27 00:00:00.000000000 Z
11
+ date: 2018-08-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: http-2
@@ -108,6 +108,7 @@ files:
108
108
  - examples/server/hello_world.rb
109
109
  - examples/server/https_hello_world.rb
110
110
  - examples/server/push_promise.rb
111
+ - examples/server/sse.rb
111
112
  - exe/h2
112
113
  - h2.gemspec
113
114
  - lib/h2.rb
@@ -115,12 +116,12 @@ files:
115
116
  - lib/h2/client/celluloid.rb
116
117
  - lib/h2/client/concurrent.rb
117
118
  - lib/h2/client/tcp_socket.rb
118
- - lib/h2/reel/ext.rb
119
119
  - lib/h2/server.rb
120
120
  - lib/h2/server/connection.rb
121
121
  - lib/h2/server/https.rb
122
122
  - lib/h2/server/push_promise.rb
123
123
  - lib/h2/server/stream.rb
124
+ - lib/h2/server/stream/event_source.rb
124
125
  - lib/h2/server/stream/request.rb
125
126
  - lib/h2/server/stream/response.rb
126
127
  - lib/h2/stream.rb
data/lib/h2/reel/ext.rb DELETED
@@ -1,48 +0,0 @@
1
- require 'reel/connection'
2
- require 'reel/request'
3
- require 'reel/server'
4
-
5
- # see also: https://github.com/celluloid/reel/pull/228
6
-
7
-
8
- # this is a little sneaky, not as direct as the PR above, but the least
9
- # invasive way i could come up with to get access to the server from the
10
- # request.
11
-
12
- module Reel
13
-
14
- # we add a `server` accessor to +Connection+...
15
- #
16
- class Request
17
- attr_reader :connection
18
- end
19
-
20
- # ... and a `connection` reader to +Request+.
21
- #
22
- class Connection
23
- attr_accessor :server
24
- end
25
-
26
- end
27
-
28
- module H2
29
- module Reel
30
- module ServerConnection
31
-
32
- # then we hijack +Server+ construction, and wrap the callback at the last
33
- # minute with one that sets the server on every connection, before
34
- # calling the original.
35
- #
36
- def initialize server, options = {}, &callback
37
- super
38
- @og_callback = @callback
39
- @callback = ->(conn) {
40
- conn.server = self
41
- @og_callback[conn]
42
- }
43
- end
44
- end
45
-
46
- ::Reel::Server.prepend ServerConnection
47
- end
48
- end