From e1ef4c390ebf4d4b399024fe1233ae5694dd9452 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Fri, 22 Jul 2011 13:12:03 +0200 Subject: [PATCH] fixing issue with URI TEMPLATE matcher --- .../protocol/uri_template/src/uri_template.e | 152 +++++++++++------- .../src/uri_template_match_result.e | 20 ++- .../uri_template/tests/test_uri_template.e | 17 +- 3 files changed, 132 insertions(+), 57 deletions(-) diff --git a/library/protocol/uri_template/src/uri_template.e b/library/protocol/uri_template/src/uri_template.e index c479985f..96e65268 100644 --- a/library/protocol/uri_template/src/uri_template.e +++ b/library/protocol/uri_template/src/uri_template.e @@ -13,6 +13,11 @@ note class URI_TEMPLATE +inherit + HASHABLE + + DEBUG_OUTPUT + create make @@ -23,17 +28,47 @@ feature {NONE} -- Initialization template := s end - make_with_handler (s: STRING; a_handler: detachable URI_TEMPLATE_HANDLER) - do - make (s) - analyze (a_handler) - end - feature -- Access template: STRING -- URI string representation +feature -- Status report + + debug_output: STRING + -- String that should be displayed in debugger to represent `Current'. + do + create Result.make_from_string (template) + end + +feature -- Access + + hash_code: INTEGER + -- Hash code value + do + Result := template.hash_code + end + +feature -- Structures + + variable_names: LIST [STRING] + do + analyze (Void) + if attached expansion_parts as l_x_parts then + create {ARRAYED_LIST [STRING]} Result.make (l_x_parts.count) + from + l_x_parts.start + until + l_x_parts.after + loop + Result.append (l_x_parts.item.variable_names) + l_x_parts.forth + end + else + create {ARRAYED_LIST [STRING]} Result.make (0) + end + end + path_variable_names: LIST [STRING] do analyze (Void) @@ -77,6 +112,7 @@ feature -- Access feature -- Builder string (a_ht: HASH_TABLE [detachable ANY, STRING]): STRING + -- Expanded template using variable from `a_ht' local tpl: like template exp: URI_TEMPLATE_EXPRESSION @@ -109,12 +145,7 @@ feature -- Builder end end - url_encoder: URL_ENCODER - once - create Result - end - -feature -- Analyze +feature -- Match match (a_uri: STRING): detachable URI_TEMPLATE_MATCH_RESULT local @@ -126,6 +157,7 @@ feature -- Analyze vn, s,t: STRING vv: STRING l_vars, l_path_vars, l_query_vars: HASH_TABLE [STRING, STRING] + l_uri_count: INTEGER do --| Extract expansion parts "\\{([^\\}]*)\\}" analyze (Void) @@ -133,45 +165,53 @@ feature -- Analyze create l_path_vars.make (l_x_parts.count) create l_query_vars.make (l_x_parts.count) l_vars := l_path_vars - tpl := template b := True - from - l_x_parts.start - p := 1 - l_offset := 0 - until - l_x_parts.after or not b - loop - exp := l_x_parts.item - vn := exp.expression - q := exp.position - --| Check text between vars - if q > p then - t := tpl.substring (p, q - 1) - s := a_uri.substring (p + l_offset, q + l_offset - 1) - b := s.same_string (t) - p := q + vn.count + 2 - end - --| Check related variable - if not vn.is_empty then - if exp.is_query then - l_vars := l_query_vars - else - l_vars := l_path_vars + l_uri_count := a_uri.count + tpl := template + if l_x_parts.is_empty then + b := a_uri.substring (1, tpl.count).same_string (tpl) + else + from + l_x_parts.start + p := 1 + l_offset := 0 + until + l_x_parts.after or not b + loop + exp := l_x_parts.item + vn := exp.expression + q := exp.position + --| Check text between vars + if q > p then + t := tpl.substring (p, q - 1) + s := a_uri.substring (p + l_offset, q + l_offset - 1) + b := s.same_string (t) + p := q + vn.count + 2 end - - inspect vn[1] - when '?' then - import_form_style_parameters_into (a_uri.substring (q + l_offset + 1, a_uri.count), l_vars) - when ';' then - import_path_style_parameters_into (a_uri.substring (q + l_offset, a_uri.count), l_vars) - else - vv := next_path_variable_value (a_uri, q + l_offset) - l_vars.force (vv, vn) - l_offset := l_offset + vv.count - (vn.count + 2) + --| Check related variable + if b and then not vn.is_empty then + if exp.is_query then + l_vars := l_query_vars + else + l_vars := l_path_vars + end + if q + l_offset <= l_uri_count then + inspect vn[1] + when '?' then + import_form_style_parameters_into (a_uri.substring (q + l_offset + 1, l_uri_count), l_vars) + when ';' then + import_path_style_parameters_into (a_uri.substring (q + l_offset, l_uri_count), l_vars) + else + vv := next_path_variable_value (a_uri, q + l_offset) + l_vars.force (vv, vn) + l_offset := l_offset + vv.count - (vn.count + 2) + end + else + b := exp.is_query --| query are optional + end end + l_x_parts.forth end - l_x_parts.forth end if b then create Result.make (l_path_vars, l_query_vars) @@ -179,6 +219,13 @@ feature -- Analyze end end +feature {NONE} -- Internal Access + + expansion_parts: detachable LIST [URI_TEMPLATE_EXPRESSION] + -- Expansion parts + +feature {NONE} -- Implementation + analyze (a_handler: detachable URI_TEMPLATE_HANDLER) local l_x_parts: like expansion_parts @@ -233,11 +280,6 @@ feature -- Analyze end end -feature {NONE} -- Implementation - - expansion_parts: detachable LIST [URI_TEMPLATE_EXPRESSION] - -- Expansion parts - import_path_style_parameters_into (a_content: STRING; res: HASH_TABLE [STRING, STRING]) require a_content_attached: a_content /= Void @@ -313,9 +355,9 @@ feature {NONE} -- Implementation Result := a_uri.substring (a_index, p) end - comma_separated_variable_names (s: STRING): LIST [STRING] - do - Result := s.split (',') + url_encoder: URL_ENCODER + once + create Result end note diff --git a/library/protocol/uri_template/src/uri_template_match_result.e b/library/protocol/uri_template/src/uri_template_match_result.e index 8c9cb3d2..711b590a 100644 --- a/library/protocol/uri_template/src/uri_template_match_result.e +++ b/library/protocol/uri_template/src/uri_template_match_result.e @@ -8,7 +8,8 @@ class URI_TEMPLATE_MATCH_RESULT create - make + make, + make_empty feature {NONE} -- Initialization @@ -18,10 +19,27 @@ feature {NONE} -- Initialization query_variables := q end + make_empty + do + make (create {like path_variables}.make (0), create {like query_variables}.make (0)) + end + feature -- Access + variable (n: STRING): detachable STRING + -- Value related to variable name `n' + do + Result := query_variables.item (n) + if Result = Void then + Result := path_variables.item (n) + end + end + path_variables: HASH_TABLE [STRING, STRING] + -- Variables being part of the path segments + query_variables: HASH_TABLE [STRING, STRING] + -- Variables being part of the query segments (i.e: after the ? ) ;note copyright: "2011-2011, Eiffel Software and others" diff --git a/library/protocol/uri_template/tests/test_uri_template.e b/library/protocol/uri_template/tests/test_uri_template.e index 76219cb8..65989a99 100644 --- a/library/protocol/uri_template/tests/test_uri_template.e +++ b/library/protocol/uri_template/tests/test_uri_template.e @@ -30,8 +30,15 @@ feature -- Test routines tpl: URI_TEMPLATE do create tpl.make ("api/foo/{foo_id}/{?id,extra}") + uri_template_match (tpl, "api/foo/bar/", <<["foo_id", "bar"]>>, <<>>) uri_template_match (tpl, "api/foo/bar/?id=123", <<["foo_id", "bar"]>>, <<["id", "123"]>>) uri_template_match (tpl, "api/foo/bar/?id=123&extra=test", <<["foo_id", "bar"]>>, <<["id", "123"], ["extra", "test"]>>) + uri_template_match (tpl, "api/foo/bar/?id=123&extra=test&one=more", <<["foo_id", "bar"]>>, <<["id", "123"], ["extra", "test"]>>) + uri_template_mismatch (tpl, "") + uri_template_mismatch (tpl, "/") + uri_template_mismatch (tpl, "foo/bar/?id=123") + uri_template_mismatch (tpl, "/api/foo/bar/") + uri_template_mismatch (tpl, "api/foo/bar") create tpl.make ("weather/{state}/{city}?forecast={day}") uri_template_match (tpl, "weather/California/Goleta?forecast=today", <<["state", "California"], ["city", "Goleta"]>>, <<["day", "today"]>>) @@ -563,6 +570,14 @@ feature -- Test routines assert ("query variables matched", matched) end + uri_template_mismatch (a_uri_template: URI_TEMPLATE; a_uri: STRING) + local + l_match: detachable URI_TEMPLATE_MATCH_RESULT + do + l_match := a_uri_template.match (a_uri) + assert ("uri %"" + a_uri + "%" does not match template %"" + a_uri_template.template + "%"", l_match = Void) + end + uri_template_match (a_uri_template: URI_TEMPLATE; a_uri: STRING; path_res: ARRAY [TUPLE [name: STRING; value: STRING]]; query_res: ARRAY [TUPLE [name: STRING; value: STRING]]) local b: BOOLEAN @@ -584,7 +599,7 @@ feature -- Test routines assert ("uri matched path variables", b) end if attached l_match.query_variables as query_ht then - b := query_ht.count = query_res.count + b := query_ht.count >= query_res.count from i := query_res.lower until