diff --git a/library/server/wsf/extension/wsf_debug_information.e b/library/server/wsf/extension/wsf_debug_information.e index 5854ca93..afa41f41 100644 --- a/library/server/wsf/extension/wsf_debug_information.e +++ b/library/server/wsf/extension/wsf_debug_information.e @@ -42,6 +42,9 @@ feature -- Settings is_verbose: BOOLEAN -- Has verbose output (default: True)? + unicode_output_enabled: BOOLEAN + -- Display names and values as unicode. + feature -- Settings change set_is_verbose (b: BOOLEAN) @@ -50,6 +53,12 @@ feature -- Settings change is_verbose := b end + set_unicode_output_enabled (b: BOOLEAN) + -- if `b' then enable unicode output, otherwise disable. + do + unicode_output_enabled := b + end + feature -- Execution append_connector_informations_to (req: WSF_REQUEST; res: WSF_RESPONSE; a_output: STRING) @@ -232,7 +241,7 @@ feature {NONE} -- Implementation it as c loop s.append (" - ") - s.append (utf.escaped_utf_32_string_to_utf_8_string_8 (c.key)) + append_unicode (c.key, s) s.append_character (' ') if attached c.item as l_item then s.append_character ('{') @@ -302,7 +311,11 @@ feature {NONE} -- Implementation it as c loop a_output.append (" - ") - a_output.append (c.item.url_encoded_name) + if unicode_output_enabled then + append_unicode (c.item.name, a_output) + else + a_output.append (c.item.url_encoded_name) + end t := c.item.generating_type if t.same_string ("WSF_STRING") then else @@ -313,15 +326,15 @@ feature {NONE} -- Implementation end a_output.append_character ('=') if attached {WSF_STRING} c.item as l_str then - s := l_str.url_encoded_value + if unicode_output_enabled then + s := l_str.value + else + s := l_str.url_encoded_value + end else s := c.item.string_representation end - if s.is_valid_as_string_8 then - v := s.as_string_8 - else - v := utf.escaped_utf_32_string_to_utf_8_string_8 (s) - end + v := utf.utf_32_string_to_utf_8_string_8 (s) if v.has ('%N') then a_output.append (eol) across @@ -349,7 +362,6 @@ feature {NONE} -- Implementation local n: INTEGER v: READABLE_STRING_8 - utf: UTF_CONVERTER do if is_verbose then a_output.append (a_title) @@ -368,11 +380,7 @@ feature {NONE} -- Implementation it as c loop a_output.append (" - ") - if c.key.is_valid_as_string_8 then - a_output.append (c.key.as_string_8) - else - a_output.append (utf.utf_32_string_to_utf_8_string_8 (c.key)) - end + append_unicode (c.key, a_output) a_output.append_character ('=') v := c.item if v.has ('%N') then @@ -398,6 +406,17 @@ feature {NONE} -- Implementation end end + append_unicode (s: READABLE_STRING_GENERAL; a_output: STRING) + local + utf: UTF_CONVERTER + do + --if s.is_valid_as_string_8 then + --a_output.append (s.as_string_8) + --else + a_output.append (utf.utf_32_string_to_utf_8_string_8 (s)) + --end + end + feature -- Constants eol: STRING = "%N" diff --git a/library/server/wsf/src/mime/wsf_application_x_www_form_urlencoded_handler.e b/library/server/wsf/src/mime/wsf_application_x_www_form_urlencoded_handler.e index aa0a806a..8bb876bc 100644 --- a/library/server/wsf/src/mime/wsf_application_x_www_form_urlencoded_handler.e +++ b/library/server/wsf/src/mime/wsf_application_x_www_form_urlencoded_handler.e @@ -1,6 +1,5 @@ note description: "Summary description for {WSF_APPLICATION_X_WWW_FORM_URLENCODED_HANDLER}." - author: "" date: "$Date$" revision: "$Revision$" @@ -12,6 +11,11 @@ inherit WSF_MIME_HANDLER_HELPER + WSF_VALUE_UTILITIES + export + {NONE} all + end + feature -- Status report valid_content_type (a_content_type: HTTP_CONTENT_TYPE): BOOLEAN @@ -54,7 +58,7 @@ feature -- Execution if j > 0 then l_name := s.substring (1, j - 1) l_value := s.substring (j + 1, s.count) - add_string_value_to_table (l_name, l_value, a_vars) + add_percent_encoded_string_value_to_table (l_name, l_value, a_vars) end end end @@ -62,7 +66,7 @@ feature -- Execution end note - copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" + copyright: "2011-2015, 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)" source: "[ Eiffel Software diff --git a/library/server/wsf/src/mime/wsf_multipart_form_data_handler.e b/library/server/wsf/src/mime/wsf_multipart_form_data_handler.e index 361ada48..e757e19c 100644 --- a/library/server/wsf/src/mime/wsf_multipart_form_data_handler.e +++ b/library/server/wsf/src/mime/wsf_multipart_form_data_handler.e @@ -1,6 +1,5 @@ note description: "Summary description for {WSF_MULTIPART_FORM_DATA_HANDLER}." - author: "" date: "$Date$" revision: "$Revision$" @@ -240,7 +239,7 @@ feature {NONE} -- Implementation: Form analyzer --| `l_up_file' might have a new name req.save_uploaded_file (l_up_file, l_content) else - add_string_value_to_table (l_name, l_content, vars) + add_utf_8_string_value_to_table (l_name, l_content, vars) end else req.error_handler.add_custom_error (0, "unamed multipart entry", Void) @@ -254,7 +253,7 @@ feature {NONE} -- Implementation: Form analyzer -- Default content type note - copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" + copyright: "2011-2015, 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)" source: "[ Eiffel Software diff --git a/library/server/wsf/src/request/value/wsf_any.e b/library/server/wsf/src/request/value/wsf_any.e index fde3c710..87ed03a1 100644 --- a/library/server/wsf/src/request/value/wsf_any.e +++ b/library/server/wsf/src/request/value/wsf_any.e @@ -34,10 +34,10 @@ feature -- Access feature -- Element change change_name (a_name: like name) + -- do - name := url_decoded_string (a_name) - ensure then - a_name.same_string (url_encoded_name) + name := a_name + url_encoded_name := url_encoded_string (a_name) end feature -- Status report @@ -71,7 +71,7 @@ feature -- Visitor end note - copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" + copyright: "2011-2015, 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)" source: "[ Eiffel Software diff --git a/library/server/wsf/src/request/value/wsf_multiple_string.e b/library/server/wsf/src/request/value/wsf_multiple_string.e index 69cf8ebe..0cdd9d53 100644 --- a/library/server/wsf/src/request/value/wsf_multiple_string.e +++ b/library/server/wsf/src/request/value/wsf_multiple_string.e @@ -89,10 +89,9 @@ feature -- Access feature -- Element change change_name (a_name: like name) + -- do name := a_name - ensure then - a_name.same_string (name) end feature -- Status report @@ -180,7 +179,7 @@ invariant string_values_not_empty: values.count >= 1 note - copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" + copyright: "2011-2015, 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)" source: "[ Eiffel Software diff --git a/library/server/wsf/src/request/value/wsf_string.e b/library/server/wsf/src/request/value/wsf_string.e index a969072e..da5951b4 100644 --- a/library/server/wsf/src/request/value/wsf_string.e +++ b/library/server/wsf/src/request/value/wsf_string.e @@ -16,17 +16,24 @@ inherit end create - make + make, + make_with_percent_encoded_values convert string_representation: {READABLE_STRING_32, STRING_32} feature {NONE} -- Initialization - make (a_name: READABLE_STRING_8; a_string: READABLE_STRING_8) + make (a_name: READABLE_STRING_GENERAL; a_string: READABLE_STRING_GENERAL) do - url_encoded_name := utf_8_percent_encoded_string (a_name) - url_encoded_value := utf_8_percent_encoded_string (a_string) + url_encoded_name := url_encoded_string (a_name) + url_encoded_value := url_encoded_string (a_string) + end + + make_with_percent_encoded_values (a_encoded_name: READABLE_STRING_8; a_encoded_value: READABLE_STRING_8) + do + url_encoded_name := a_encoded_name + url_encoded_value := a_encoded_value end feature -- Access @@ -105,11 +112,10 @@ feature -- Status report feature -- Element change change_name (a_name: like name) + -- do - internal_name := Void - url_encoded_name := a_name - ensure then - a_name.same_string (url_encoded_name) + internal_name := a_name + url_encoded_name := url_encoded_string (a_name) end feature -- Helper @@ -147,89 +153,163 @@ feature -- Visitor vis.process_string (Current) end -feature {NONE} -- Implementation +--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_percent_encoded_string (s: READABLE_STRING_GENERAL): 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_into_percent_encoded_string_8 (s, s8) +-- Result := s8 +-- else +-- Result := s.to_string_8 +-- 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 +-- utf_8_string_into_percent_encoded_string_8 (s: READABLE_STRING_GENERAL; 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 +-- -- FIXME: unicode character, first utf8 it, then percent encode it. +-- append_percent_encoded_unicode_character_code_to (c, a_result) +---- a_result.append_code (c) +-- end +-- end +-- end + +-- append_percent_encoded_ascii_character_code_to (a_code: NATURAL_32; a_result: STRING_GENERAL) +-- -- Append extended ascii character code `a_code' as percent-encoded content into `a_result' +-- -- Note: it does not UTF-8 convert this extended ASCII. +-- require +-- is_extended_ascii: a_code <= 0xFF +-- local +-- c: INTEGER +-- do +-- if a_code > 0xFF then +-- -- Unicode +-- append_percent_encoded_unicode_character_code_to (a_code, a_result) +-- else +-- -- Extended ASCII +-- c := a_code.to_integer_32 +-- a_result.append_code (37) -- 37 '%%' +-- a_result.append_code (hex_digit [c |>> 4]) +-- a_result.append_code (hex_digit [c & 0xF]) +-- end +-- ensure +-- appended: a_result.count > old a_result.count +-- end + +-- append_percent_encoded_unicode_character_code_to (a_code: NATURAL_32; a_result: STRING_GENERAL) +-- -- Append Unicode character code `a_code' as UTF-8 and percent-encoded content into `a_result' +-- -- Note: it does include UTF-8 conversion of extended ASCII and Unicode. +-- do +-- if a_code <= 0x7F then +-- -- 0xxxxxxx +-- append_percent_encoded_ascii_character_code_to (a_code, a_result) +-- elseif a_code <= 0x7FF then +-- -- 110xxxxx 10xxxxxx +-- append_percent_encoded_ascii_character_code_to ((a_code |>> 6) | 0xC0, a_result) +-- append_percent_encoded_ascii_character_code_to ((a_code & 0x3F) | 0x80, a_result) +-- elseif a_code <= 0xFFFF then +-- -- 1110xxxx 10xxxxxx 10xxxxxx +-- append_percent_encoded_ascii_character_code_to ((a_code |>> 12) | 0xE0, a_result) +-- append_percent_encoded_ascii_character_code_to (((a_code |>> 6) & 0x3F) | 0x80, a_result) +-- append_percent_encoded_ascii_character_code_to ((a_code & 0x3F) | 0x80, a_result) +-- else +-- -- c <= 1FFFFF - there are no higher code points +-- -- 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx +-- append_percent_encoded_ascii_character_code_to ((a_code |>> 18) | 0xF0, a_result) +-- append_percent_encoded_ascii_character_code_to (((a_code |>> 12) & 0x3F) | 0x80, a_result) +-- append_percent_encoded_ascii_character_code_to (((a_code |>> 6) & 0x3F) | 0x80, a_result) +-- append_percent_encoded_ascii_character_code_to ((a_code & 0x3F) | 0x80, a_result) +-- end +-- ensure +-- appended: a_result.count > old a_result.count +-- end + +-- hex_digit: SPECIAL [NATURAL_32] +-- -- Hexadecimal digits. +-- once +-- create Result.make_filled (0, 16) +-- Result [0] := {NATURAL_32} 48 -- 48 '0' +-- Result [1] := {NATURAL_32} 49 -- 49 '1' +-- Result [2] := {NATURAL_32} 50 -- 50 '2' +-- Result [3] := {NATURAL_32} 51 -- 51 '3' +-- Result [4] := {NATURAL_32} 52 -- 52 '4' +-- Result [5] := {NATURAL_32} 53 -- 53 '5' +-- Result [6] := {NATURAL_32} 54 -- 54 '6' +-- Result [7] := {NATURAL_32} 55 -- 55 '7' +-- Result [8] := {NATURAL_32} 56 -- 56 '8' +-- Result [9] := {NATURAL_32} 57 -- 57 '9' +-- Result [10] := {NATURAL_32} 65 -- 65 'A' +-- Result [11] := {NATURAL_32} 66 -- 66 'B' +-- Result [12] := {NATURAL_32} 67 -- 67 'C' +-- Result [13] := {NATURAL_32} 68 -- 68 'D' +-- Result [14] := {NATURAL_32} 69 -- 69 'E' +-- Result [15] := {NATURAL_32} 70 -- 70 'F' +-- end note - copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others" + copyright: "2011-2015, 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)" source: "[ Eiffel Software diff --git a/library/server/wsf/src/request/value/wsf_table.e b/library/server/wsf/src/request/value/wsf_table.e index 51d12e19..ed740dc9 100644 --- a/library/server/wsf/src/request/value/wsf_table.e +++ b/library/server/wsf/src/request/value/wsf_table.e @@ -17,23 +17,34 @@ inherit ITERABLE [WSF_VALUE] create - make + make, + make_with_percent_encoded_name feature {NONE} -- Initialization - make (a_name: READABLE_STRING_8) + make (a_name: READABLE_STRING_GENERAL) do - name := url_decoded_string (a_name) - url_encoded_name := a_name - create values.make (5) + name := a_name.as_string_32 + url_encoded_name := url_encoded_string (a_name) + create values.make (3) + end + + make_with_percent_encoded_name (a_encoded_name: READABLE_STRING_8) + do + url_encoded_name := a_encoded_name + name := url_decoded_string (a_encoded_name) + create values.make (3) end feature -- Access name: READABLE_STRING_32 - -- Parameter name + -- + --| Note that the value might be html encoded as well + --| this is the application responsibility to html decode it url_encoded_name: READABLE_STRING_8 + -- URL encoded string of `name'. first_value: detachable WSF_VALUE -- First value if any. @@ -59,13 +70,16 @@ feature -- Access end values: HASH_TABLE [WSF_VALUE, STRING_32] + -- Associated items values, indexed by unicode name. value (k: READABLE_STRING_GENERAL): detachable WSF_VALUE + -- Value associated with name `k'. do Result := values.item (k.to_string_32) end count: INTEGER + -- Number of values. do Result := values.count end @@ -77,14 +91,15 @@ feature -- Access Result := first_name end +feature -- Element change + feature -- Element change change_name (a_name: like name) + -- do - name := url_decoded_string (a_name) - url_encoded_name := a_name - ensure then - a_name.same_string (url_encoded_name) + name := a_name + url_encoded_name := url_encoded_string (a_name) end feature -- Status report @@ -217,7 +232,7 @@ feature -- Visitor end note - copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" + copyright: "2011-2015, 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)" source: "[ Eiffel Software diff --git a/library/server/wsf/src/request/value/wsf_uploaded_file.e b/library/server/wsf/src/request/value/wsf_uploaded_file.e index 3239849d..5f314df3 100644 --- a/library/server/wsf/src/request/value/wsf_uploaded_file.e +++ b/library/server/wsf/src/request/value/wsf_uploaded_file.e @@ -65,11 +65,10 @@ feature -- Status report feature -- Element change change_name (a_name: like name) + -- do - name := url_decoded_string (a_name) - url_encoded_name := a_name - ensure then - a_name.same_string (url_encoded_name) + name := a_name + url_encoded_name := url_encoded_string (a_name) end feature -- Status report @@ -182,7 +181,7 @@ feature -- Basic operation if f.exists then f.rename_file (a_destination) Result := True - end + end end ensure removed: not exists @@ -241,7 +240,7 @@ feature -- Element change end note - copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others" + copyright: "2011-2015, 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)" source: "[ Eiffel Software diff --git a/library/server/wsf/src/request/wsf_value.e b/library/server/wsf/src/request/wsf_value.e index ce57dd63..4e05c5ac 100644 --- a/library/server/wsf/src/request/wsf_value.e +++ b/library/server/wsf/src/request/wsf_value.e @@ -36,8 +36,10 @@ feature -- Access feature -- Element change change_name (a_name: like name) - -- Change parameter name + -- Change parameter `name'. deferred + ensure + name_changed: a_name.same_string (name) end feature -- Status report @@ -128,7 +130,7 @@ feature -- Visitor end note - copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others" + copyright: "2011-2015, 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)" source: "[ Eiffel Software diff --git a/library/server/wsf/src/support/wsf_mime_handler_helper.e b/library/server/wsf/src/support/wsf_mime_handler_helper.e index 2f64720b..fefae1bd 100644 --- a/library/server/wsf/src/support/wsf_mime_handler_helper.e +++ b/library/server/wsf/src/support/wsf_mime_handler_helper.e @@ -7,122 +7,25 @@ note deferred class WSF_MIME_HANDLER_HELPER +inherit + ANY + + WSF_VALUE_UTILITIES + export + {NONE} all + end + feature {NONE} -- Implementation full_input_data (req: WSF_REQUEST): STRING_8 + -- Read or reused full input data from `req'. do create Result.make (0) req.read_input_data_into (Result) end - add_string_value_to_table (a_name: READABLE_STRING_8; a_value: READABLE_STRING_8; a_table: HASH_TABLE [WSF_VALUE, READABLE_STRING_GENERAL]) - do - add_value_to_table (a_name, new_string_value (a_name, a_value), a_table) - end - - add_value_to_table (a_name: READABLE_STRING_8; a_value: WSF_VALUE; a_table: HASH_TABLE [WSF_VALUE, READABLE_STRING_GENERAL]) - local - l_decoded_name: STRING_32 - v: detachable WSF_VALUE - n,k,r: STRING_32 --- k32: STRING_32 - p,q: INTEGER - tb,ptb: detachable WSF_TABLE - do - --| Check if this is a list format such as choice[] or choice[a] or even choice[a][] or choice[a][b][c]... - l_decoded_name := url_encoder.decoded_string (a_name) - p := l_decoded_name.index_of ({CHARACTER_32}'[', 1) - if p > 0 then - q := l_decoded_name.index_of ({CHARACTER_32}']', p + 1) - if q > p then - n := l_decoded_name.substring (1, p - 1) - r := l_decoded_name.substring (q + 1, l_decoded_name.count) - r.left_adjust; r.right_adjust - - create tb.make (n) - if a_table.has_key (tb.name) and then attached {WSF_TABLE} a_table.found_item as l_existing_table then - tb := l_existing_table - end - - k := l_decoded_name.substring (p + 1, q - 1) - k.left_adjust; k.right_adjust - if k.is_empty then - k.append_integer (tb.count + 1) - end - v := tb - n.append_character ({CHARACTER_32}'[') - n.append (k) - n.append_character ({CHARACTER_32}']') - - from - until - r.is_empty - loop - ptb := tb - p := r.index_of ({CHARACTER_32} '[', 1) - if p > 0 then - q := r.index_of ({CHARACTER_32} ']', p + 1) - if q > p then - if attached {WSF_TABLE} ptb.value (k) as l_tb_value then - tb := l_tb_value - else - create tb.make (n) - ptb.add_value (tb, k) - end - - k := r.substring (p + 1, q - 1) - r := r.substring (q + 1, r.count) - r.left_adjust; r.right_adjust - if k.is_empty then - k.append_integer (tb.count + 1) - end - n.append_character ('[') - n.append (k) - n.append_character (']') - end - else - r.wipe_out - --| Ignore bad value - end - end - a_value.change_name (n) - tb.add_value (a_value, k) - else - --| Missing end bracket - end - end - if v = Void then - a_value.change_name (a_name) - v := a_value - end - if a_table.has_key (v.name) and then attached a_table.found_item as l_existing_value then - if tb /= Void then - --| Already done in previous part - elseif attached {WSF_MULTIPLE_STRING} l_existing_value as l_multi then - l_multi.add_value (v) - else - a_table.force (create {WSF_MULTIPLE_STRING}.make_with_array (<>), v.name) - check replaced: a_table.found and then a_table.found_item ~ l_existing_value end - end - else - a_table.force (v, v.name) - end - end - - new_string_value (a_name: READABLE_STRING_8; a_value: READABLE_STRING_8): WSF_STRING - do - create Result.make (a_name, a_value) - end - -feature {NONE} -- Implementation - - url_encoder: URL_ENCODER - once - create {UTF8_URL_ENCODER} Result - end - note - copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" + copyright: "2011-2015, 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)" source: "[ Eiffel Software diff --git a/library/server/wsf/src/support/wsf_value_utilities.e b/library/server/wsf/src/support/wsf_value_utilities.e new file mode 100644 index 00000000..31a87287 --- /dev/null +++ b/library/server/wsf/src/support/wsf_value_utilities.e @@ -0,0 +1,158 @@ +note + description: "[ + Utility routines to handle parameters and convert them as string, list or table values. + ]" + date: "$Date$" + revision: "$Revision$" + +class + WSF_VALUE_UTILITIES + +inherit + ANY + + SHARED_WSF_PERCENT_ENCODER + rename + percent_encoder as url_encoder + export + {NONE} all + end + +feature -- Smart parameter identification + + add_utf_8_string_value_to_table (a_utf_8_name: READABLE_STRING_8; a_utf_8_value: READABLE_STRING_8; a_table: HASH_TABLE [WSF_VALUE, READABLE_STRING_GENERAL]) + local + utf: UTF_CONVERTER + n,v: READABLE_STRING_32 + do + n := utf.utf_8_string_8_to_string_32 (a_utf_8_name) + v := utf.utf_8_string_8_to_string_32 (a_utf_8_value) + add_value_to_table (n, new_string_value (n, v), a_table) + end + + add_percent_encoded_string_value_to_table (a_encoded_name: READABLE_STRING_8; a_encoded_value: READABLE_STRING_8; a_table: HASH_TABLE [WSF_VALUE, READABLE_STRING_GENERAL]) + local + v: WSF_STRING + do + v := new_string_value_with_percent_encoded_values (a_encoded_name, a_encoded_value) + add_value_to_table (v.name, v, a_table) + end + + add_value_to_table (a_name: READABLE_STRING_GENERAL; a_value: WSF_VALUE; a_table: HASH_TABLE [WSF_VALUE, READABLE_STRING_GENERAL]) + local + l_decoded_name: STRING_32 + l_encoded_name: READABLE_STRING_8 + v: detachable WSF_VALUE + n,k,r,vn: STRING_32 + p,q: INTEGER + tb,ptb: detachable WSF_TABLE + do + --| Check if this is a list format such as choice[] or choice[a] or even choice[a][] or choice[a][b][c]... + l_decoded_name := a_name.as_string_32 --url_encoder.decoded_string (a_name) + l_encoded_name := url_encoder.percent_encoded_string (l_decoded_name) + p := l_decoded_name.index_of ({CHARACTER_32}'[', 1) + n := l_decoded_name + if p > 0 then + q := l_decoded_name.index_of ({CHARACTER_32}']', p + 1) + if q > p then + n := l_decoded_name.substring (1, p - 1) + r := l_decoded_name.substring (q + 1, l_decoded_name.count) + r.left_adjust; r.right_adjust + + create tb.make (n) + if attached {WSF_TABLE} a_table.item (tb.name) as l_existing_table then + tb := l_existing_table + end + + k := l_decoded_name.substring (p + 1, q - 1) + k.left_adjust; k.right_adjust + if k.is_empty then + k.append_integer (tb.count + 1) + end + v := tb + create vn.make_from_string (n) + vn.append_character ({CHARACTER_32}'[') + vn.append (k) + vn.append_character ({CHARACTER_32}']') + + from + until + r.is_empty + loop + ptb := tb + p := r.index_of ({CHARACTER_32} '[', 1) + if p > 0 then + q := r.index_of ({CHARACTER_32} ']', p + 1) + if q > p then + if attached {WSF_TABLE} ptb.value (k) as l_tb_value then + tb := l_tb_value + else + create tb.make (n) + ptb.add_value (tb, k) + end + + k := r.substring (p + 1, q - 1) + r := r.substring (q + 1, r.count) + r.left_adjust; r.right_adjust + if k.is_empty then + k.append_integer (tb.count + 1) + end + vn.append_character ('[') + vn.append (k) + vn.append_character (']') + end + else + r.wipe_out + --| Ignore bad value + end + end + a_value.change_name (vn) + tb.add_value (a_value, k) + else + --| Missing end bracket + end + end + if v = Void then + a_value.change_name (l_decoded_name) + v := a_value + end + if attached a_table.item (n) as l_existing_value then + if tb /= Void then + --| Already done in previous part + elseif attached {WSF_MULTIPLE_STRING} l_existing_value as l_multi then + l_multi.add_value (v) + elseif attached {WSF_TABLE} l_existing_value as l_table then + -- Keep previous values (most likely we have table[1]=foo, table[2]=bar ..and table=/foo/bar + -- Anyway for this case, we keep the previous version, and ignore this "conflict" + else + a_table.force (create {WSF_MULTIPLE_STRING}.make_with_array (<>), v.name) + check replaced: a_table.found and then a_table.found_item ~ l_existing_value end + end + else + a_table.force (v, n) + end + end + +feature -- Factory + + new_string_value (a_name: READABLE_STRING_GENERAL; a_value: READABLE_STRING_GENERAL): WSF_STRING + do + create Result.make (a_name, a_value) + end + + new_string_value_with_percent_encoded_values (a_encoded_name: READABLE_STRING_8; a_encoded_value: READABLE_STRING_8): WSF_STRING + do + create Result.make_with_percent_encoded_values (a_encoded_name, a_encoded_value) + end + +note + copyright: "2011-2015, 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)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/wsf/src/wsf_request.e b/library/server/wsf/src/wsf_request.e index e644e70e..061f82e5 100644 --- a/library/server/wsf/src/wsf_request.e +++ b/library/server/wsf/src/wsf_request.e @@ -20,8 +20,8 @@ note About https support: `is_https' indicates if the request is made through an https connection or not. ]" - date: "$Date: 2014-05-14 16:52:42 +0200 (mer., 14 mai 2014) $" - revision: "$Revision: 95057 $" + date: "$Date$" + revision: "$Revision$" class WSF_REQUEST @@ -41,6 +41,11 @@ inherit {NONE} all end + WSF_VALUE_UTILITIES + export + {NONE} all + end + create {WSF_EXECUTION, WGI_EXPORTER} make_from_wgi @@ -846,7 +851,7 @@ feature -- Access: CGI meta parameters - 1.1 local l_result: like internal_percent_encoded_path_info r: READABLE_STRING_8 - i: INTEGER + i,m,n,spos: INTEGER do l_result := internal_percent_encoded_path_info if l_result = Void then @@ -860,6 +865,28 @@ feature -- Access: CGI meta parameters - 1.1 if attached script_name as s then if l_result.starts_with (s) then l_result := l_result.substring (s.count + 1, l_result.count) + else + --| Handle Rewrite url engine, to have clean path + from + i := 1 + m := l_result.count + n := s.count + until + i > m or i > n or l_result[i] /= s[i] + loop + if l_result[i] = '/' then + spos := i + end + i := i + 1 + end + if i > 1 then + if l_result[i-1] = '/' then + i := i -1 + elseif spos > 0 then + i := spos + end + l_result := l_result.substring (i, m) + end end end internal_percent_encoded_path_info := l_result @@ -1399,7 +1426,7 @@ feature {NONE} -- Cookies k.left_adjust k.right_adjust if not k.is_empty then - add_value_to_table (k, v, l_cookies) + add_percent_encoded_string_value_to_table (k, v, l_cookies) end end end @@ -1463,7 +1490,7 @@ feature {WSF_REQUEST_PATH_PARAMETERS_SOURCE} -- Path parameters: Element change across lst as c loop - add_value_to_table (c.key, c.item, l_table) + add_percent_encoded_string_value_to_table (c.key, c.item, l_table) end src.update_path_parameters (l_table) end @@ -1494,7 +1521,7 @@ feature {NONE} -- Query parameters: implementation vars: like internal_query_parameters_table p,e: INTEGER rq_uri: like request_uri - s: detachable STRING + s: detachable READABLE_STRING_8 do vars := internal_query_parameters_table if vars = Void then @@ -1556,7 +1583,7 @@ feature {NONE} -- Query parameters: implementation l_name := s l_value := empty_string_8 end - add_value_to_table (l_name, l_value, Result) + add_percent_encoded_string_value_to_table (l_name, l_value, Result) end end end @@ -1715,100 +1742,6 @@ feature {NONE} -- Form fields and related Result := vars end -feature {NONE} -- Implementation: smart parameter identification - - add_value_to_table (a_name: READABLE_STRING_8; a_value: READABLE_STRING_8; a_table: STRING_TABLE [WSF_VALUE]) - -- Add urlencoded parameter `a_name'=`a_value' to `a_table' - -- following smart computation such as handling the "..[..]" as table - local - v: detachable WSF_VALUE - n, k, r: STRING_8 - k32: STRING_32 - p, q: INTEGER - tb, ptb: detachable WSF_TABLE - do - --| Check if this is a list format such as choice[] or choice[a] or even choice[a][] or choice[a][b][c]... - p := a_name.index_of ('[', 1) - if p > 0 then - q := a_name.index_of (']', p + 1) - if q > p then - n := a_name.substring (1, p - 1) - r := a_name.substring (q + 1, a_name.count) - r.left_adjust; r.right_adjust - - create tb.make (n) - if a_table.has_key (tb.name) and then attached {WSF_TABLE} a_table.found_item as l_existing_table then - tb := l_existing_table - end - - k := a_name.substring (p + 1, q - 1) - k.left_adjust; k.right_adjust - if k.is_empty then - k.append_integer (tb.count + 1) - end - v := tb - create n.make_from_string (n) - n.append_character ('[') - n.append (k) - n.append_character (']') - - from - until - r.is_empty - loop - ptb := tb - p := r.index_of ({CHARACTER_8} '[', 1) - if p > 0 then - q := r.index_of ({CHARACTER_8} ']', p + 1) - if q > p then - k32 := url_decoded_string (k) - if attached {WSF_TABLE} ptb.value (k32) as l_tb_value then - tb := l_tb_value - else - create tb.make (n) - ptb.add_value (tb, k32) - end - - k := r.substring (p + 1, q - 1) - r := r.substring (q + 1, r.count) - r.left_adjust; r.right_adjust - if k.is_empty then - k.append_integer (tb.count + 1) - end - n.append_character ('[') - n.append (k) - n.append_character (']') - end - else - r.wipe_out - --| Ignore bad value - end - end - tb.add_value (new_string_value (n, a_value), k) - else - --| Missing end bracket - end - end - if v = Void then - v := new_string_value (a_name, a_value) - end - if a_table.has_key (v.name) and then attached a_table.found_item as l_existing_value then - if tb /= Void then - --| Already done in previous part - elseif attached {WSF_MULTIPLE_STRING} l_existing_value as l_multi then - l_multi.add_value (v) - elseif attached {WSF_TABLE} l_existing_value as l_table then - -- Keep previous values (most likely we have table[1]=foo, table[2]=bar ..and table=/foo/bar - -- Anyway for this case, we keep the previous version, and ignore this "conflict" - else - a_table.force (create {WSF_MULTIPLE_STRING}.make_with_array (<>), v.name) - check replaced: a_table.found and then a_table.found_item ~ l_existing_value end - end - else - a_table.force (v, v.name) - end - end - feature -- Uploaded File Handling is_uploaded_file (a_filename: READABLE_STRING_GENERAL): BOOLEAN @@ -2133,11 +2066,6 @@ feature {NONE} -- Implementation: utilities one_starting_slash: Result[1] = '/' and (Result.count = 1 or else Result[2] /= '/') end - new_string_value (a_name: READABLE_STRING_8; a_value: READABLE_STRING_8): WSF_STRING - do - create Result.make (a_name, a_value) - end - empty_string_32: IMMUTABLE_STRING_32 -- Reusable empty string once diff --git a/library/server/wsf/src/wsf_response.e b/library/server/wsf/src/wsf_response.e index f787dc8f..0ca3530c 100644 --- a/library/server/wsf/src/wsf_response.e +++ b/library/server/wsf/src/wsf_response.e @@ -319,7 +319,7 @@ feature -- Header output operation: helpers feature -- Header add cookie add_cookie (a_cookie: WSF_COOKIE) - -- Add a Set-Cookie header field to the response, + -- Add a Set-Cookie header field to the response, -- if no Set-Cookie header field already use same cookie-name. --| Servers SHOULD NOT include more than one Set-Cookie header field in --| the same response with the same cookie-name. @@ -328,7 +328,7 @@ feature -- Header add cookie do across internal_header.headers as ic - until + until l_same_cookie_name loop if ic.item.starts_with ("Set-Cookie:") then @@ -564,7 +564,7 @@ feature {NONE} -- Implemenation loop j := j + 1 end - if j > n then + if j <= n then Result := a_cookie_name.same_characters (a_cookie_line, j, i, 1) end end