1
0
Fork 0
mirror of https://github.com/puma/puma.git synced 2022-11-09 13:48:40 -05:00

Proper 'Connection' header handling compatible with HTTP 1.0 and HTTP 1.1 protocols

This commit is contained in:
iaintshine 2015-02-19 14:43:17 +01:00
parent 72e59a5380
commit be9b5e978b
4 changed files with 134 additions and 20 deletions

View file

@ -535,7 +535,7 @@ module Puma
line_ending = LINE_END
colon = COLON
if env[HTTP_VERSION] == HTTP_11
http_11 = if env[HTTP_VERSION] == HTTP_11
allow_chunked = true
keep_alive = env[HTTP_CONNECTION] != CLOSE
include_keepalive_header = false
@ -552,6 +552,7 @@ module Puma
no_body ||= status < 200 || STATUS_WITH_NO_ENTITY_BODY[status]
end
true
else
allow_chunked = false
keep_alive = env[HTTP_CONNECTION] == KEEP_ALIVE
@ -567,6 +568,7 @@ module Puma
no_body ||= status < 200 || STATUS_WITH_NO_ENTITY_BODY[status]
end
false
end
response_hijack = nil
@ -593,6 +595,12 @@ module Puma
end
end
if include_keepalive_header
lines << CONNECTION_KEEP_ALIVE
elsif http_11 && !keep_alive
lines << CONNECTION_CLOSE
end
if no_body
if content_length and status != 204
lines.append CONTENT_LENGTH_S, content_length.to_s, line_ending
@ -603,12 +611,6 @@ module Puma
return keep_alive
end
if include_keepalive_header
lines << CONNECTION_KEEP_ALIVE
elsif !keep_alive
lines << CONNECTION_CLOSE
end
unless response_hijack
if content_length
lines.append CONTENT_LENGTH_S, content_length.to_s, line_ending

View file

@ -106,7 +106,7 @@ class TestPersistent < Test::Unit::TestCase
@client << @http10_request
assert_equal "HTTP/1.0 200 OK\r\nX-Header: Works\r\nConnection: close\r\n\r\n", lines(4)
assert_equal "HTTP/1.0 200 OK\r\nX-Header: Works\r\n\r\n", lines(3)
assert_equal "HelloChunked", @client.read
end
@ -132,7 +132,7 @@ class TestPersistent < Test::Unit::TestCase
@client << @http10_request
sz = @body[0].size.to_s
assert_equal "HTTP/1.0 200 OK\r\nX-Header: Works\r\nConnection: close\r\nContent-Length: #{sz}\r\n\r\n", lines(5)
assert_equal "HTTP/1.0 200 OK\r\nX-Header: Works\r\nContent-Length: #{sz}\r\n\r\n", lines(4)
assert_equal "Hello", @client.read(5)
end

View file

@ -216,7 +216,7 @@ class TestPumaServer < Test::Unit::TestCase
data = sock.read
assert_equal "HTTP/1.0 449 CUSTOM\r\nConnection: close\r\nContent-Length: 0\r\n\r\n", data
assert_equal "HTTP/1.0 449 CUSTOM\r\nContent-Length: 0\r\n\r\n", data
end
def test_custom_http_codes_11
@ -285,4 +285,116 @@ class TestPumaServer < Test::Unit::TestCase
assert_equal "HTTP/1.1 408 Request Timeout\r\n", data
end
def test_http_11_keep_alive_with_body
@server.app = proc { |env| [200, {"Content-Type" => "plain/text"}, ["hello"]] }
@server.add_tcp_listener @host, @port
@server.run
sock = TCPSocket.new @host, @port
sock << "GET / HTTP/1.1\r\nConnection: Keep-Alive\r\n\r\n"
data = sock.read
assert_equal "HTTP/1.1 200 OK\r\nContent-Type: plain/text\r\nContent-Length: 5\r\n\r\nhello", data
end
def test_http_11_close_with_body
@server.app = proc { |env| [200, {"Content-Type" => "plain/text"}, ["hello"]] }
@server.add_tcp_listener @host, @port
@server.run
sock = TCPSocket.new @host, @port
sock << "GET / HTTP/1.1\r\nConnection: close\r\n\r\n"
data = sock.read
assert_equal "HTTP/1.1 200 OK\r\nContent-Type: plain/text\r\nConnection: close\r\nContent-Length: 5\r\n\r\nhello", data
end
def test_http_11_keep_alive_without_body
@server.app = proc { |env| [204, {}, []] }
@server.add_tcp_listener @host, @port
@server.run
sock = TCPSocket.new @host, @port
sock << "GET / HTTP/1.1\r\nConnection: Keep-Alive\r\n\r\n"
data = sock.read
assert_equal "HTTP/1.1 204 No Content\r\n\r\n", data
end
def test_http_11_close_without_body
@server.app = proc { |env| [204, {}, []] }
@server.add_tcp_listener @host, @port
@server.run
sock = TCPSocket.new @host, @port
sock << "GET / HTTP/1.1\r\nConnection: close\r\n\r\n"
data = sock.read
assert_equal "HTTP/1.1 204 No Content\r\nConnection: close\r\n\r\n", data
end
def test_http_10_keep_alive_with_body
@server.app = proc { |env| [200, {"Content-Type" => "plain/text"}, ["hello"]] }
@server.add_tcp_listener @host, @port
@server.run
sock = TCPSocket.new @host, @port
sock << "GET / HTTP/1.0\r\nConnection: Keep-Alive\r\n\r\n"
data = sock.read
assert_equal "HTTP/1.0 200 OK\r\nContent-Type: plain/text\r\nConnection: Keep-Alive\r\nContent-Length: 5\r\n\r\nhello", data
end
def test_http_10_close_with_body
@server.app = proc { |env| [200, {"Content-Type" => "plain/text"}, ["hello"]] }
@server.add_tcp_listener @host, @port
@server.run
sock = TCPSocket.new @host, @port
sock << "GET / HTTP/1.0\r\nConnection: close\r\n\r\n"
data = sock.read
assert_equal "HTTP/1.0 200 OK\r\nContent-Type: plain/text\r\nContent-Length: 5\r\n\r\nhello", data
end
def test_http_10_keep_alive_without_body
@server.app = proc { |env| [204, {}, []] }
@server.add_tcp_listener @host, @port
@server.run
sock = TCPSocket.new @host, @port
sock << "GET / HTTP/1.0\r\nConnection: Keep-Alive\r\n\r\n"
data = sock.read
assert_equal "HTTP/1.0 204 No Content\r\nConnection: Keep-Alive\r\n\r\n", data
end
def test_http_10_close_without_body
@server.app = proc { |env| [204, {}, []] }
@server.add_tcp_listener @host, @port
@server.run
sock = TCPSocket.new @host, @port
sock << "GET / HTTP/1.0\r\nConnection: close\r\n\r\n"
data = sock.read
assert_equal "HTTP/1.0 204 No Content\r\n\r\n", data
end
end

View file

@ -8,31 +8,31 @@ require 'socket'
# (or Windows)
unless defined?(JRUBY_VERSION) || RbConfig::CONFIG["host_os"] =~ /mingw|mswin/
class TestPumaUnixSocket < Test::Unit::TestCase
App = lambda { |env| [200, {}, ["Works"]] }
Path = "test/puma.sock"
def setup
@server = Puma::Server.new App
@server.add_unix_listener Path
@server.run
end
def teardown
@server.stop(true)
File.unlink Path if File.exist? Path
end
def test_server
sock = UNIXSocket.new Path
sock << "GET / HTTP/1.0\r\nHost: blah.com\r\n\r\n"
expected = "HTTP/1.0 200 OK\r\nConnection: close\r\nContent-Length: 5\r\n\r\nWorks"
expected = "HTTP/1.0 200 OK\r\nContent-Length: 5\r\n\r\nWorks"
assert_equal expected, sock.read(expected.size)
sock.close
end
end