#!/usr/bin/env ruby # # WebAgent class # # Copyright 2001-2002 TAKAHASHI 'Maki' Masayoshi # You can redistribute and/or modify it under the same term as Ruby. # http://www.ruby-lang.org/en/LICENSE.txt require 'net/http' require 'cgi' #require 'uri' #ruby1.6.7未満だと必要? #require 'stringio' #ruby1.6.7未満だと必要? #require 'cookie.rb' #必要。pathの都合があるので、webagentをrequire時に併記 class WebAgent class Error < StandardError; end VERSION = '0.6.0' ## cookie保存用ファイル COOKIES_FILE = 'agent_cookie.dat' attr_reader :uri attr_accessor :code, :message, :header, :body attr_accessor :cookies, :client_header attr_accessor :auto_redirection ## redirect(301)を自動化 attr_accessor :auto_refreshn ## Metaのrefreshを自動化 # attr_accessor :userpass ## (user名):(password)をbase64化 attr_accessor :auth_mode ## 認証のモード ## true/false def initialize() @code = nil @body = nil @header = nil @client_header = nil ## for client @uri = nil @old_uri = [] @auto_redirection = true @auto_refresh = true @cookies = Hash.new() @cookie_manager = CookieManager.new(COOKIES_FILE) @send_userpass = false @proxy_uri = nil if ENV['http_proxy'] @proxy_uri = URI.parse(ENV['http_proxy']) end load_cookies() @client_header = Hash.new() create_default_header() end ## URL(uri)の設定。 ## 文字列ならURIオブジェクトを生成する。 def uri=(uri) case uri when String @uri = URI.parse(uri) when URI::Generic @uri = uri else raise WebAgent::Error, 'invalid URI: ' + uri.inspect end @client_header['cookie'] = @cookie_manager.find(@uri) || '' end ## basic認証用のユーザ名とパスワードを設定 def userpass=(userpass) if /:/ !~ userpass raise WebAgent::Error, "invalid userpass format: #{userpass}" end @userpass = [userpass].pack('m').chomp end ## basic認証用のユーザ名とパスワードを読み出す def userpass @userpass.unpack('m')[0] end ## プロキシ対応のため、HTTP(クラス)を作る。 def get_http_adapter() if ENV['http_proxy'] @proxy_uri = URI.parse(ENV['http_proxy']) return Net::HTTP::Proxy(@proxy_uri.host, @proxy_uri.port) else return Net::HTTP end end private :get_http_adapter ## 送信用HTTPヘッダをセットする。 def create_default_header() @client_header = Hash.new() @client_header['user-agent'] = "Web-Agent/#{VERSION}" # @client_header['accept-encoding'] = "gzip,deflate" end private :create_default_header ## クッキーの読み込みを行う。 def load_cookies @cookie_manager.load_cookies() end private :load_cookies ## クッキーの書き出しを(必要があれば)行う。 def save_cookies @cookie_manager.save_cookies() end private :save_cookies ## リクエストのpathを作る def request_path() @uri.request_uri end private :request_path ##レスポンスの解析をする ## Content-Encodingなレスポンスは展開まで行う。 def read_response(res) @code = res.code @message = res.message @header = Hash.new() res.each{|key, value| @header[key] = value } if @header['set-cookie'] @cookie_manager.parse(@header['set-cookie'], @uri) end @body = @raw_body = res.body if @header['content-encoding'] if @header['content-encoding'].downcase == 'gzip' || @header['content-encoding'].downcase == 'x-gzip' @body = gunzip(res.body) elsif @header['content-encoding'].downcase == 'deflate' @body = inflate(res.body) end end end ## gzip化された文字列をunzipする。 def gunzip(str) str_io = StringIO.new(str) gunziped_str = Zlib::GzipReader.new(str_io).read() return gunziped_str end ## deflate化された文字列をinflateする。 def inflate(str) inflated_str = Zlib::Inflate.inflate(str) return inflated_str end ## 指定されているURIのページを持ってくる。 def get(optinal_header = nil) send_request('get', optinal_header) end def head(optinal_header = nil) send_request('head', optinal_header) end def send_request(method, optional_header = nil) optional_header ||= Hash.new() client_header = @client_header.dup client_header.update(optional_header) if @send_userpass && @auth_mode client_header['authorization'] = "Basic #{@userpass}" else client_header.delete('authorization') end net_http = get_http_adapter() net_http.start(@uri.host, @uri.port) do |http| # p [request_path, client_header] if method.downcase == 'head' res = http.head2(request_path(), client_header) elsif method.downcase == 'get' res = http.get2(request_path(), client_header) else raise WebAgent::Error, 'invalid method' end read_response(res) end if @code =~ /^30[1237]/ if @auto_redirection resend(method, @header['location'], optional_header) end elsif @code =~ /^401/ if @auth_mode && !@send_userpass @send_userpass = true resend(method, @uri, optional_header) else ## authorization failed.. end elsif %r|.*