lib/httpx/plugins/proxy/socks4.rb in httpx-0.3.1 vs lib/httpx/plugins/proxy/socks4.rb in httpx-0.4.0
- old
+ new
@@ -8,62 +8,67 @@
module Proxy
module Socks4
VERSION = 4
CONNECT = 1
GRANTED = 90
+ PROTOCOLS = %w[socks4 socks4a].freeze
Error = Class.new(Error)
- class Socks4ProxyChannel < ProxyChannel
+ module ConnectionMethods
private
- def proxy_connect
- @parser = SocksParser.new(@write_buffer, @options)
- @parser.once(:packet, &method(:on_packet))
- end
-
- def on_packet(packet)
- _version, status, _port, _ip = packet.unpack("CCnN")
- if status == GRANTED
- req, _ = @pending.first
- request_uri = req.uri
- @io = ProxySSL.new(@io, request_uri, @options) if request_uri.scheme == "https"
- transition(:connected)
- throw(:called)
- else
- on_socks_error("socks error: #{status}")
- end
- end
-
def transition(nextstate)
+ return super unless @options.proxy && PROTOCOLS.include?(@options.proxy.uri.scheme)
+
case nextstate
when :connecting
return unless @state == :idle
+
@io.connect
return unless @io.connected?
+
req, _ = @pending.first
return unless req
+
request_uri = req.uri
- @write_buffer << Packet.connect(@parameters, request_uri)
- proxy_connect
+ @write_buffer << Packet.connect(@options.proxy, request_uri)
+ __socks4_proxy_connect
when :connected
return unless @state == :connecting
+
@parser = nil
end
log(level: 1, label: "SOCKS4: ") { "#{nextstate}: #{@write_buffer.to_s.inspect}" } unless nextstate == :open
super
end
- def on_socks_error(message)
+ def __socks4_proxy_connect
+ @parser = SocksParser.new(@write_buffer, @options)
+ @parser.once(:packet, &method(:__socks4_on_packet))
+ end
+
+ def __socks4_on_packet(packet)
+ _version, status, _port, _ip = packet.unpack("CCnN")
+ if status == GRANTED
+ req, _ = @pending.first
+ request_uri = req.uri
+ @io = ProxySSL.new(@io, request_uri, @options) if request_uri.scheme == "https"
+ transition(:connected)
+ throw(:called)
+ else
+ on_socks4_error("socks error: #{status}")
+ end
+ end
+
+ def on_socks4_error(message)
ex = Error.new(message)
ex.set_backtrace(caller)
on_error(ex)
throw(:called)
end
end
- Parameters.register("socks4", Socks4ProxyChannel)
- Parameters.register("socks4a", Socks4ProxyChannel)
class SocksParser
include Callbacks
def initialize(buffer, options)
@@ -90,9 +95,10 @@
def connect(parameters, uri)
packet = [VERSION, CONNECT, uri.port].pack("CCn")
begin
ip = IPAddr.new(uri.host)
raise Error, "Socks4 connection to #{ip} not supported" unless ip.ipv4?
+
packet << [ip.to_i].pack("N")
rescue IPAddr::InvalidAddressError
if parameters.uri.scheme == "socks4"
# resolv defaults to IPv4, and socks4 doesn't support IPv6 otherwise
ip = IPAddr.new(Resolv.getaddress(uri.host))