def self.parse(socket, params={})
response = new(:status => socket.read(12)[9, 11].to_i)
socket.readline
until ((data = socket.readline).chop!).empty?
key, value = data.split(/:\s*/, 2)
response.headers[key] = ([*response.headers[key]] << value).compact.join(', ')
if key.casecmp('Content-Length') == 0
content_length = value.to_i
elsif (key.casecmp('Transfer-Encoding') == 0) && (value.casecmp('chunked') == 0)
transfer_encoding_chunked = true
end
end
unless (params[:method].to_s.casecmp('HEAD') == 0) || NO_ENTITY.include?(response.status)
expected_status = !params.has_key?(:expects) || [*params[:expects]].include?(response.status)
if expected_status && params.has_key?(:response_block)
if transfer_encoding_chunked
while (chunk_size = socket.readline.chop!.to_i(16)) > 0
params[:response_block].call(socket.read(chunk_size + 2).chop!, nil, nil)
end
socket.read(2)
elsif remaining = content_length
while remaining > 0
params[:response_block].call(socket.read([params[:chunk_size], remaining].min), [remaining - params[:chunk_size], 0].max, content_length)
remaining -= params[:chunk_size]
end
else
while remaining = socket.read(params[:chunk_size])
params[:response_block].call(remaining, remaining.length, content_length)
end
end
else
if transfer_encoding_chunked
while (chunk_size = socket.readline.chop!.to_i(16)) > 0
response.body << socket.read(chunk_size + 2).chop!
end
socket.read(2)
elsif remaining = content_length
while remaining > 0
response.body << socket.read([params[:chunk_size], remaining].min)
remaining -= params[:chunk_size]
end
else
response.body << socket.read
end
end
end
response
end