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