Better support for HTTP/1.0 and also related to persistent connection.

This commit is contained in:
2015-04-01 22:41:43 +02:00
parent 7e057b20b1
commit d9cbc72058
5 changed files with 116 additions and 29 deletions

View File

@@ -39,7 +39,7 @@ feature {NONE} -- Initialization
create request_header.make_empty
create request_header_map.make (10)
keep_alive_enabled := False
keep_alive_requested := False
end
feature -- Status report
@@ -85,8 +85,10 @@ feature -- Access
remote_info: detachable TUPLE [addr: STRING; hostname: STRING; port: INTEGER]
-- Information related to remote client
keep_alive_enabled: BOOLEAN
-- Inside a persistent connection?
keep_alive_requested: BOOLEAN
-- Persistent connection requested?
-- either has "Connection: Keep-Alive" header,
-- or is HTTP/1.1 and no header "Connection: close".
is_http_version_1_0: BOOLEAN
do
@@ -117,7 +119,6 @@ feature -- Change
set_is_verbose (b: BOOLEAN)
do
is_verbose := b
print ("set_is_verbose " + b.out + "%N")
end
feature -- Execution
@@ -164,7 +165,9 @@ feature -- Execution
n := n + 1
-- FIXME: it seems to be called one more time, mostly to see this is done.
execute_request
l_exit := has_error or l_socket.is_closed or not l_socket.is_open_read or not keep_alive_enabled
l_exit := not {HTTPD_SERVER}.is_persistent_connection_supported
or has_error or l_socket.is_closed or not l_socket.is_open_read
or not keep_alive_requested
reset_request
end
end
@@ -297,20 +300,19 @@ feature -- Parsing
line := next_line (a_socket)
end
end
if not {HTTPD_SERVER}.is_persistent_connection_supported then
keep_alive_enabled := False
elseif is_http_version_1_0 then
keep_alive_enabled := attached request_header_map.item ("Connection") as l_connection and then
-- Except for HTTP/1.0, persistent connection is the default.
keep_alive_requested := True
if is_http_version_1_0 then
keep_alive_requested := attached request_header_map.item ("Connection") as l_connection and then
l_connection.is_case_insensitive_equal_general ("keep-alive")
else
-- By default HTTP:1/1 support persistent connection.
if attached request_header_map.item ("Connection") as l_connection then
print ("Connection -> " + l_connection + "%N")
if l_connection.is_case_insensitive_equal_general ("close") then
keep_alive_enabled := False
keep_alive_requested := False
end
else
keep_alive_enabled := True
keep_alive_requested := True
end
end
end

View File

@@ -76,6 +76,13 @@ feature -- Request processing
create req.make (httpd_environment (a_socket), l_input, connector)
create res.make (l_output, l_error)
if is_http_version_1_0 then
l_output.set_http_version ({HTTP_CONSTANTS}.http_version_1_0)
res.set_http_version_1_0
else
l_output.set_http_version (version)
end
res.set_is_persistent_connection_requested (keep_alive_requested)
req.set_meta_string_variable ("RAW_HEADER_DATA", request_header)

View File

@@ -50,7 +50,12 @@ feature -- Status writing
m: detachable READABLE_STRING_8
do
create s.make (16)
if attached http_version as v then
s.append (v)
else
-- Default to 1.1
s.append ({HTTP_CONSTANTS}.http_version_1_1)
end
s.append_character (' ')
s.append_integer (a_code)
m := a_reason_phrase

View File

@@ -18,6 +18,28 @@ inherit
create
make
feature -- Settings
is_http_version_1_0: BOOLEAN
-- Is associated request using HTTP/1.0 ?
is_persistent_connection_requested: BOOLEAN
-- Is persistent connection requested?
feature -- Settings change
set_http_version_1_0
-- Set associated request is using HTTP/1.0.
do
is_http_version_1_0 := True
end
set_is_persistent_connection_requested (b: BOOLEAN)
-- Set `is_persistent_connection_requested' to `b'.
do
is_persistent_connection_requested := b
end
feature -- Header output operation
put_header_text (a_text: READABLE_STRING_8)
@@ -30,26 +52,64 @@ feature -- Header output operation
o := output
create s.make_from_string (a_text)
-- FIXME: check if HTTP versions 1.0 or else.
i := s.substring_index ("%NConnection:", 1)
if {HTTPD_SERVER}.is_persistent_connection_supported then
-- Current standalone support persistent connection.
-- If HTTP/1.1:
-- by default all connection are persistent
-- then no need to return "Connection:" header
-- unless header has "Connection: close"
-- then return "Connection: close"
-- If HTTP/1.0:
-- by default, connection is not persistent
-- unless header has "Connection: Keep-Alive"
-- then return "Connection: Keep-Alive"
-- if header has "Connection: Close"
-- then return "Connection: close"
if is_persistent_connection_requested then
if is_http_version_1_0 then
if i = 0 then
-- Existing response header does not has "Connection: " header.
s.append ("Connection: Keep-Alive")
s.append (o.crlf)
else
-- Do not override the application decision.
end
end
else
-- If HTTP/1.1 and persistent connection is not requested,
-- then return "close"
if i = 0 and not is_http_version_1_0 then
-- Existing response header does not has "Connection: " header.
s.append ("Connection: close")
s.append (o.crlf)
else
-- Do not override the application decision.
end
end
else
-- persistent connection support is disabled.
-- Return "Connection: close" in any case.
-- Except for HTTP/1.0 since not required.
if i > 0 then
j := s.index_of ('%R', i + 12)
end
if {HTTPD_SERVER}.is_persistent_connection_supported then
if i = 0 then
s.append ("Connection: Keep-Alive")
s.append (o.crlf)
end
else
-- standalone does not support persistent connection for now
if j > 0 then
-- Replace existing "Connection:" header with "Connection: close"
l_connection := s.substring (i + 12, j - 1)
l_connection.adjust
if not l_connection.is_case_insensitive_equal_general ("close") then
if
not is_http_version_1_0 and
not l_connection.is_case_insensitive_equal_general ("close")
then
s.replace_substring ("Connection: close", i + 1, j - 1)
end
else
elseif not is_http_version_1_0 then
-- HTTP/1.1: always return "close" since persistent connection is not supported.
s.append ("Connection: close")
s.append (o.crlf)
elseif is_persistent_connection_requested then
-- For HTTP/1.0, return "Connection: close", only if client sent a "Connection: Keep-Alive"
s.append ("Connection: close")
s.append (o.crlf)
end

View File

@@ -74,6 +74,9 @@ feature -- Status writing
feature -- Status report
http_version: detachable READABLE_STRING_8
-- Optional HTTP version.
is_available: BOOLEAN
-- Is output available?
--| i.e: no issue with associated output stream, like closed socket, or related?
@@ -85,6 +88,16 @@ feature -- Status report
deferred
end
feature -- Element change
set_http_version (v: like http_version)
-- Set `http_version' to `v'.
require
valid_version: v /= Void implies v.starts_with ("HTTP/")
do
http_version := v
end
feature -- Basic operations
flush