Fixed various issues related to unicode and CGI variables (assuming that CGI variables are utf-8 encoded, and sometime percent encoded).
Delayed computation of `value' and `name' from WSF_STRING.
Fixed computation of REQUEST_URI when the server does not provide it (this is rare, but possible).
compute it as SERVER_NAME + encoded-PATH_INFO + {? + QUERY_STRING}
This commit is contained in:
@@ -70,6 +70,7 @@ feature -- Request processing
|
|||||||
|
|
||||||
e: EXECUTION_ENVIRONMENT
|
e: EXECUTION_ENVIRONMENT
|
||||||
enc: URL_ENCODER
|
enc: URL_ENCODER
|
||||||
|
utf: UTF_CONVERTER
|
||||||
do
|
do
|
||||||
l_request_uri := a_handler.uri
|
l_request_uri := a_handler.uri
|
||||||
l_headers_map := a_handler.request_header_map
|
l_headers_map := a_handler.request_header_map
|
||||||
@@ -80,13 +81,13 @@ feature -- Request processing
|
|||||||
across
|
across
|
||||||
vars as c
|
vars as c
|
||||||
loop
|
loop
|
||||||
env.force (enc.encoded_string (c.item), enc.encoded_string (c.key))
|
env.force (utf.utf_32_string_to_utf_8_string_8 (c.item), utf.utf_32_string_to_utf_8_string_8 (c.key))
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
create env.make (0)
|
create env.make (0)
|
||||||
end
|
end
|
||||||
|
|
||||||
--| for Any Abc-Def-Ghi add (or replace) the HTTP_ABC_DEF_GHI variable to `env'
|
--| for Any Abc-Def-Ghi add (or replace) the HTTP_ABC_DEF_GHI variable to `env'
|
||||||
from
|
from
|
||||||
l_headers_map.start
|
l_headers_map.start
|
||||||
until
|
until
|
||||||
|
|||||||
@@ -253,7 +253,7 @@ feature -- Access: HTTP_* CGI meta parameters - 1.1
|
|||||||
do
|
do
|
||||||
Result := meta_string_variable ({WGI_META_NAMES}.http_if_match)
|
Result := meta_string_variable ({WGI_META_NAMES}.http_if_match)
|
||||||
end
|
end
|
||||||
|
|
||||||
http_if_modified_since: detachable READABLE_STRING_8
|
http_if_modified_since: detachable READABLE_STRING_8
|
||||||
-- Modification check on resource
|
-- Modification check on resource
|
||||||
do
|
do
|
||||||
@@ -306,8 +306,11 @@ feature {NONE} -- Element change: CGI meta parameter related to PATH_INFO
|
|||||||
s: like meta_string_variable
|
s: like meta_string_variable
|
||||||
table: STRING_TABLE [READABLE_STRING_8]
|
table: STRING_TABLE [READABLE_STRING_8]
|
||||||
l_query_string: like query_string
|
l_query_string: like query_string
|
||||||
l_request_uri: detachable STRING_32
|
l_request_uri: detachable READABLE_STRING_8
|
||||||
|
s8: STRING_8
|
||||||
l_empty_string: like empty_string
|
l_empty_string: like empty_string
|
||||||
|
enc: PERCENT_ENCODER
|
||||||
|
utf: UTF_CONVERTER
|
||||||
do
|
do
|
||||||
create {STRING_8} l_empty_string.make_empty
|
create {STRING_8} l_empty_string.make_empty
|
||||||
empty_string := l_empty_string
|
empty_string := l_empty_string
|
||||||
@@ -319,8 +322,11 @@ feature {NONE} -- Element change: CGI meta parameter related to PATH_INFO
|
|||||||
until
|
until
|
||||||
a_vars.after
|
a_vars.after
|
||||||
loop
|
loop
|
||||||
-- Warning: truncated value to ascii !!!
|
if attached {READABLE_STRING_32} a_vars.item_for_iteration as s32 then
|
||||||
table.force (a_vars.item_for_iteration.to_string_8, a_vars.key_for_iteration)
|
table.force (utf.utf_32_string_to_utf_8_string_8 (s32), a_vars.key_for_iteration)
|
||||||
|
else
|
||||||
|
table.force (a_vars.item_for_iteration.to_string_8, a_vars.key_for_iteration)
|
||||||
|
end
|
||||||
a_vars.forth
|
a_vars.forth
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -370,14 +376,22 @@ feature {NONE} -- Element change: CGI meta parameter related to PATH_INFO
|
|||||||
if s /= Void then
|
if s /= Void then
|
||||||
l_request_uri := s
|
l_request_uri := s
|
||||||
else
|
else
|
||||||
--| It might occur that REQUEST_URI is not available, so let's compute it from SCRIPT_NAME
|
--| REQUEST_URI is not always available, in this case,
|
||||||
create l_request_uri.make_from_string (script_name)
|
--| compute it from SCRIPT_NAME, PATH_INFO and QUERY_STRING which are required by CGI.
|
||||||
|
create s8.make_from_string (script_name)
|
||||||
|
create enc
|
||||||
|
enc.append_partial_percent_encoded_string_to (utf.utf_8_string_8_to_string_32 (path_info), s8, <<'/', '!', '$', '&', '%'', '(', ')', '*', '+', ',', ';', '='>>)
|
||||||
if not l_query_string.is_empty then
|
if not l_query_string.is_empty then
|
||||||
l_request_uri.append_character ('?')
|
s8.append_character ('?')
|
||||||
l_request_uri.append (l_query_string)
|
s8.append (l_query_string)
|
||||||
end
|
end
|
||||||
|
l_request_uri := s8
|
||||||
end
|
end
|
||||||
request_uri := single_slash_starting_string (l_request_uri)
|
--| FIXME: should it strip "////abc/def" to "/abc/def" ?
|
||||||
|
--| Not sure why this was done before.
|
||||||
|
-- l_request_uri := single_slash_starting_string (l_request_uri)
|
||||||
|
request_uri := l_request_uri
|
||||||
|
set_meta_string_variable ({WGI_META_NAMES}.request_uri, l_request_uri)
|
||||||
end
|
end
|
||||||
|
|
||||||
set_orig_path_info (s: READABLE_STRING_8)
|
set_orig_path_info (s: READABLE_STRING_8)
|
||||||
@@ -482,7 +496,7 @@ invariant
|
|||||||
empty_string_unchanged: empty_string.is_empty
|
empty_string_unchanged: empty_string.is_empty
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -25,11 +25,8 @@ feature {NONE} -- Initialization
|
|||||||
|
|
||||||
make (a_name: READABLE_STRING_8; a_string: READABLE_STRING_8)
|
make (a_name: READABLE_STRING_8; a_string: READABLE_STRING_8)
|
||||||
do
|
do
|
||||||
name := url_decoded_string (a_name)
|
url_encoded_name := utf_8_percent_encoded_string (a_name)
|
||||||
value := url_decoded_string (a_string)
|
url_encoded_value := utf_8_percent_encoded_string (a_string)
|
||||||
|
|
||||||
url_encoded_name := a_name
|
|
||||||
url_encoded_value := a_string
|
|
||||||
end
|
end
|
||||||
|
|
||||||
feature -- Access
|
feature -- Access
|
||||||
@@ -38,11 +35,31 @@ feature -- Access
|
|||||||
-- <Precursor>
|
-- <Precursor>
|
||||||
--| Note that the value might be html encoded as well
|
--| Note that the value might be html encoded as well
|
||||||
--| this is the application responsibility to html decode it
|
--| this is the application responsibility to html decode it
|
||||||
|
local
|
||||||
|
v: like internal_name
|
||||||
|
do
|
||||||
|
v := internal_name
|
||||||
|
if v = Void then
|
||||||
|
v := url_decoded_string (url_encoded_name)
|
||||||
|
internal_name := v
|
||||||
|
end
|
||||||
|
Result := v
|
||||||
|
end
|
||||||
|
|
||||||
value: READABLE_STRING_32
|
value: READABLE_STRING_32
|
||||||
-- <Precursor>
|
-- <Precursor>
|
||||||
--| Note that the value might be html encoded as well
|
--| Note that the value might be html encoded as well
|
||||||
--| this is the application responsibility to html decode it
|
--| this is the application responsibility to html decode it
|
||||||
|
local
|
||||||
|
v: like internal_value
|
||||||
|
do
|
||||||
|
v := internal_value
|
||||||
|
if v = Void then
|
||||||
|
v := url_decoded_string (url_encoded_value)
|
||||||
|
internal_value := v
|
||||||
|
end
|
||||||
|
Result := v
|
||||||
|
end
|
||||||
|
|
||||||
url_encoded_name: READABLE_STRING_8
|
url_encoded_name: READABLE_STRING_8
|
||||||
-- URL encoded string of `name'.
|
-- URL encoded string of `name'.
|
||||||
@@ -50,6 +67,14 @@ feature -- Access
|
|||||||
url_encoded_value: READABLE_STRING_8
|
url_encoded_value: READABLE_STRING_8
|
||||||
-- URL encoded string of `value'.
|
-- URL encoded string of `value'.
|
||||||
|
|
||||||
|
feature {NONE} -- Access: internals
|
||||||
|
|
||||||
|
internal_name: detachable like name
|
||||||
|
-- Cached value of `name'.
|
||||||
|
|
||||||
|
internal_value: detachable like value
|
||||||
|
-- Cached value of `value'.
|
||||||
|
|
||||||
feature -- Conversion
|
feature -- Conversion
|
||||||
|
|
||||||
integer_value: INTEGER
|
integer_value: INTEGER
|
||||||
@@ -81,7 +106,7 @@ feature -- Element change
|
|||||||
|
|
||||||
change_name (a_name: like name)
|
change_name (a_name: like name)
|
||||||
do
|
do
|
||||||
name := url_decoded_string (a_name)
|
internal_name := Void
|
||||||
url_encoded_name := a_name
|
url_encoded_name := a_name
|
||||||
ensure then
|
ensure then
|
||||||
a_name.same_string (url_encoded_name)
|
a_name.same_string (url_encoded_name)
|
||||||
@@ -122,8 +147,89 @@ feature -- Visitor
|
|||||||
vis.process_string (Current)
|
vis.process_string (Current)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Implementation
|
||||||
|
|
||||||
|
utf_8_percent_encoded_string (s: READABLE_STRING_8): READABLE_STRING_8
|
||||||
|
-- Percent-encode the UTF-8 sequence characters from UTF-8 encoded `s' and
|
||||||
|
-- return the Result.
|
||||||
|
local
|
||||||
|
s8: STRING_8
|
||||||
|
i, n, nb: INTEGER
|
||||||
|
do
|
||||||
|
-- First check if there are such UTF-8 character
|
||||||
|
-- If it has, convert them and return a new object as Result
|
||||||
|
-- otherwise return `s' directly to avoid creating a new object
|
||||||
|
from
|
||||||
|
i := 1
|
||||||
|
n := s.count
|
||||||
|
nb := 0
|
||||||
|
until
|
||||||
|
i > n
|
||||||
|
loop
|
||||||
|
if s.code (i) > 0x7F then -- >= 128
|
||||||
|
nb := nb + 1
|
||||||
|
end
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
if nb > 0 then
|
||||||
|
create s8.make (s.count + nb * 3)
|
||||||
|
utf_8_string_8_into_percent_encoded_string_8 (s, s8)
|
||||||
|
Result := s8
|
||||||
|
else
|
||||||
|
Result := s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
utf_8_string_8_into_percent_encoded_string_8 (s: READABLE_STRING_8; a_result: STRING_8)
|
||||||
|
-- Copy STRING_32 corresponding to UTF-8 sequence `s' appended into `a_result'.
|
||||||
|
local
|
||||||
|
i: INTEGER
|
||||||
|
n: INTEGER
|
||||||
|
c: NATURAL_32
|
||||||
|
do
|
||||||
|
from
|
||||||
|
n := s.count
|
||||||
|
a_result.grow (a_result.count + n)
|
||||||
|
until
|
||||||
|
i >= n
|
||||||
|
loop
|
||||||
|
i := i + 1
|
||||||
|
c := s.code (i)
|
||||||
|
if c <= 0x7F then
|
||||||
|
-- 0xxxxxxx
|
||||||
|
a_result.append_code (c)
|
||||||
|
elseif c <= 0xDF then
|
||||||
|
-- 110xxxxx 10xxxxxx
|
||||||
|
url_encoder.append_percent_encoded_character_code_to (c, a_result)
|
||||||
|
i := i + 1
|
||||||
|
if i <= n then
|
||||||
|
url_encoder.append_percent_encoded_character_code_to (s.code (i), a_result)
|
||||||
|
end
|
||||||
|
elseif c <= 0xEF then
|
||||||
|
-- 1110xxxx 10xxxxxx 10xxxxxx
|
||||||
|
url_encoder.append_percent_encoded_character_code_to (s.code (i), a_result)
|
||||||
|
i := i + 2
|
||||||
|
if i <= n then
|
||||||
|
url_encoder.append_percent_encoded_character_code_to (s.code (i - 1), a_result)
|
||||||
|
url_encoder.append_percent_encoded_character_code_to (s.code (i), a_result)
|
||||||
|
end
|
||||||
|
elseif c <= 0xF7 then
|
||||||
|
-- 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||||
|
url_encoder.append_percent_encoded_character_code_to (s.code (i), a_result)
|
||||||
|
i := i + 3
|
||||||
|
if i <= n then
|
||||||
|
url_encoder.append_percent_encoded_character_code_to (s.code (i - 2), a_result)
|
||||||
|
url_encoder.append_percent_encoded_character_code_to (s.code (i - 1), a_result)
|
||||||
|
url_encoder.append_percent_encoded_character_code_to (s.code (i), a_result)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
a_result.append_code (c)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
Reference in New Issue
Block a user