class HTTPray::Connection

Public Class Methods

new(host, port, timeout = 1, ssl_context = nil, retry_count = 1, retry_circuit_breaker_interval = 10) click to toggle source
# File lib/httpray.rb, line 18
def initialize(host, port, timeout = 1, ssl_context = nil, retry_count = 1, retry_circuit_breaker_interval = 10)
  @host = host
  @port = port
  @timeout = timeout
  @ssl_context = ssl_context
  @retry_count = retry_count
  @retry_circuit_breaker_interval = retry_circuit_breaker_interval
  @next_retry_time = Time.now - @retry_circuit_breaker_interval
  @socket = connect
end

Public Instance Methods

connect() click to toggle source
# File lib/httpray.rb, line 116
def connect
  socket, _ = connect2
  socket
end
connect2() click to toggle source

private

# File lib/httpray.rb, line 78
def connect2
  address = Socket.getaddrinfo(@host, nil, Socket::AF_INET).first[3]
  socket_address = Socket.pack_sockaddr_in(@port, address)

  socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
  socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)

  expire_time = Time.now + @timeout
  begin
    raise Timeout if Time.now > expire_time
    socket.connect_nonblock(socket_address)
  rescue Errno::EISCONN
    nil #continue
  rescue IO::WaitReadable, IO::WaitWritable, Errno::EADDRNOTAVAIL
    select_timeout = expire_time - Time.now
    select_timeout = 0 if select_timeout < 0
    IO.select([socket], [socket], [socket], select_timeout)
    retry
  end

  original_socket = socket
  if @ssl_context
    socket = OpenSSL::SSL::SSLSocket.new(socket, @ssl_context)
    socket.hostname = @host
    socket.sync_close = true
    begin
      raise Timeout if Time.now > expire_time
      socket.connect_nonblock
    rescue IO::WaitReadable, IO::WaitWritable
      select_timeout = expire_time - Time.now
      select_timeout = 0 if select_timeout < 0
      IO.select([socket.io], [socket.io], [socket.io], select_timeout)
      retry
    end
  end
  return socket, original_socket
end
reconnect() click to toggle source
# File lib/httpray.rb, line 35
def reconnect
  @socket = connect unless @socket && !socket.closed?
end
request(*args) { |socket| ... } click to toggle source
# File lib/httpray.rb, line 71
def request(*args)
  socket = request!(*args)
  yield(socket) if block_given?
end
request!(method, uri, headers = {}, body = nil) click to toggle source
# File lib/httpray.rb, line 39
def request!(method, uri, headers = {}, body = nil)
  tries ||= 0
  reconnect
  socket = @socket
  uri = URI.parse(uri) unless URI === uri

  headers = DEFAULT_HEADERS.merge(headers).merge("Host" => uri.host)
  headers["Content-Length"] = body.bytesize if body

  socket.write_nonblock "#{method} #{uri.request_uri} HTTP/1.0\r\n"
  headers.each do |header, value|
    socket.write_nonblock "#{header}: #{value}\r\n"
  end
  socket.write_nonblock "\r\n"
  socket.write_nonblock body if body
  socket
rescue => error
  @socket.close unless @socket.closed?
  now = Time.now
  if now > @next_retry_time
    if tries < @retry_count 
      tries += 1
      retry
    else
      @next_retry_time = now + @retry_circuit_breaker_interval
      raise error
    end
  else
    raise HTTPray::CircuitBreakerError
  end
end
socket() click to toggle source

public

# File lib/httpray.rb, line 31
def socket
  @socket
end