class HTTP::Connection
A connection to the HTTP server
def close
def close socket.close unless socket.closed? @pending_response = nil @pending_request = nil end
def finish_response
def finish_response close unless keep_alive? parser.reset @pending_response = nil end
def initialize(req, options)
def initialize(req, options) @persistent = options.persistent? @parser = Response::Parser.new @socket = options[:socket_class].open(req.socket_host, req.socket_port) start_tls(req.uri.host, options[:ssl_socket_class], options[:ssl_context]) if req.uri.is_a?(URI::HTTPS) && !req.using_proxy? end
def keep_alive?
def keep_alive? !!@keep_alive && !socket.closed? end
def read_headers!
def read_headers! read_more BUFFER_SIZE until parser.headers set_keep_alive rescue IOError, Errno::ECONNRESET, Errno::EPIPE => ex return if ex.is_a?(EOFError) && parser.headers raise IOError, "problem making HTTP request: #{ex}" end
def read_more(size)
def read_more(size) parser << socket.readpartial(size) unless parser.finished? end
def readpartial(size = BUFFER_SIZE)
-
(Nil)
- when no more data left -
(String)
- data chunk
def readpartial(size = BUFFER_SIZE) return unless pending_response begin read_more size finished = parser.finished? rescue EOFError finished = true end chunk = parser.chunk finish_response if finished chunk.to_s end
def send_request(req)
def send_request(req) if pending_response fail StateError, "Tried to send a request while one is pending already. Make sure you read off the body." elsif pending_request fail StateError, "Tried to send a request while a response is pending. Make sure you've fully read the body from the request." end @pending_request = true req.stream socket @pending_response = true @pending_request = nil end
def set_keep_alive
Store whether the connection should be kept alive.
def set_keep_alive return @keep_alive = false unless persistent # HTTP/1.0 requires opt in for Keep Alive if parser.http_version == "1.0" @keep_alive = parser.headers["Connection"] == HTTP::Client::KEEP_ALIVE # HTTP/1.1 is opt-out elsif parser.http_version == "1.1" @keep_alive = parser.headers["Connection"] != HTTP::Client::CLOSE # Anything else we assume doesn't supportit else @keep_alive = false end end
def start_tls(host, ssl_socket_class, ssl_context)
def start_tls(host, ssl_socket_class, ssl_context) # TODO: abstract away SSLContexts so we can use other TLS libraries ssl_context ||= OpenSSL::SSL::SSLContext.new @socket = ssl_socket_class.new(socket, ssl_context) socket.sync_close = true socket.connect if ssl_context.verify_mode == OpenSSL::SSL::VERIFY_PEER socket.post_connection_check(host) end socket end