async-http 0.48.0 → 0.48.1

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: 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