From 50ba8ca7030dc79ded86928002e2b2694d99ef14 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Thu, 5 Nov 2015 21:32:24 +0100 Subject: [PATCH] Fixed various unicode issue related to query and form parameters. (Especially for the multipart/form-data encoding.) Factorized code related to smart parameters computing (handling list , table, ...) in WSF_VALUE_UTILITIES. Fixed an issue with percent_encoded_path_info computation from request_uri. Fixed issue with cookie addition having same cookie name. Fixed unicode support for uploaded file. WSF_STRING is reusing WSF_PERCENT_ENCODER. Use unicode output for WSF_DEBUG_HANDLER. Code cleaning --- .../wsf/extension/handler/wsf_debug_handler.e | 1 + .../wsf/extension/wsf_debug_information.e | 47 +++-- ...pplication_x_www_form_urlencoded_handler.e | 10 +- .../mime/wsf_multipart_form_data_handler.e | 12 +- .../server/wsf/src/request/value/wsf_any.e | 8 +- .../src/request/value/wsf_multiple_string.e | 5 +- .../server/wsf/src/request/value/wsf_string.e | 105 ++---------- .../server/wsf/src/request/value/wsf_table.e | 37 ++-- .../wsf/src/request/value/wsf_uploaded_file.e | 37 ++-- library/server/wsf/src/request/wsf_value.e | 6 +- .../wsf/src/support/wsf_mime_handler_helper.e | 117 ++----------- .../wsf/src/support/wsf_value_utilities.e | 160 ++++++++++++++++++ library/server/wsf/src/wsf_request.e | 140 ++++----------- library/server/wsf/src/wsf_response.e | 6 +- 14 files changed, 329 insertions(+), 362 deletions(-) create mode 100644 library/server/wsf/src/support/wsf_value_utilities.e diff --git a/library/server/wsf/extension/handler/wsf_debug_handler.e b/library/server/wsf/extension/handler/wsf_debug_handler.e index 7ae7a266..d34cd7fb 100644 --- a/library/server/wsf/extension/handler/wsf_debug_handler.e +++ b/library/server/wsf/extension/handler/wsf_debug_handler.e @@ -59,6 +59,7 @@ feature -- Access create dbg.make dbg.set_is_verbose (True) + dbg.set_unicode_output_enabled (True) dbg.append_cgi_variables_to (req, res, s) dbg.append_information_to (req, res, s) 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..50d778a0 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$" @@ -139,10 +138,12 @@ feature {NONE} -- Implementation: Form analyzer local n, i,p, b,e: INTEGER l_name, l_filename, l_content_type: detachable STRING_8 + l_unicode_name: READABLE_STRING_32 l_header: detachable STRING_8 l_content: detachable STRING_8 l_line: detachable STRING_8 l_up_file: WSF_UPLOADED_FILE + utf: UTF_CONVERTER do from p := 1 @@ -235,12 +236,13 @@ feature {NONE} -- Implementation: Form analyzer if l_content_type = Void then l_content_type := default_content_type end - create l_up_file.make (l_name, l_filename, l_content_type, l_content.count) - add_value_to_table (l_name, l_up_file, vars) + l_unicode_name := utf.utf_8_string_8_to_string_32 (l_name) + create l_up_file.make (l_unicode_name, utf.utf_8_string_8_to_escaped_string_32 (l_filename), l_content_type, l_content.count) + add_value_to_table (l_unicode_name, l_up_file, vars) --| `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 +256,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..37027a7b 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,8 @@ feature -- Visitor vis.process_string (Current) 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 - 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..d58f53c4 100644 --- a/library/server/wsf/src/request/value/wsf_uploaded_file.e +++ b/library/server/wsf/src/request/value/wsf_uploaded_file.e @@ -15,17 +15,27 @@ inherit end create - make + make, + make_with_percent_encoded_values feature {NONE} -- Initialization - make (a_name: READABLE_STRING_8; n: like filename; t: like content_type; s: like size) + make (a_name: READABLE_STRING_GENERAL; a_filename: READABLE_STRING_GENERAL; a_content_type: like content_type; a_size: like size) do - name := url_decoded_string (a_name) - url_encoded_name := a_name - filename := n - content_type := t - size := s + name := a_name.as_string_32 + url_encoded_name := url_encoded_string (a_name) + filename := a_filename.as_string_32 + content_type := a_content_type + size := a_size + end + + make_with_percent_encoded_values (a_encoded_name: READABLE_STRING_8; a_filename: READABLE_STRING_GENERAL; a_content_type: like content_type; a_size: like size) + do + name := url_decoded_string (a_encoded_name) + url_encoded_name := a_encoded_name + filename := a_filename.as_string_32 + content_type := a_content_type + size := a_size end feature -- Access @@ -65,11 +75,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 @@ -99,7 +108,7 @@ feature -- Visitor feature -- Access: Uploaded File - filename: STRING + filename: STRING_32 -- original filename safe_filename: STRING @@ -182,7 +191,7 @@ feature -- Basic operation if f.exists then f.rename_file (a_destination) Result := True - end + end end ensure removed: not exists @@ -241,7 +250,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..60b2bdf3 --- /dev/null +++ b/library/server/wsf/src/support/wsf_value_utilities.e @@ -0,0 +1,160 @@ +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 + l_encoded_name := a_value.url_encoded_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 + -- New WSF_STRING value built from unicode `a_name' and `a_value'. + 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 + -- New WSF_STRING value built from utf8+percent encoded `a_encoded_name' and `a_encoded_value'. + 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