async-http 0.48.0 → 0.48.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bd79f3f1a3f1c5c5283c9e851433bce5833c18f33b231623fb1e414de078282f
4
- data.tar.gz: bc27cc3ed8568cdd884e09c0889d8d78c3a879bf0117c94c9845f8ea2bd4e5d9
3
+ metadata.gz: 2a0c1192533c40875a7712d03cfa8b43c654b08b28159c0d87db7ebdd4aca4d1
4
+ data.tar.gz: 3b2c33d137af08f87117f8a5c88dae911b148aaebe0bb2e4b91e38191e2b46e8
5
5
  SHA512:
6
- metadata.gz: 5efa88bd4fb17b26b36b434879ff1e2757fdee205d08ee9b5f6a111d867ace9fd2d06ade0b6f895445fc9d5c09057b047d474d80d70f79022644a2af4b3fba0e
7
- data.tar.gz: cd4863983ac3392d88e47c7d5244a5968ea90caa5b906d7335a2ccc42a70f9fd2348bc48a77e9b4e34dad736c83477af39759c6a14d08aff69d1d27775017828
6
+ metadata.gz: c347570d4608e7ccf62b80fbcc07d4d6da83e4dbfdb787655df8e039a7a4d90556d5b0ca0b21a0e1ecf2d13dc00488837730b94fd5ff1d6b160c4e4c2ddb92b0
7
+ data.tar.gz: 9c967f8ebcaaee6f2f14114917f716a0e1464a1dccb44ceda1e0409e409896838ab3a17a2134afd1cbc2ce0a767990ead112d679b89f3b016fc8be0accf58635
data/Gemfile CHANGED
@@ -3,6 +3,8 @@ source 'https://rubygems.org'
3
3
  # Specify your gem's dependencies in async-io.gemspec
4
4
  gemspec
5
5
 
6
+ # gem "protocol-http", path: "../protocol-http"
7
+ # gem "protocol-http1", path: "../protocol-http1"
6
8
  # gem "protocol-http2", path: "../protocol-http2"
7
9
  # gem "protocol-hpack", path: "../protocol-hpack"
8
10
 
@@ -24,7 +24,7 @@ require_relative 'stream'
24
24
  module Async
25
25
  module HTTP
26
26
  module Body
27
- # A body which is designed for hijacked connections.
27
+ # A body which is designed for hijacked server responses - a response which uses a block to read and write the request and response bodies respectively.
28
28
  class Hijack < ::Protocol::HTTP::Body::Readable
29
29
  def self.response(request, status, headers, &block)
30
30
  ::Protocol::HTTP::Response[status, headers, self.wrap(request, &block)]
@@ -46,32 +46,35 @@ module Async
46
46
  # @param length [Integer] the amount of data to read
47
47
  # @param buffer [String] the buffer which will receive the data
48
48
  # @return a buffer containing the data
49
- def read(length = nil, buffer = nil)
49
+ def read(size = nil, buffer = nil)
50
+ return '' if size == 0
51
+
50
52
  buffer ||= Async::IO::Buffer.new
51
- buffer.clear
53
+ if @buffer
54
+ buffer.replace(@buffer)
55
+ @buffer = nil
56
+ end
52
57
 
53
- until buffer.bytesize == length
54
- @buffer = read_next if @buffer.nil?
55
- break if @buffer.nil?
58
+ if size
59
+ while buffer.bytesize < size and chunk = read_next
60
+ buffer << chunk
61
+ end
56
62
 
57
- remaining_length = length - buffer.bytesize if length
63
+ @buffer = buffer.byteslice(size, buffer.bytesize)
64
+ buffer = buffer.byteslice(0, size)
58
65
 
59
- if remaining_length && remaining_length < @buffer.bytesize
60
- # We know that we are not going to reuse the original buffer.
61
- # But byteslice will generate a hidden copy. So let's freeze it first:
62
- @buffer.freeze
63
-
64
- buffer << @buffer.byteslice(0, remaining_length)
65
- @buffer = @buffer.byteslice(remaining_length, @buffer.bytesize)
66
+ if buffer.empty?
67
+ return nil
66
68
  else
67
- buffer << @buffer
68
- @buffer = nil
69
+ return buffer
69
70
  end
71
+ else
72
+ while chunk = read_next
73
+ buffer << chunk
74
+ end
75
+
76
+ return buffer
70
77
  end
71
-
72
- return nil if buffer.empty? && length && length > 0
73
-
74
- return buffer
75
78
  end
76
79
 
77
80
  # Read at most `size` bytes from the stream. Will avoid reading from the underlying stream if possible.
@@ -129,7 +132,6 @@ module Async
129
132
  @input&.close
130
133
  end
131
134
 
132
- # close must never be called on the input stream. huh?
133
135
  def close_write
134
136
  @output&.close
135
137
  end
@@ -97,7 +97,19 @@ module Async
97
97
  alias << write
98
98
 
99
99
  def inspect
100
- "\#<#{self.class} #{@count} chunks written#{@finished ? ', finished' : ', waiting'}>"
100
+ "\#<#{self.class} #{@count} chunks written, #{status}>"
101
+ end
102
+
103
+ private
104
+
105
+ def status
106
+ if @finished
107
+ 'finished'
108
+ elsif @closed
109
+ 'closing'
110
+ else
111
+ 'waiting'
112
+ end
101
113
  end
102
114
  end
103
115
  end
@@ -75,6 +75,11 @@ module Async
75
75
  end
76
76
 
77
77
  def close
78
+ while @pool.busy?
79
+ Async.logger.warn(self) {"Waiting for pool to drain: #{@pool}"}
80
+ @pool.wait
81
+ end
82
+
78
83
  @pool.close
79
84
  end
80
85
 
@@ -47,7 +47,11 @@ module Async
47
47
 
48
48
  @url = url
49
49
 
50
- @endpoint = self.build_endpoint(endpoint)
50
+ if endpoint
51
+ @endpoint = self.build_endpoint(endpoint)
52
+ else
53
+ @endpoint = nil
54
+ end
51
55
  end
52
56
 
53
57
  def to_url
@@ -109,8 +113,8 @@ module Async
109
113
  @options[:scheme] || @url.scheme
110
114
  end
111
115
 
112
- def authority
113
- if default_port?
116
+ def authority(ignore_default_port = true)
117
+ if ignore_default_port and default_port?
114
118
  @url.hostname
115
119
  else
116
120
  "#{@url.hostname}:#{port}"
@@ -34,7 +34,7 @@ module Async
34
34
  endpoint = Endpoint.parse(url)
35
35
 
36
36
  client = @clients.fetch(endpoint) do
37
- @clients[endpoint] = Client.new(endpoint)
37
+ @clients[endpoint] = self.client_for(endpoint)
38
38
  end
39
39
 
40
40
  body = Body::Buffered.wrap(body)
@@ -44,6 +44,10 @@ module Async
44
44
  return client.call(request)
45
45
  end
46
46
 
47
+ def client_for(endpoint)
48
+ Client.new(endpoint)
49
+ end
50
+
47
51
  def close
48
52
  @clients.each_value(&:close)
49
53
  @clients.clear
@@ -25,11 +25,51 @@ require_relative 'body/pipe'
25
25
 
26
26
  module Async
27
27
  module HTTP
28
+ # Wraps a client, address and headers required to initiate a connectio to a remote host using the CONNECT verb.
29
+ # Behaves like a TCP endpoint for the purposes of connecting to a remote host.
28
30
  class Proxy
31
+ module Client
32
+ def proxy(endpoint, headers = [])
33
+ Proxy.new(self, endpoint.authority(false), headers)
34
+ end
35
+
36
+ # Create a client that will proxy requests through the current client.
37
+ def proxied_client(endpoint, headers = [])
38
+ proxy = self.proxy(endpoint, headers)
39
+
40
+ return self.class.new(proxy.wrap_endpoint(endpoint))
41
+ end
42
+
43
+ def proxied_endpoint(endpoint, headers = [])
44
+ proxy = self.proxyfor(endpoint, headers)
45
+
46
+ return proxy.wrap_endpoint(endpoint)
47
+ end
48
+ end
49
+
50
+ # Prepare and endpoint which can establish a TCP connection to the remote system.
51
+ # @param client [Async::HTTP::Client] the client which will be used as a proxy server.
52
+ # @param host [String] the hostname or address to connect to.
53
+ # @param port [String] the port number to connect to.
54
+ # @param headers [Array] an optional list of headers to use when establishing the connection.
55
+ # @see Async::IO::Endpoint#tcp
29
56
  def self.tcp(client, host, port, headers = [])
30
57
  self.new(client, "#{host}:#{port}", headers)
31
58
  end
32
59
 
60
+ # Construct a endpoint that will use the given client as a proxy for HTTP requests.
61
+ # @param client [Async::HTTP::Client] the client which will be used as a proxy server.
62
+ # @param endpoint [Async::HTTP::Endpoint] the endpoint to connect to.
63
+ # @param headers [Array] an optional list of headers to use when establishing the connection.
64
+ def self.endpoint(client, endpoint, headers = [])
65
+ proxy = self.new(client, endpoint.authority(false), headers)
66
+
67
+ return proxy.endpoint(endpoint.url)
68
+ end
69
+
70
+ # @param client [Async::HTTP::Client] the client which will be used as a proxy server.
71
+ # @param address [String] the address to connect to.
72
+ # @param headers [Array] an optional list of headers to use when establishing the connection.
33
73
  def initialize(client, address, headers = [])
34
74
  @client = client
35
75
  @address = address
@@ -38,14 +78,13 @@ module Async
38
78
 
39
79
  attr :client
40
80
 
81
+ # Close the underlying client connection.
41
82
  def close
42
- while @client.pool.busy?
43
- @client.pool.wait
44
- end
45
-
46
83
  @client.close
47
84
  end
48
85
 
86
+ # Establish a TCP connection to the specified host.
87
+ # @return [Socket] a connected bi-directional socket.
49
88
  def connect(&block)
50
89
  input = Body::Writable.new
51
90
 
@@ -62,9 +101,12 @@ module Async
62
101
  end
63
102
  end
64
103
 
65
- def endpoint(url, **options)
66
- Endpoint.parse(url, self, **options)
104
+ # @return [Async::HTTP::Endpoint] an endpoint that connects via the specified proxy.
105
+ def wrap_endpoint(endpoint)
106
+ Endpoint.new(endpoint.url, self, **endpoint.options)
67
107
  end
68
108
  end
109
+
110
+ Client.prepend(Proxy::Client)
69
111
  end
70
112
  end
@@ -20,6 +20,6 @@
20
20
 
21
21
  module Async
22
22
  module HTTP
23
- VERSION = "0.48.0"
23
+ VERSION = "0.48.1"
24
24
  end
25
25
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: async-http
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.48.0
4
+ version: 0.48.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-08-11 00:00:00.000000000 Z
11
+ date: 2019-08-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async