h2 0.6.1 → 0.7.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
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