# Copyright, 2019, by Samuel G. D. Williams. <http://www.codeotaku.com># # Permission is hereby granted, free of charge, to any person obtaining a copy# of this software and associated documentation files (the "Software"), to deal# in the Software without restriction, including without limitation the rights# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell# copies of the Software, and to permit persons to whom the Software is# furnished to do so, subject to the following conditions:# # The above copyright notice and this permission notice shall be included in# all copies or substantial portions of the Software.# # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN# THE SOFTWARE.require_relative'client'require_relative'endpoint'require_relative'body/pipe'moduleAsyncmoduleHTTP# Wraps a client, address and headers required to initiate a connectio to a remote host using the CONNECT verb.# Behaves like a TCP endpoint for the purposes of connecting to a remote host.classProxymoduleClientdefproxy(endpoint,headers=[])Proxy.new(self,endpoint.authority(false),headers)end# Create a client that will proxy requests through the current client.defproxied_client(endpoint,headers=[])proxy=self.proxy(endpoint,headers)returnself.class.new(proxy.wrap_endpoint(endpoint))enddefproxied_endpoint(endpoint,headers=[])proxy=self.proxyfor(endpoint,headers)returnproxy.wrap_endpoint(endpoint)endend# Prepare and endpoint which can establish a TCP connection to the remote system.# @param client [Async::HTTP::Client] the client which will be used as a proxy server.# @param host [String] the hostname or address to connect to.# @param port [String] the port number to connect to.# @param headers [Array] an optional list of headers to use when establishing the connection.# @see Async::IO::Endpoint#tcpdefself.tcp(client,host,port,headers=[])self.new(client,"#{host}:#{port}",headers)end# Construct a endpoint that will use the given client as a proxy for HTTP requests.# @param client [Async::HTTP::Client] the client which will be used as a proxy server.# @param endpoint [Async::HTTP::Endpoint] the endpoint to connect to.# @param headers [Array] an optional list of headers to use when establishing the connection.defself.endpoint(client,endpoint,headers=[])proxy=self.new(client,endpoint.authority(false),headers)returnproxy.endpoint(endpoint.url)end# @param client [Async::HTTP::Client] the client which will be used as a proxy server.# @param address [String] the address to connect to.# @param headers [Array] an optional list of headers to use when establishing the connection.definitialize(client,address,headers=[])@client=client@address=address@headers=headersendattr:client# Close the underlying client connection.defclose@client.closeend# Establish a TCP connection to the specified host.# @return [Socket] a connected bi-directional socket.defconnect(&block)input=Body::Writable.newresponse=@client.connect(@address.to_s,@headers,input)pipe=Body::Pipe.new(response.body,input)returnpipe.to_iounlessblock_given?beginyieldpipe.to_ioensurepipe.closeendend# @return [Async::HTTP::Endpoint] an endpoint that connects via the specified proxy.defwrap_endpoint(endpoint)Endpoint.new(endpoint.url,self,**endpoint.options)endendClient.prepend(Proxy::Client)endend