DESCRIPTION

  HTTPAccess::Client -- Client to retrieve web resources via HTTP.

How to create your client.

  1. Create simple client.
    clnt = HTTPAccess::Client.new

  2. Accessing resources through HTTP proxy.
    clnt = HTTPAccess::Client.new("http://myproxy:8080")

  3. Set User-Agent and From in HTTP request header.(nil means "No proxy")
    clnt = HTTPAccess::Client.new(nil, "MyAgent", "nahi@keynauts.com")

How to retrieve web resources.

  1. Get content of specified URL.
    puts clnt.get_content("http://www.ruby-lang.org/en/")

  2. Do HEAD request.
    res = clnt.head(uri)

  3. Do GET request with query.
    res = clnt.get(uri)

  4. Do POST request.
    res = clnt.post(uri)
    res = clnt.get|post|head(uri, proxy)
Methods
Constants
NO_PROXY_HOSTS = ['localhost']
Attributes
[R] agent_name
[RW] cookie_manager
[R] from
[R] ssl_config
[R] test_loopback_response
Public Class methods
new(proxy = nil, agent_name = nil, from = nil)

SYNOPSIS

  Client.new(proxy = nil, agent_name = nil, from = nil)

ARGS

  proxy             A String of HTTP proxy URL. ex. "http://proxy:8080".
  agent_name        A String for "User-Agent" HTTP request header.
  from              A String for "From" HTTP request header.

DESCRIPTION

  Create an instance.
  SSLConfig cannot be re-initialized.  Create new client.
# File lib/facets/more/httpaccess.rb, line 117
  def initialize(proxy = nil, agent_name = nil, from = nil)
    @proxy = nil        # assigned later.
    @no_proxy = nil
    @agent_name = agent_name
    @from = from
    @basic_auth = BasicAuth.new(self)
    @debug_dev = nil
    @ssl_config = SSLConfig.new(self)
    @redirect_uri_callback = method(:default_redirect_uri_callback)
    @test_loopback_response = []
    @session_manager = SessionManager.new
    @session_manager.agent_name = @agent_name
    @session_manager.from = @from
    @session_manager.ssl_config = @ssl_config
    @cookie_manager = WebAgent::CookieManager.new
    self.proxy = proxy
  end
Public Instance methods
connect_timeout()
# File lib/facets/more/httpaccess.rb, line 154
  def connect_timeout
    @session_manager.connect_timeout
  end
connect_timeout=(connect_timeout)
# File lib/facets/more/httpaccess.rb, line 158
  def connect_timeout=(connect_timeout)
    reset_all
    @session_manager.connect_timeout = connect_timeout
  end
debug_dev()
# File lib/facets/more/httpaccess.rb, line 135
  def debug_dev
    @debug_dev
  end
debug_dev=(dev)
# File lib/facets/more/httpaccess.rb, line 139
  def debug_dev=(dev)
    @debug_dev = dev
    reset_all
    @session_manager.debug_dev = dev
  end
default_redirect_uri_callback(res)
# File lib/facets/more/httpaccess.rb, line 270
  def default_redirect_uri_callback(res)
    uri = res.header['location'][0]
    puts "Redirect to: #{uri}" if $DEBUG
    uri
  end
delete(uri, extheader = {}, &block)
# File lib/facets/more/httpaccess.rb, line 292
  def delete(uri, extheader = {}, &block)
    request('DELETE', uri, nil, nil, extheader, &block)
  end
delete_async(uri, extheader = {})
# File lib/facets/more/httpaccess.rb, line 328
  def delete_async(uri, extheader = {})
    request_async('DELETE', uri, nil, nil, extheader)
  end
get(uri, query = nil, extheader = {}, &block)
# File lib/facets/more/httpaccess.rb, line 280
  def get(uri, query = nil, extheader = {}, &block)
    request('GET', uri, query, nil, extheader, &block)
  end
get_async(uri, query = nil, extheader = {})
# File lib/facets/more/httpaccess.rb, line 316
  def get_async(uri, query = nil, extheader = {})
    request_async('GET', uri, query, nil, extheader)
  end
get_content(uri, query = nil, extheader = {}, &block)

SYNOPSIS

  Client#get_content(uri, query = nil, extheader = {}, &block = nil)

ARGS

  uri       an_URI or a_string of uri to connect.
  query     a_hash or an_array of query part.  e.g. { "a" => "b" }.
            Give an array to pass multiple value like
            [["a" => "b"], ["a" => "c"]].
  extheader
            a_hash of extra headers like { "SOAPAction" => "urn:foo" }.
  &block    Give a block to get chunked message-body of response like
            get_content(uri) { |chunked_body| ... }
            Size of each chunk may not be the same.

DESCRIPTION

  Get a_sring of message-body of response.
# File lib/facets/more/httpaccess.rb, line 258
  def get_content(uri, query = nil, extheader = {}, &block)
    retry_connect(uri, query) do |uri, query|
      get(uri, query, extheader, &block)
    end
  end
head(uri, query = nil, extheader = {})
# File lib/facets/more/httpaccess.rb, line 276
  def head(uri, query = nil, extheader = {})
    request('HEAD', uri, query, nil, extheader)
  end
head_async(uri, query = nil, extheader = {})

Async interface.

# File lib/facets/more/httpaccess.rb, line 312
  def head_async(uri, query = nil, extheader = {})
    request_async('HEAD', uri, query, nil, extheader)
  end
no_proxy()
# File lib/facets/more/httpaccess.rb, line 203
  def no_proxy
    @no_proxy
  end
no_proxy=(no_proxy)
# File lib/facets/more/httpaccess.rb, line 207
  def no_proxy=(no_proxy)
    @no_proxy = no_proxy
    reset_all
  end
options(uri, extheader = {}, &block)
# File lib/facets/more/httpaccess.rb, line 296
  def options(uri, extheader = {}, &block)
    request('OPTIONS', uri, nil, nil, extheader, &block)
  end
options_async(uri, extheader = {})
# File lib/facets/more/httpaccess.rb, line 332
  def options_async(uri, extheader = {})
    request_async('OPTIONS', uri, nil, nil, extheader)
  end
post(uri, body = nil, extheader = {}, &block)
# File lib/facets/more/httpaccess.rb, line 284
  def post(uri, body = nil, extheader = {}, &block)
    request('POST', uri, nil, body, extheader, &block)
  end
post_async(uri, body = nil, extheader = {})
# File lib/facets/more/httpaccess.rb, line 320
  def post_async(uri, body = nil, extheader = {})
    request_async('POST', uri, nil, body, extheader)
  end
post_content(uri, body = nil, extheader = {}, &block)
# File lib/facets/more/httpaccess.rb, line 264
  def post_content(uri, body = nil, extheader = {}, &block)
    retry_connect(uri, nil) do |uri, query|
      post(uri, body, extheader, &block)
    end
  end
protocol_version()
# File lib/facets/more/httpaccess.rb, line 145
  def protocol_version
    @session_manager.protocol_version
  end
protocol_version=(protocol_version)
# File lib/facets/more/httpaccess.rb, line 149
  def protocol_version=(protocol_version)
    reset_all
    @session_manager.protocol_version = protocol_version
  end
proxy()
# File lib/facets/more/httpaccess.rb, line 181
  def proxy
    @proxy
  end
proxy=(proxy)
# File lib/facets/more/httpaccess.rb, line 185
  def proxy=(proxy)
    if proxy.nil?
      @proxy = nil
    else
      if proxy.is_a?(URI)
        @proxy = proxy
      else
        @proxy = URI.parse(proxy)
      end
      if @proxy.scheme == nil or @proxy.scheme.downcase != 'http' or
          @proxy.host == nil or @proxy.port == nil
        raise ArgumentError.new("unsupported proxy `#{proxy}'")
      end
    end
    reset_all
    @proxy
  end
put(uri, body = nil, extheader = {}, &block)
# File lib/facets/more/httpaccess.rb, line 288
  def put(uri, body = nil, extheader = {}, &block)
    request('PUT', uri, nil, body, extheader, &block)
  end
put_async(uri, body = nil, extheader = {})
# File lib/facets/more/httpaccess.rb, line 324
  def put_async(uri, body = nil, extheader = {})
    request_async('PUT', uri, nil, body, extheader)
  end
receive_timeout()
# File lib/facets/more/httpaccess.rb, line 172
  def receive_timeout
    @session_manager.receive_timeout
  end
receive_timeout=(receive_timeout)
# File lib/facets/more/httpaccess.rb, line 176
  def receive_timeout=(receive_timeout)
    reset_all
    @session_manager.receive_timeout = receive_timeout
  end
redirect_uri_callback=(redirect_uri_callback)
# File lib/facets/more/httpaccess.rb, line 237
  def redirect_uri_callback=(redirect_uri_callback)
    @redirect_uri_callback = redirect_uri_callback
  end
request(method, uri, query = nil, body = nil, extheader = {}, &block)
# File lib/facets/more/httpaccess.rb, line 304
  def request(method, uri, query = nil, body = nil, extheader = {}, &block)
    conn = Connection.new
    conn_request(conn, method, uri, query, body, extheader, &block)
    conn.pop
  end
request_async(method, uri, query = nil, body = nil, extheader = {})
# File lib/facets/more/httpaccess.rb, line 340
  def request_async(method, uri, query = nil, body = nil, extheader = {})
    conn = Connection.new
    t = Thread.new(conn) { |tconn|
      conn_request(tconn, method, uri, query, body, extheader)
    }
    conn.async_thread = t
    conn
  end
reset(uri)

Management interface.

# File lib/facets/more/httpaccess.rb, line 357
  def reset(uri)
    @session_manager.reset(uri)
  end
reset_all()
# File lib/facets/more/httpaccess.rb, line 361
  def reset_all
    @session_manager.reset_all
  end
save_cookie_store()
# File lib/facets/more/httpaccess.rb, line 233
  def save_cookie_store
    @cookie_manager.save_cookies
  end
send_timeout()
# File lib/facets/more/httpaccess.rb, line 163
  def send_timeout
    @session_manager.send_timeout
  end
send_timeout=(send_timeout)
# File lib/facets/more/httpaccess.rb, line 167
  def send_timeout=(send_timeout)
    reset_all
    @session_manager.send_timeout = send_timeout
  end
set_basic_auth(uri, user_id, passwd)
# File lib/facets/more/httpaccess.rb, line 218
  def set_basic_auth(uri, user_id, passwd)
    unless uri.is_a?(URI)
      uri = URI.parse(uri)
    end
    @basic_auth.set(uri, user_id, passwd)
  end
set_cookie_store(filename)
# File lib/facets/more/httpaccess.rb, line 225
  def set_cookie_store(filename)
    if @cookie_manager.cookies_file
      raise RuntimeError.new("overriding cookie file location")
    end
    @cookie_manager.cookies_file = filename
    @cookie_manager.load_cookies if filename
  end
socket_sync=(socket_sync)

if your ruby is older than 2005-09-06, do not set socket_sync = false to avoid an SSL socket blocking bug in openssl/buffering.rb.

# File lib/facets/more/httpaccess.rb, line 214
  def socket_sync=(socket_sync)
    @session_manager.socket_sync = socket_sync
  end
trace(uri, query = nil, body = nil, extheader = {}, &block)
# File lib/facets/more/httpaccess.rb, line 300
  def trace(uri, query = nil, body = nil, extheader = {}, &block)
    request('TRACE', uri, query, body, extheader, &block)
  end
trace_async(uri, query = nil, body = nil, extheader = {})
# File lib/facets/more/httpaccess.rb, line 336
  def trace_async(uri, query = nil, body = nil, extheader = {})
    request_async('TRACE', uri, query, body, extheader)
  end
Private Instance methods
conn_request(conn, method, uri, query, body, extheader, &block)
# File lib/facets/more/httpaccess.rb, line 384
  def conn_request(conn, method, uri, query, body, extheader, &block)
    unless uri.is_a?(URI)
      uri = URI.parse(uri)
    end
    proxy = no_proxy?(uri) ? nil : @proxy
    begin
      req = create_request(method, uri, query, body, extheader, !proxy.nil?)
      do_get_block(req, proxy, conn, &block)
    rescue Session::KeepAliveDisconnected
      req = create_request(method, uri, query, body, extheader, !proxy.nil?)
      do_get_block(req, proxy, conn, &block)
    end
  end
create_request(method, uri, query, body, extheader, proxy)
# File lib/facets/more/httpaccess.rb, line 398
  def create_request(method, uri, query, body, extheader, proxy)
    if extheader.is_a?(Hash)
      extheader = extheader.to_a
    end
    cred = @basic_auth.get(uri)
    if cred
      extheader << ['Authorization', "Basic " << cred]
    end
    if cookies = @cookie_manager.find(uri)
      extheader << ['Cookie', cookies]
    end
    boundary = nil
    content_type = extheader.find { |key, value|
      key.downcase == 'content-type'
    }
    if content_type && content_type[1] =~ /boundary=(.+)\z/
      boundary = $1
    end
    req = HTTP::Message.new_request(method, uri, query, body, proxy, boundary)
    extheader.each do |key, value|
      req.header.set(key, value)
    end
    if content_type.nil? and !body.nil?
      req.header.set('content-type', 'application/x-www-form-urlencoded')
    end
    req
  end
do_get_block(req, proxy, conn, &block)

!! CAUTION !!

  Method 'do_get*' runs under MT conditon. Be careful to change.
# File lib/facets/more/httpaccess.rb, line 446
  def do_get_block(req, proxy, conn, &block)
    if str = @test_loopback_response.shift
      dump_dummy_request_response(req.body.dump, str) if @debug_dev
      conn.push(HTTP::Message.new_response(str))
      return
    end
    content = ''
    res = HTTP::Message.new_response(content)
    @debug_dev << "= Request\n\n" if @debug_dev
    sess = @session_manager.query(req, proxy)
    @debug_dev << "\n\n= Response\n\n" if @debug_dev
    do_get_header(req, res, sess)
    conn.push(res)
    sess.get_data() do |str|
      block.call(str) if block
      content << str
    end
    @session_manager.keep(sess) unless sess.closed?
  end
do_get_header(req, res, sess)
# File lib/facets/more/httpaccess.rb, line 486
  def do_get_header(req, res, sess)
    res.version, res.status, res.reason = sess.get_status
    sess.get_header().each do |line|
      unless /^([^:]+)\s*:\s*(.*)$/ =~ line
        raise RuntimeError.new("Unparsable header: '#{line}'.") if $DEBUG
      end
      res.header.set($1, $2)
    end
    if res.header['set-cookie']
      res.header['set-cookie'].each do |cookie|
        @cookie_manager.parse(cookie, req.header.request_uri)
      end
    end
  end
do_get_stream(req, proxy, conn)
# File lib/facets/more/httpaccess.rb, line 466
  def do_get_stream(req, proxy, conn)
    if str = @test_loopback_response.shift
      dump_dummy_request_response(req.body.dump, str) if @debug_dev
      conn.push(HTTP::Message.new_response(str))
      return
    end
    piper, pipew = IO.pipe
    res = HTTP::Message.new_response(piper)
    @debug_dev << "= Request\n\n" if @debug_dev
    sess = @session_manager.query(req, proxy)
    @debug_dev << "\n\n= Response\n\n" if @debug_dev
    do_get_header(req, res, sess)
    conn.push(res)
    sess.get_data() do |str|
      pipew.syswrite(str)
    end
    pipew.close
    @session_manager.keep(sess) unless sess.closed?
  end
dump_dummy_request_response(req, res)
# File lib/facets/more/httpaccess.rb, line 501
  def dump_dummy_request_response(req, res)
    @debug_dev << "= Dummy Request\n\n"
    @debug_dev << req
    @debug_dev << "\n\n= Dummy Response\n\n"
    @debug_dev << res
  end
no_proxy?(uri)
# File lib/facets/more/httpaccess.rb, line 428
  def no_proxy?(uri)
    if !@proxy or NO_PROXY_HOSTS.include?(uri.host)
      return true
    end
    unless @no_proxy
      return false
    end
    @no_proxy.scan(/([^:,]+)(?::(\d+))?/) do |host, port|
      if /(\A|\.)#{Regexp.quote(host)}\z/i =~ uri.host &&
          (!port || uri.port == port.to_i)
        return true
      end
    end
    false
  end
retry_connect(uri, query = nil) {|uri, query| ...}
# File lib/facets/more/httpaccess.rb, line 367
  def retry_connect(uri, query = nil)
    retry_number = 0
    while retry_number < 10
      res = yield(uri, query)
      if res.status == HTTP::Status::OK
        return res.content
      elsif HTTP::Status.redirect?(res.status)
        uri = @redirect_uri_callback.call(res)
        query = nil
        retry_number += 1
      else
        raise RuntimeError.new("Unexpected response: #{res.header.inspect}")
      end
    end
    raise RuntimeError.new("Retry count exceeded.")
  end