lib/net/ssh/proxy/http.rb in net-ssh-1.1.4 vs lib/net/ssh/proxy/http.rb in net-ssh-2.0.0
- old
+ new
@@ -1,126 +1,94 @@
-#--
-# =============================================================================
-# Copyright (c) 2004,2005 Jamis Buck (jamis@37signals.com)
-# All rights reserved.
-#
-# This source file is distributed as part of the Net::SSH Secure Shell Client
-# library for Ruby. This file (and the library as a whole) may be used only as
-# allowed by either the BSD license, or the Ruby license (or, by association
-# with the Ruby license, the GPL). See the "doc" subdirectory of the Net::SSH
-# distribution for the texts of these licenses.
-# -----------------------------------------------------------------------------
-# net-ssh website : http://net-ssh.rubyforge.org
-# project website: http://rubyforge.org/projects/net-ssh
-# =============================================================================
-#++
-
require 'socket'
-require 'base64'
require 'net/ssh/proxy/errors'
-module Net
- module SSH
- module Proxy
+module Net; module SSH; module Proxy
- # An implementation of a socket factory that returns a socket which
- # will tunnel the connection through an HTTP proxy. It allows explicit
- # specification of the user and password, but if none are given it
- # will look in the HTTP_PROXY_USER/HTTP_PROXY_PASSWORD and
- # CONNECT_USER/CONNECT_PASSWORD environment variables as well.
- class HTTP
+ # An implementation of an HTTP proxy. To use it, instantiate it, then
+ # pass the instantiated object via the :proxy key to Net::SSH.start:
+ #
+ # require 'net/ssh/proxy/http'
+ #
+ # proxy = Net::SSH::Proxy::HTTP.new('proxy.host', proxy_port)
+ # Net::SSH.start('host', 'user', :proxy => proxy) do |ssh|
+ # ...
+ # end
+ #
+ # If the proxy requires authentication, you can pass :user and :password
+ # to the proxy's constructor:
+ #
+ # proxy = Net::SSH::Proxy::HTTP.new('proxy.host', proxy_port,
+ # :user => "user", :password => "password")
+ #
+ # Note that HTTP digest authentication is not supported; Basic only at
+ # this point.
+ class HTTP
- # Create a new socket factory that tunnels via the given host and
- # port.
- def initialize( proxy_host, proxy_port=80, options={} )
- @proxy_host = proxy_host
- @proxy_port = proxy_port
- @options = options
- end
+ # The hostname or IP address of the HTTP proxy.
+ attr_reader :proxy_host
- # Return a new socket connected to the given host and port via the
- # proxy that was requested when the socket factory was instantiated.
- def open( host, port )
- connect_string = "CONNECT #{host}:#{port} HTTP/1.0"
+ # The port number of the proxy.
+ attr_reader :proxy_port
- socket = TCPSocket.new( @proxy_host, @proxy_port )
- socket.puts connect_string
- socket.puts
+ # The map of additional options that were given to the object at
+ # initialization.
+ attr_reader :options
- resp = parse_response( socket )
+ # Create a new socket factory that tunnels via the given host and
+ # port. The +options+ parameter is a hash of additional settings that
+ # can be used to tweak this proxy connection. Specifically, the following
+ # options are supported:
+ #
+ # * :user => the user name to use when authenticating to the proxy
+ # * :password => the password to use when authenticating
+ def initialize(proxy_host, proxy_port=80, options={})
+ @proxy_host = proxy_host
+ @proxy_port = proxy_port
+ @options = options
+ end
- return socket if resp[:code] == 200
+ # Return a new socket connected to the given host and port via the
+ # proxy that was requested when the socket factory was instantiated.
+ def open(host, port)
+ socket = TCPSocket.new(proxy_host, proxy_port)
+ socket.write "CONNECT #{host}:#{port} HTTP/1.0\r\n"
- socket.shutdown
- raise ConnectError, resp.inspect unless resp[:code] == 407
+ if options[:user]
+ credentials = ["#{options[:user]}:#{options[:password]}"].pack("m*").gsub(/\s/, "")
+ socket.write "Proxy-Authorization: Basic #{credentials}\r\n"
+ end
- user = proxy_user
- passwd = proxy_password
+ socket.write "\r\n"
- raise UnauthorizedError, "no proxy user given" unless user
+ resp = parse_response(socket)
- auth = resp[:headers]["Proxy-Authenticate"]
- scheme, parms = auth.split( / /, 2 )
+ return socket if resp[:code] == 200
- case scheme
- when "Basic"
- credentials =
- Base64.encode64( "#{user}:#{passwd}" ).gsub( /\n/, "" )
- else
- raise NotImplementedError,
- "authorization scheme #{scheme.inspect} is not supported"
- end
+ socket.close
+ raise ConnectError, resp.inspect
+ end
- socket = TCPSocket.new( @proxy_host, @proxy_port )
- socket.puts connect_string
- socket.puts "Proxy-Authorization: #{scheme} #{credentials}"
- socket.puts
+ private
- resp = parse_response( socket )
+ def parse_response(socket)
+ version, code, reason = socket.gets.chomp.split(/ /, 3)
+ headers = {}
- raise ConnectError, resp.inspect if resp[:code] != 200
-
- return socket
+ while (line = socket.gets.chomp) != ""
+ name, value = line.split(/:/, 2)
+ headers[name.strip] = value.strip
end
- def parse_response( socket )
- version, code, reason = socket.gets.chomp.split( / /, 3 )
- headers = {}
-
- while ( line = socket.gets.chomp ) != ""
- name, value = line.split( /:/, 2 ).map { |v| v.strip }
- headers[ name ] = value
- end
-
- if headers[ "Content-Length" ]
- body = socket.read( headers[ "Content-Length" ].to_i )
- end
-
- return { :version => version,
- :code => code.to_i,
- :reason => reason,
- :headers => headers,
- :body => body }
+ if headers["Content-Length"]
+ body = socket.read(headers["Content-Length"].to_i)
end
- private :parse_response
- def proxy_user
- return @options[ :user ] if @options[ :user ]
- return ENV['HTTP_PROXY_USER'] if ENV['HTTP_PROXY_USER']
- return ENV['CONNECT_USER'] if ENV['CONNECT_USER']
- return nil
- end
- private :proxy_user
-
- def proxy_password
- return @options[ :password ] if @options[ :password ]
- return ENV['HTTP_PROXY_PASSWORD'] if ENV['HTTP_PROXY_PASSWORD']
- return ENV['CONNECT_PASSWORD'] if ENV['CONNECT_PASSWORD']
- return ""
- end
- private :proxy_password
-
+ return { :version => version,
+ :code => code.to_i,
+ :reason => reason,
+ :headers => headers,
+ :body => body }
end
- end
end
-end
+
+end; end; end