net-http2 0.14.0 → 0.14.1
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 +4 -4
- data/README.md +8 -2
- data/lib/net-http2/client.rb +23 -13
- data/lib/net-http2/request.rb +68 -2
- data/lib/net-http2/socket.rb +54 -3
- data/lib/net-http2/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7ca19f3b01ed565929287e4db629d7c5a3c1522e
|
4
|
+
data.tar.gz: d31dc0fc2f7cf652dcc8bdac6fcc8b31b6721797
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b0b94a8d7e38e0fed916585ff63b8f1686e0cf0ae0107dced66a7de8199155ac62484366fd1808ba2bfeb5e6fc02fb2bcd4cabab061ecfa2833a6bf1621ef22b
|
7
|
+
data.tar.gz: f88d758b5174c933832c003ce996f0a97277bf0b24da7ba517825bcb2eb4a898b8773f56b008fe256eb247ca0a659117a8cc04be0f22f463145e60fb414ab117
|
data/README.md
CHANGED
@@ -75,9 +75,10 @@ client.close
|
|
75
75
|
|
76
76
|
Returns a new client. `url` is a `string` such as `http://nghttp2.org`.
|
77
77
|
The current options are:
|
78
|
-
|
78
|
+
|
79
79
|
* `:connect_timeout`, specifies the max connect timeout in seconds (defaults to 60).
|
80
80
|
* `:ssl_context`, in case the url has an https scheme and you want your SSL client to use a custom context.
|
81
|
+
* `:proxy_addr`, `:proxy_port`, `:proxy_user`, `:proxy_pass`, specify Proxy connection parameters.
|
81
82
|
|
82
83
|
To create a new client:
|
83
84
|
```ruby
|
@@ -105,12 +106,13 @@ These behave similarly to HTTP/1 calls.
|
|
105
106
|
|
106
107
|
Sends a request. Returns `nil` in case a timeout occurs.
|
107
108
|
|
108
|
-
`method` is a symbol that specifies the `:method` header (`:get`, `:post`, `:put`, `:patch`, `:delete`, `:options`). The body and
|
109
|
+
`method` is a symbol that specifies the `:method` header (`:get`, `:post`, `:put`, `:patch`, `:delete`, `:options`). The body, headers and query-string params of the request can be specified in the options, together with the timeout.
|
109
110
|
|
110
111
|
```ruby
|
111
112
|
response_1 = client.call(:get, '/path1')
|
112
113
|
response_2 = client.call(:get, '/path2', headers: { 'x-custom' => 'custom' })
|
113
114
|
response_3 = client.call(:post, '/path3', body: "the request body", timeout: 1)
|
115
|
+
response_3 = client.call(:post, '/path4', params: { page: 4 })
|
114
116
|
```
|
115
117
|
|
116
118
|
##### Non-blocking calls
|
@@ -149,6 +151,10 @@ The real benefit of HTTP/2 is being able to receive body and header streams. Ins
|
|
149
151
|
|
150
152
|
The request's path.
|
151
153
|
|
154
|
+
* **params** → **`hash`**
|
155
|
+
|
156
|
+
The query string params in hash format, for example `{one: 1, two: 2}`. These will be encoded and appended to `path`.
|
157
|
+
|
152
158
|
* **body** → **`string`**
|
153
159
|
|
154
160
|
The request's body.
|
data/lib/net-http2/client.rb
CHANGED
@@ -5,7 +5,8 @@ require 'http/2'
|
|
5
5
|
|
6
6
|
module NetHttp2
|
7
7
|
|
8
|
-
DRAFT
|
8
|
+
DRAFT = 'h2'
|
9
|
+
PROXY_SETTINGS_KEYS = [:proxy_addr, :proxy_port, :proxy_user, :proxy_pass]
|
9
10
|
|
10
11
|
class Client
|
11
12
|
attr_reader :uri
|
@@ -15,6 +16,10 @@ module NetHttp2
|
|
15
16
|
@connect_timeout = options[:connect_timeout] || 60
|
16
17
|
@ssl_context = add_npn_to_context(options[:ssl_context] || OpenSSL::SSL::SSLContext.new)
|
17
18
|
|
19
|
+
PROXY_SETTINGS_KEYS.each do |key|
|
20
|
+
instance_variable_set("@#{key}", options[key]) if options[key]
|
21
|
+
end
|
22
|
+
|
18
23
|
@is_ssl = (@uri.scheme == 'https')
|
19
24
|
|
20
25
|
@mutex = Mutex.new
|
@@ -55,13 +60,15 @@ module NetHttp2
|
|
55
60
|
private
|
56
61
|
|
57
62
|
def init_vars
|
58
|
-
@
|
63
|
+
@mutex.synchronize do
|
64
|
+
@socket.close if @socket && !@socket.closed?
|
59
65
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
66
|
+
@h2 = nil
|
67
|
+
@socket = nil
|
68
|
+
@socket_thread = nil
|
69
|
+
@first_data_sent = false
|
70
|
+
@streams = {}
|
71
|
+
end
|
65
72
|
end
|
66
73
|
|
67
74
|
def new_stream
|
@@ -85,8 +92,7 @@ module NetHttp2
|
|
85
92
|
|
86
93
|
return if @socket_thread
|
87
94
|
|
88
|
-
|
89
|
-
@socket = new_socket
|
95
|
+
@socket = new_socket
|
90
96
|
|
91
97
|
@socket_thread = Thread.new do
|
92
98
|
begin
|
@@ -95,14 +101,14 @@ module NetHttp2
|
|
95
101
|
rescue EOFError
|
96
102
|
# socket closed
|
97
103
|
init_vars
|
98
|
-
|
104
|
+
raise SocketError.new 'Socket was remotely closed'
|
99
105
|
|
100
106
|
rescue Exception => e
|
101
107
|
# error on socket
|
102
108
|
init_vars
|
103
|
-
|
109
|
+
raise e
|
104
110
|
end
|
105
|
-
end
|
111
|
+
end.tap { |t| t.abort_on_exception = true }
|
106
112
|
end
|
107
113
|
end
|
108
114
|
|
@@ -126,7 +132,11 @@ module NetHttp2
|
|
126
132
|
end
|
127
133
|
|
128
134
|
def new_socket
|
129
|
-
|
135
|
+
options = {
|
136
|
+
ssl: ssl?, ssl_context: @ssl_context, connect_timeout: @connect_timeout
|
137
|
+
}
|
138
|
+
PROXY_SETTINGS_KEYS.each { |k| options[k] = instance_variable_get("@#{k}") }
|
139
|
+
NetHttp2::Socket.create(@uri, options)
|
130
140
|
end
|
131
141
|
|
132
142
|
def ensure_sent_before_receiving
|
data/lib/net-http2/request.rb
CHANGED
@@ -1,15 +1,18 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
|
1
3
|
module NetHttp2
|
2
4
|
|
3
5
|
class Request
|
4
6
|
|
5
7
|
DEFAULT_TIMEOUT = 60
|
6
8
|
|
7
|
-
attr_reader :method, :uri, :path, :body, :timeout
|
9
|
+
attr_reader :method, :uri, :path, :params, :body, :timeout
|
8
10
|
|
9
11
|
def initialize(method, uri, path, options={})
|
10
12
|
@method = method
|
11
13
|
@uri = uri
|
12
14
|
@path = path
|
15
|
+
@params = options[:params] || {}
|
13
16
|
@body = options[:body]
|
14
17
|
@headers = options[:headers] || {}
|
15
18
|
@timeout = options[:timeout] || DEFAULT_TIMEOUT
|
@@ -21,7 +24,7 @@ module NetHttp2
|
|
21
24
|
@headers.merge!({
|
22
25
|
':scheme' => @uri.scheme,
|
23
26
|
':method' => @method.to_s.upcase,
|
24
|
-
':path' =>
|
27
|
+
':path' => full_path,
|
25
28
|
})
|
26
29
|
|
27
30
|
@headers.merge!(':authority' => "#{@uri.host}:#{@uri.port}") unless @headers[':authority']
|
@@ -35,6 +38,12 @@ module NetHttp2
|
|
35
38
|
@headers
|
36
39
|
end
|
37
40
|
|
41
|
+
def full_path
|
42
|
+
path = @path
|
43
|
+
path += "?#{to_query(@params)}" unless @params.empty?
|
44
|
+
path
|
45
|
+
end
|
46
|
+
|
38
47
|
def on(event, &block)
|
39
48
|
raise ArgumentError, 'on event must provide a block' unless block_given?
|
40
49
|
|
@@ -46,5 +55,62 @@ module NetHttp2
|
|
46
55
|
return unless @events[event]
|
47
56
|
@events[event].each { |b| b.call(arg) }
|
48
57
|
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
# The to_param and to_query code here below is a free adaptation from the original code in:
|
62
|
+
# <https://github.com/rails/rails/blob/v5.0.0.1/activesupport/lib/active_support/core_ext/object/to_query.rb>
|
63
|
+
# released under the following MIT license:
|
64
|
+
#
|
65
|
+
# Copyright (c) 2005-2016 David Heinemeier Hansson
|
66
|
+
#
|
67
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
68
|
+
# a copy of this software and associated documentation files (the
|
69
|
+
# "Software"), to deal in the Software without restriction, including
|
70
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
71
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
72
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
73
|
+
# the following conditions:
|
74
|
+
#
|
75
|
+
# The above copyright notice and this permission notice shall be
|
76
|
+
# included in all copies or substantial portions of the Software.
|
77
|
+
#
|
78
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
79
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
80
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
81
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
82
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
83
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
84
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
85
|
+
|
86
|
+
def to_param(element)
|
87
|
+
if element.is_a?(TrueClass) || element.is_a?(FalseClass) || element.is_a?(NilClass)
|
88
|
+
element
|
89
|
+
elsif element.is_a?(Array)
|
90
|
+
element.collect(&:to_param).join '/'
|
91
|
+
else
|
92
|
+
element.to_s.strip
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def to_query(element, namespace_or_key = nil)
|
97
|
+
if element.is_a?(Hash)
|
98
|
+
element.collect do |key, value|
|
99
|
+
unless (value.is_a?(Hash) || value.is_a?(Array)) && value.empty?
|
100
|
+
to_query(value, namespace_or_key ? "#{namespace_or_key}[#{key}]" : key)
|
101
|
+
end
|
102
|
+
end.compact.sort! * '&'
|
103
|
+
elsif element.is_a?(Array)
|
104
|
+
prefix = "#{namespace_or_key}[]"
|
105
|
+
|
106
|
+
if element.empty?
|
107
|
+
to_query(nil, prefix)
|
108
|
+
else
|
109
|
+
element.collect { |value| to_query(value, prefix) }.join '&'
|
110
|
+
end
|
111
|
+
else
|
112
|
+
"#{CGI.escape(to_param(namespace_or_key))}=#{CGI.escape(to_param(element).to_s)}"
|
113
|
+
end
|
114
|
+
end
|
49
115
|
end
|
50
116
|
end
|
data/lib/net-http2/socket.rb
CHANGED
@@ -3,15 +3,22 @@ module NetHttp2
|
|
3
3
|
module Socket
|
4
4
|
|
5
5
|
def self.create(uri, options)
|
6
|
-
|
6
|
+
return ssl_socket(uri, options) if options[:ssl]
|
7
|
+
return proxy_tcp_socket(uri, options) if options[:proxy_addr]
|
8
|
+
|
9
|
+
tcp_socket(uri, options)
|
7
10
|
end
|
8
11
|
|
9
12
|
def self.ssl_socket(uri, options)
|
10
|
-
tcp =
|
13
|
+
tcp = if options[:proxy_addr]
|
14
|
+
proxy_tcp_socket(uri, options)
|
15
|
+
else
|
16
|
+
tcp_socket(uri, options)
|
17
|
+
end
|
11
18
|
|
12
19
|
socket = OpenSSL::SSL::SSLSocket.new(tcp, options[:ssl_context])
|
13
20
|
socket.sync_close = true
|
14
|
-
socket.hostname = uri.
|
21
|
+
socket.hostname = options[:proxy_addr] || uri.host
|
15
22
|
|
16
23
|
socket.connect
|
17
24
|
|
@@ -46,5 +53,49 @@ module NetHttp2
|
|
46
53
|
|
47
54
|
socket
|
48
55
|
end
|
56
|
+
|
57
|
+
def self.proxy_tcp_socket(uri, options)
|
58
|
+
proxy_addr = options[:proxy_addr]
|
59
|
+
proxy_port = options[:proxy_port]
|
60
|
+
proxy_user = options[:proxy_user]
|
61
|
+
proxy_pass = options[:proxy_pass]
|
62
|
+
|
63
|
+
proxy_uri = URI.parse("#{proxy_addr}:#{proxy_port}")
|
64
|
+
proxy_socket = tcp_socket(proxy_uri, options)
|
65
|
+
|
66
|
+
# The majority of proxies do not explicitly support HTTP/2 protocol,
|
67
|
+
# while they successfully create a TCP tunnel
|
68
|
+
# which can pass through binary data of HTTP/2 connection.
|
69
|
+
# So we’ll keep HTTP/1.1
|
70
|
+
http_version = '1.1'
|
71
|
+
|
72
|
+
buf = "CONNECT #{uri.host}:#{uri.port} HTTP/#{http_version}\r\n"
|
73
|
+
buf << "Host: #{uri.host}:#{uri.port}\r\n"
|
74
|
+
if proxy_user
|
75
|
+
credential = ["#{proxy_user}:#{proxy_pass}"].pack('m')
|
76
|
+
credential.delete!("\r\n")
|
77
|
+
buf << "Proxy-Authorization: Basic #{credential}\r\n"
|
78
|
+
end
|
79
|
+
buf << "\r\n"
|
80
|
+
proxy_socket.write(buf)
|
81
|
+
validate_proxy_response!(proxy_socket)
|
82
|
+
|
83
|
+
proxy_socket
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def self.validate_proxy_response!(socket)
|
89
|
+
result = ''
|
90
|
+
loop do
|
91
|
+
line = socket.gets
|
92
|
+
break if !line || line.strip.empty?
|
93
|
+
|
94
|
+
result << line
|
95
|
+
end
|
96
|
+
return if result =~ /HTTP\/\d(?:\.\d)?\s+2\d\d\s/
|
97
|
+
|
98
|
+
raise(StandardError, "Proxy connection failure:\n#{result}")
|
99
|
+
end
|
49
100
|
end
|
50
101
|
end
|
data/lib/net-http2/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: net-http2
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.14.
|
4
|
+
version: 0.14.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Roberto Ostinelli
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-12-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: http-2
|