diff --git a/examples/restbucksCRUD/restbucks-safe.ecf b/examples/restbucksCRUD/restbucks-safe.ecf index 30267388..912b95ca 100644 --- a/examples/restbucksCRUD/restbucks-safe.ecf +++ b/examples/restbucksCRUD/restbucks-safe.ecf @@ -1,5 +1,5 @@ - + diff --git a/examples/restbucksCRUD/src/resource/order_handler.e b/examples/restbucksCRUD/src/resource/order_handler.e index 057a3a95..c11883d1 100644 --- a/examples/restbucksCRUD/src/resource/order_handler.e +++ b/examples/restbucksCRUD/src/resource/order_handler.e @@ -33,6 +33,8 @@ inherit REFACTORING_HELPER SHARED_ORDER_VALIDATION + WSF_SELF_DOCUMENTED_HANDLER + feature -- execute uri_execute (req: WSF_REQUEST; res: WSF_RESPONSE) @@ -51,6 +53,25 @@ feature -- API DOC api_doc : STRING = "URI:/order METHOD: POST%N URI:/order/{orderid} METHOD: GET, PUT, DELETE%N" + +feature -- Documentation + + mapping_documentation (m: WSF_ROUTER_MAPPING; a_request_methods: detachable WSF_REQUEST_METHODS): WSF_ROUTER_MAPPING_DOCUMENTATION + do + create Result.make (m) + if a_request_methods /= Void then + if a_request_methods.has_method_post then + Result.add_description ("URI:/order METHOD: POST") + elseif + a_request_methods.has_method_get + or a_request_methods.has_method_put + or a_request_methods.has_method_delete + then + Result.add_description ("URI:/order/{orderid} METHOD: GET, PUT, DELETE") + end + end + end + feature -- HTTP Methods do_get (req: WSF_REQUEST; res: WSF_RESPONSE) diff --git a/examples/restbucksCRUD/src/restbucks_server.e b/examples/restbucksCRUD/src/restbucks_server.e index 79870862..3fbd8add 100644 --- a/examples/restbucksCRUD/src/restbucks_server.e +++ b/examples/restbucksCRUD/src/restbucks_server.e @@ -48,24 +48,8 @@ feature -- Execution -- I'm using this method to handle the method not allowed response -- in the case that the given uri does not have a corresponding http method -- to handle it. - local - h : HTTP_HEADER - l_description : STRING - l_api_doc : STRING do - if req.content_length_value > 0 then - req.input.read_string (req.content_length_value.as_integer_32) - end - create h.make - h.put_content_type_text_plain - l_api_doc := "%NPlease check the API%NURI:/order METHOD: POST%NURI:/order/{orderid} METHOD: GET, PUT, DELETE%N" - l_description := req.request_method + req.request_uri + " is not allowed" + "%N" + l_api_doc - l_description.append ("%NHTML documentation:/api/doc METHOD: GET%N") - h.put_content_length (l_description.count) - h.put_current_date - res.set_status_code ({HTTP_STATUS_CODE}.method_not_allowed) - res.put_header_text (h.string) - res.put_string (l_description) + Precursor (req, res) end note diff --git a/examples/tutorial/step_4/hello/src/hello_application.e b/examples/tutorial/step_4/hello/src/hello_application.e index b2c4d250..2dfbaeb1 100644 --- a/examples/tutorial/step_4/hello/src/hello_application.e +++ b/examples/tutorial/step_4/hello/src/hello_application.e @@ -42,17 +42,17 @@ feature {NONE} -- Initialization feature -- Helper: mapping - map_agent_uri (a_uri: READABLE_STRING_8; a_action: like {WSF_URI_AGENT_HANDLER}.action; rqst_methods: detachable WSF_ROUTER_METHODS) + map_agent_uri (a_uri: READABLE_STRING_8; a_action: like {WSF_URI_AGENT_HANDLER}.action; rqst_methods: detachable WSF_REQUEST_METHODS) do router.map_with_request_methods (create {WSF_URI_MAPPING}.make (a_uri, create {WSF_URI_AGENT_HANDLER}.make (a_action)), rqst_methods) end - map_uri_template (a_tpl: READABLE_STRING_8; a_handler: WSF_URI_TEMPLATE_HANDLER; rqst_methods: detachable WSF_ROUTER_METHODS) + map_uri_template (a_tpl: READABLE_STRING_8; a_handler: WSF_URI_TEMPLATE_HANDLER; rqst_methods: detachable WSF_REQUEST_METHODS) do router.map_with_request_methods (create {WSF_URI_TEMPLATE_MAPPING}.make (a_tpl, a_handler), rqst_methods) end - map_agent_uri_template_response (a_tpl: READABLE_STRING_8; a_action: like {WSF_URI_TEMPLATE_RESPONSE_AGENT_HANDLER}.action; rqst_methods: detachable WSF_ROUTER_METHODS) + map_agent_uri_template_response (a_tpl: READABLE_STRING_8; a_action: like {WSF_URI_TEMPLATE_RESPONSE_AGENT_HANDLER}.action; rqst_methods: detachable WSF_REQUEST_METHODS) do router.map_with_request_methods (create {WSF_URI_TEMPLATE_MAPPING}.make (a_tpl, create {WSF_URI_TEMPLATE_RESPONSE_AGENT_HANDLER}.make (a_action)), rqst_methods) end diff --git a/library/server/wsf/router/documentation/wsf_router_self_documentation_handler.e b/library/server/wsf/router/documentation/wsf_router_self_documentation_handler.e index 0de5d36b..b0fbb6da 100644 --- a/library/server/wsf/router/documentation/wsf_router_self_documentation_handler.e +++ b/library/server/wsf/router/documentation/wsf_router_self_documentation_handler.e @@ -45,7 +45,7 @@ feature {NONE} -- Initialization feature -- Documentation - mapping_documentation (m: WSF_ROUTER_MAPPING): WSF_ROUTER_MAPPING_DOCUMENTATION + mapping_documentation (m: WSF_ROUTER_MAPPING; a_request_methods: detachable WSF_REQUEST_METHODS): WSF_ROUTER_MAPPING_DOCUMENTATION do create Result.make (m) Result.set_is_hidden (is_hidden) @@ -54,7 +54,7 @@ feature -- Documentation feature {WSF_ROUTER} -- Mapping - on_mapped (a_mapping: WSF_ROUTER_MAPPING; a_rqst_methods: detachable WSF_ROUTER_METHODS) + on_mapped (a_mapping: WSF_ROUTER_MAPPING; a_rqst_methods: detachable WSF_REQUEST_METHODS) -- Callback called when a router map a route to Current handler do if attached {WSF_STARTS_WITH_MAPPING} a_mapping as m then diff --git a/library/server/wsf/router/documentation/wsf_router_self_documentation_message.e b/library/server/wsf/router/documentation/wsf_router_self_documentation_message.e index d936f8e1..1b1bd834 100644 --- a/library/server/wsf/router/documentation/wsf_router_self_documentation_message.e +++ b/library/server/wsf/router/documentation/wsf_router_self_documentation_message.e @@ -191,14 +191,14 @@ feature {WSF_RESPONSE} -- Output res.put_string (l_description) end - append_documentation_to (s: STRING_8; m: WSF_ROUTER_MAPPING; meths: detachable WSF_ROUTER_METHODS) + append_documentation_to (s: STRING_8; m: WSF_ROUTER_MAPPING; meths: detachable WSF_REQUEST_METHODS) local l_url: detachable STRING_8 l_base_url: detachable READABLE_STRING_8 l_doc: detachable WSF_ROUTER_MAPPING_DOCUMENTATION do if attached {WSF_SELF_DOCUMENTED_ROUTER_MAPPING} m as l_doc_mapping then - l_doc := l_doc_mapping.documentation + l_doc := l_doc_mapping.documentation (meths) end if l_doc = Void or else not l_doc.is_hidden then diff --git a/library/server/wsf/router/documentation/wsf_self_documented_handler.e b/library/server/wsf/router/documentation/wsf_self_documented_handler.e index 8617759c..84608a0d 100644 --- a/library/server/wsf/router/documentation/wsf_self_documented_handler.e +++ b/library/server/wsf/router/documentation/wsf_self_documented_handler.e @@ -9,7 +9,7 @@ deferred class feature -- Documentation - mapping_documentation (m: WSF_ROUTER_MAPPING): WSF_ROUTER_MAPPING_DOCUMENTATION + mapping_documentation (m: WSF_ROUTER_MAPPING; a_request_methods: detachable WSF_REQUEST_METHODS): WSF_ROUTER_MAPPING_DOCUMENTATION deferred end diff --git a/library/server/wsf/router/documentation/wsf_self_documented_router_mapping.e b/library/server/wsf/router/documentation/wsf_self_documented_router_mapping.e index e4281de9..49a8f5ca 100644 --- a/library/server/wsf/router/documentation/wsf_self_documented_router_mapping.e +++ b/library/server/wsf/router/documentation/wsf_self_documented_router_mapping.e @@ -12,10 +12,10 @@ inherit feature -- Documentation - documentation: WSF_ROUTER_MAPPING_DOCUMENTATION + documentation (a_request_methods: detachable WSF_REQUEST_METHODS): WSF_ROUTER_MAPPING_DOCUMENTATION do if attached {WSF_SELF_DOCUMENTED_HANDLER} handler as obj then - Result := obj.mapping_documentation (Current) + Result := obj.mapping_documentation (Current, a_request_methods) else create Result.make (Current) end diff --git a/library/server/wsf/router/support/starts_with/context_helpers/wsf_starts_with_context_routed_service.e b/library/server/wsf/router/support/starts_with/context_helpers/wsf_starts_with_context_routed_service.e index cb9abe30..19480c41 100644 --- a/library/server/wsf/router/support/starts_with/context_helpers/wsf_starts_with_context_routed_service.e +++ b/library/server/wsf/router/support/starts_with/context_helpers/wsf_starts_with_context_routed_service.e @@ -17,7 +17,7 @@ feature -- Mapping helper: starts_with map_starts_with_request_methods (a_uri, h, Void) end - map_starts_with_request_methods (a_uri: READABLE_STRING_8; h: WSF_STARTS_WITH_CONTEXT_HANDLER [C]; rqst_methods: detachable WSF_ROUTER_METHODS) + map_starts_with_request_methods (a_uri: READABLE_STRING_8; h: WSF_STARTS_WITH_CONTEXT_HANDLER [C]; rqst_methods: detachable WSF_REQUEST_METHODS) do router.map_with_request_methods (create {WSF_STARTS_WITH_CONTEXT_MAPPING [C]}.make (a_uri, h), rqst_methods) end @@ -29,7 +29,7 @@ feature -- Mapping helper: starts_with agent map_starts_with_agent_with_request_methods (a_uri, proc, Void) end - map_starts_with_agent_with_request_methods (a_uri: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [start_path: READABLE_STRING_8; ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE]]; rqst_methods: detachable WSF_ROUTER_METHODS) + map_starts_with_agent_with_request_methods (a_uri: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [start_path: READABLE_STRING_8; ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE]]; rqst_methods: detachable WSF_REQUEST_METHODS) do map_starts_with_request_methods (a_uri, create {WSF_STARTS_WITH_AGENT_CONTEXT_HANDLER [C] }.make (proc), rqst_methods) end diff --git a/library/server/wsf/router/support/uri/context_helpers/wsf_uri_context_routed_service.e b/library/server/wsf/router/support/uri/context_helpers/wsf_uri_context_routed_service.e index aed575c7..e0e2220b 100644 --- a/library/server/wsf/router/support/uri/context_helpers/wsf_uri_context_routed_service.e +++ b/library/server/wsf/router/support/uri/context_helpers/wsf_uri_context_routed_service.e @@ -17,7 +17,7 @@ feature -- Mapping helper: uri map_uri_with_request_methods (a_uri, h, Void) end - map_uri_with_request_methods (a_uri: READABLE_STRING_8; h: WSF_URI_CONTEXT_HANDLER [C]; rqst_methods: detachable WSF_ROUTER_METHODS) + map_uri_with_request_methods (a_uri: READABLE_STRING_8; h: WSF_URI_CONTEXT_HANDLER [C]; rqst_methods: detachable WSF_REQUEST_METHODS) do router.map_with_request_methods (create {WSF_URI_CONTEXT_MAPPING [C]}.make (a_uri, h), rqst_methods) end @@ -29,7 +29,7 @@ feature -- Mapping helper: uri agent map_uri_agent_with_request_methods (a_uri, proc, Void) end - map_uri_agent_with_request_methods (a_uri: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE]]; rqst_methods: detachable WSF_ROUTER_METHODS) + map_uri_agent_with_request_methods (a_uri: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE]]; rqst_methods: detachable WSF_REQUEST_METHODS) do map_uri_with_request_methods (a_uri, create {WSF_URI_AGENT_CONTEXT_HANDLER [C] }.make (proc), rqst_methods) end diff --git a/library/server/wsf/router/support/uri/helpers/wsf_uri_routed_service.e b/library/server/wsf/router/support/uri/helpers/wsf_uri_routed_service.e index 05df16f9..cbb68d28 100644 --- a/library/server/wsf/router/support/uri/helpers/wsf_uri_routed_service.e +++ b/library/server/wsf/router/support/uri/helpers/wsf_uri_routed_service.e @@ -17,7 +17,7 @@ feature -- Mapping helper: uri map_uri_with_request_methods (a_uri, h, Void) end - map_uri_with_request_methods (a_uri: READABLE_STRING_8; h: WSF_URI_HANDLER; rqst_methods: detachable WSF_ROUTER_METHODS) + map_uri_with_request_methods (a_uri: READABLE_STRING_8; h: WSF_URI_HANDLER; rqst_methods: detachable WSF_REQUEST_METHODS) do router.map_with_request_methods (create {WSF_URI_MAPPING}.make (a_uri, h), rqst_methods) end @@ -29,7 +29,7 @@ feature -- Mapping helper: uri agent map_uri_agent_with_request_methods (a_uri, proc, Void) end - map_uri_agent_with_request_methods (a_uri: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [req: WSF_REQUEST; res: WSF_RESPONSE]]; rqst_methods: detachable WSF_ROUTER_METHODS) + map_uri_agent_with_request_methods (a_uri: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [req: WSF_REQUEST; res: WSF_RESPONSE]]; rqst_methods: detachable WSF_REQUEST_METHODS) do map_uri_with_request_methods (a_uri, create {WSF_URI_AGENT_HANDLER}.make (proc), rqst_methods) end diff --git a/library/server/wsf/router/support/uri_template/context_helpers/wsf_uri_template_context_routed_service.e b/library/server/wsf/router/support/uri_template/context_helpers/wsf_uri_template_context_routed_service.e index 46d75538..45f698b9 100644 --- a/library/server/wsf/router/support/uri_template/context_helpers/wsf_uri_template_context_routed_service.e +++ b/library/server/wsf/router/support/uri_template/context_helpers/wsf_uri_template_context_routed_service.e @@ -17,7 +17,7 @@ feature -- Mapping helper: uri map_uri_template_with_request_methods (a_tpl, h, Void) end - map_uri_template_with_request_methods (a_tpl: READABLE_STRING_8; h: WSF_URI_TEMPLATE_CONTEXT_HANDLER [C]; rqst_methods: detachable WSF_ROUTER_METHODS) + map_uri_template_with_request_methods (a_tpl: READABLE_STRING_8; h: WSF_URI_TEMPLATE_CONTEXT_HANDLER [C]; rqst_methods: detachable WSF_REQUEST_METHODS) do router.map_with_request_methods (create {WSF_URI_TEMPLATE_CONTEXT_MAPPING [C]}.make (a_tpl, h), rqst_methods) end @@ -29,7 +29,7 @@ feature -- Mapping helper: uri agent map_uri_template_agent_with_request_methods (a_tpl, proc, Void) end - map_uri_template_agent_with_request_methods (a_tpl: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE]]; rqst_methods: detachable WSF_ROUTER_METHODS) + map_uri_template_agent_with_request_methods (a_tpl: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE]]; rqst_methods: detachable WSF_REQUEST_METHODS) do map_uri_template_with_request_methods (a_tpl, create {WSF_URI_TEMPLATE_AGENT_CONTEXT_HANDLER [C] }.make (proc), rqst_methods) end diff --git a/library/server/wsf/router/support/uri_template/helpers/wsf_uri_template_routed_service.e b/library/server/wsf/router/support/uri_template/helpers/wsf_uri_template_routed_service.e index 3e5c7dfb..018f3c86 100644 --- a/library/server/wsf/router/support/uri_template/helpers/wsf_uri_template_routed_service.e +++ b/library/server/wsf/router/support/uri_template/helpers/wsf_uri_template_routed_service.e @@ -17,19 +17,19 @@ feature -- Mapping helper: uri map_uri_template_with_request_methods (a_tpl, h, Void) end - map_uri_template_with_request_methods (a_tpl: READABLE_STRING_8; h: WSF_URI_TEMPLATE_HANDLER; rqst_methods: detachable WSF_ROUTER_METHODS) + map_uri_template_with_request_methods (a_tpl: READABLE_STRING_8; h: WSF_URI_TEMPLATE_HANDLER; rqst_methods: detachable WSF_REQUEST_METHODS) do router.map_with_request_methods (create {WSF_URI_TEMPLATE_MAPPING}.make (a_tpl, h), rqst_methods) end -feature -- Mapping helper: uri agent +feature -- Mapping helper: uri agent map_uri_template_agent (a_tpl: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [req: WSF_REQUEST; res: WSF_RESPONSE]]) do map_uri_template_agent_with_request_methods (a_tpl, proc, Void) end - map_uri_template_agent_with_request_methods (a_tpl: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [req: WSF_REQUEST; res: WSF_RESPONSE]]; rqst_methods: detachable WSF_ROUTER_METHODS) + map_uri_template_agent_with_request_methods (a_tpl: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [req: WSF_REQUEST; res: WSF_RESPONSE]]; rqst_methods: detachable WSF_REQUEST_METHODS) do map_uri_template_with_request_methods (a_tpl, create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (proc), rqst_methods) end diff --git a/library/server/wsf/router/wsf_handler.e b/library/server/wsf/router/wsf_handler.e index b4a5a87d..1470a08d 100644 --- a/library/server/wsf/router/wsf_handler.e +++ b/library/server/wsf/router/wsf_handler.e @@ -17,7 +17,7 @@ feature -- Status report feature {WSF_ROUTER} -- Mapping - on_mapped (a_mapping: WSF_ROUTER_MAPPING; a_rqst_methods: detachable WSF_ROUTER_METHODS) + on_mapped (a_mapping: WSF_ROUTER_MAPPING; a_rqst_methods: detachable WSF_REQUEST_METHODS) -- Callback called when a router map a route to Current handler do end diff --git a/library/server/wsf/router/wsf_request_methods.e b/library/server/wsf/router/wsf_request_methods.e new file mode 100644 index 00000000..a2af35c3 --- /dev/null +++ b/library/server/wsf/router/wsf_request_methods.e @@ -0,0 +1,483 @@ +note + description: "[ + Object that is use in relation with WSF_ROUTER, to precise which request methods is accepted. + For convenience, `make_from_iterable' is available, so that you can use <<"GET", "POST">> for instance + but remember manifest string are evil ... + Since in HTTP you can use your own custom request method, this is not possible to catch any typo + ( for instance if you write "POST" instead of "P0ST" this is hard to find the error, + but in one case it uses upper "o" and in the other case this is zero "0" + ) + + The recommanded way to use is for instance + create {WSF_REQUEST_METHODS}.make_get_post + create methods; methods.enable_get; methods.enable_post + + This sounds heavy, but this is much safer. + + ( note: in addition internally this first checks using reference comparison + and then compare string value, so it brings optimization for accepted request methods. + ) + ]" + date: "$Date$" + revision: "$Revision$" + +class + WSF_REQUEST_METHODS + +inherit + ITERABLE [READABLE_STRING_8] + redefine + default_create + end + + HTTP_REQUEST_METHODS + redefine + default_create + end + +create + default_create, + make, + make_from_iterable, + make_from_string + +convert + to_array: {ARRAY [READABLE_STRING_8]}, + make_from_iterable ({ITERABLE [READABLE_STRING_8], ITERABLE [STRING_8], ARRAY [READABLE_STRING_8], ARRAY [STRING_8]}), + make_from_string ({READABLE_STRING_8, STRING_8}) + +feature {NONE} -- Initialization + + default_create + do + Precursor + make (1) + end + + make (n: INTEGER) + do + create methods.make (n) + end + + make_from_iterable (v: ITERABLE [READABLE_STRING_8]) + do + make (1) + add_methods (v) + end + + make_from_string (v: READABLE_STRING_8) + do + make_from_iterable (v.split (',')) + end + +feature -- Status report + + is_locked: BOOLEAN + -- Is Current locked? And then can not be modified? + + is_empty: BOOLEAN + do + Result := methods.count = 0 + end + + has (a_method: READABLE_STRING_8): BOOLEAN + -- Has `a_method' enabled? + require + a_method_is_uppercase: a_method.same_string (a_method.as_upper) + do + -- First look for string object itself, + -- in case `a_method' comes from one of the HTTP_REQUEST_METHODS constants + Result := across methods as c some c.item = a_method end + if not Result then + -- If not found, look for the same string value + Result := across methods as c some c.item.same_string_general (a_method) end + end + end + + has_some_of (a_methods: WSF_REQUEST_METHODS): BOOLEAN + -- Has any methods from `a_methods' enabled? + do + Result := across a_methods as c some has (c.item) end + end + + has_all_of (a_methods: WSF_REQUEST_METHODS): BOOLEAN + -- Has all methods from `a_methods' enabled? + do + Result := across a_methods as c all has (c.item) end + end + + has_method_get: BOOLEAN + -- Has method GET enabled? + do + Result := has (method_get) + end + + has_method_post: BOOLEAN + -- Has method POST enabled? + do + Result := has (method_post) + end + + has_method_put: BOOLEAN + -- Has method PUT enabled? + do + Result := has (method_put) + end + + has_method_delete: BOOLEAN + -- Has method DELETE enabled? + do + Result := has (method_delete) + end + + has_method_options: BOOLEAN + -- Has method OPTIONS enabled? + do + Result := has (method_options) + end + + has_method_head: BOOLEAN + -- Has method HEAD enabled? + do + Result := has (method_head) + end + + has_method_trace: BOOLEAN + -- Has method TRACE enabled? + do + Result := has (method_trace) + end + + has_method_connect: BOOLEAN + -- Has method CONNECT enabled? + do + Result := has (method_connect) + end + + has_method_patch: BOOLEAN + -- Has method PATCH enabled? + do + Result := has (method_patch) + end + +feature -- Access + + new_cursor: INDEXABLE_ITERATION_CURSOR [READABLE_STRING_8] + -- Fresh cursor associated with current structure + do + Result := methods.new_cursor + end + +feature -- Status change + + lock + -- Lock current and prevent any change in methods + -- Once it is locked, it is impossible to unlock. + do + is_locked := True + end + +feature -- Basic operations + + plus alias "+" (a_other: WSF_REQUEST_METHODS): WSF_REQUEST_METHODS + -- Merge Current and a_other into Result + require + a_other_not_void: a_other /= Void + do + create Result.make_from_iterable (Current) + Result.add_methods (a_other) + end + +feature -- Element change + + enable_get + require + is_not_locked: not is_locked + get_disabled: not has (method_get) + do + methods.extend (method_get) + ensure + get_enabled: has (method_get) + end + + disable_get + require + is_not_locked: not is_locked + get_enabled: has (method_get) + do + prune_method (method_get) + ensure + get_disabled: not has (method_get) + end + + enable_post + require + is_not_locked: not is_locked + post_disabled: not has (method_post) + do + methods.extend (method_post) + ensure + post_enabled: has (method_post) + end + + disable_post + require + is_not_locked: not is_locked + post_enabled: has (method_post) + do + prune_method (method_post) + ensure + post_disabled: not has (method_post) + end + + enable_put + require + is_not_locked: not is_locked + put_disabled: not has (method_put) + do + methods.extend (method_put) + ensure + put_enabled: has (method_put) + end + + disable_put + require + is_not_locked: not is_locked + put_enabled: has (method_put) + do + prune_method (method_put) + ensure + put_disabled: not has (method_put) + end + + enable_delete + require + is_not_locked: not is_locked + delete_disabled: not has (method_delete) + do + methods.extend (method_delete) + ensure + delete_enabled: has (method_delete) + end + + disable_delete + require + is_not_locked: not is_locked + delete_enabled: has (method_delete) + do + prune_method (method_delete) + ensure + delete_disabled: not has (method_delete) + end + + enable_options + require + is_not_locked: not is_locked + options_disabled: not has (method_options) + do + methods.extend (method_options) + ensure + options_enabled: has (method_options) + end + + disable_options + require + is_not_locked: not is_locked + options_enabled: has (method_options) + do + prune_method (method_options) + ensure + options_disabled: not has (method_options) + end + + enable_head + require + is_not_locked: not is_locked + head_disabled: not has (method_head) + do + methods.extend (method_head) + ensure + head_enabled: has (method_head) + end + + disable_head + require + is_not_locked: not is_locked + head_enabled: has (method_head) + do + prune_method (method_head) + ensure + head_disabled: not has (method_head) + end + + enable_trace + require + is_not_locked: not is_locked + trace_disabled: not has (method_trace) + do + methods.extend (method_trace) + ensure + trace_enabled: has (method_trace) + end + + disable_trace + require + is_not_locked: not is_locked + trace_enabled: has (method_trace) + do + prune_method (method_trace) + ensure + trace_disabled: not has (method_trace) + end + + enable_connect + require + is_not_locked: not is_locked + connect_disabled: not has (method_connect) + do + methods.extend (method_connect) + ensure + connect_enabled: has (method_connect) + end + + disable_connect + require + is_not_locked: not is_locked + connect_enabled: has (method_connect) + do + prune_method (method_connect) + ensure + connect_disabled: not has (method_connect) + end + + enable_patch + require + is_not_locked: not is_locked + patch_disabled: not has (method_patch) + do + methods.extend (method_patch) + ensure + patch_enabled: has (method_patch) + end + + disable_patch + require + is_not_locked: not is_locked + patch_enabled: has (method_patch) + do + prune_method (method_patch) + ensure + patch_disabled: not has (method_patch) + end + + enable_custom (m: READABLE_STRING_8) + require + is_not_locked: not is_locked + not_blank: not across m as mc some mc.item.is_space end + custom_disabled: not has (m.as_upper) + do + methods.extend (m.as_upper) + ensure + custom_enabled: has (m.as_upper) + end + + disable_custom (m: READABLE_STRING_8) + require + is_not_locked: not is_locked + not_blank: not across m as mc some mc.item.is_space end + custom_enabled: has (m.as_upper) + do + prune_method (m.as_upper) + ensure + custom_disabled: not has (m.as_upper) + end + +feature -- Access + + methods: ARRAYED_LIST [READABLE_STRING_8] + + to_array: ARRAY [READABLE_STRING_8] + do + Result := methods.to_array + end + +feature {WSF_REQUEST_METHODS} -- Implementation + + add_methods (lst: ITERABLE [READABLE_STRING_8]) + -- Enable methods from `lst' + do + if not is_locked then + across + lst as c + loop + add_method_using_constant (c.item) + end + end + end + +feature {NONE} -- Implementation + + add_method_using_constant (v: READABLE_STRING_8) + -- Add method `v' using method_* constant + do + if v.is_case_insensitive_equal (method_get) then + enable_get + elseif v.is_case_insensitive_equal (method_post) then + enable_post + elseif v.is_case_insensitive_equal (method_put) then + enable_put + elseif v.is_case_insensitive_equal (method_delete) then + enable_delete + elseif v.is_case_insensitive_equal (method_head) then + enable_head + elseif v.is_case_insensitive_equal (method_options) then + enable_options + elseif v.is_case_insensitive_equal (method_trace) then + enable_trace + elseif v.is_case_insensitive_equal (method_connect) then + enable_connect + elseif v.is_case_insensitive_equal (method_patch) then + enable_patch + else + enable_custom (v) + end + ensure + method_set: has (v.as_upper) + end + + prune_method (v: READABLE_STRING_8) + require + is_upper_case: v.same_string (v.as_upper) + local + m: READABLE_STRING_8 + do + if not is_locked then + from + methods.start + until + methods.after + loop + m := methods.item + if m = v or else m.same_string (v) then + methods.remove + else + methods.forth + end + end + end + end + +invariant + methods_are_uppercase: across methods as c all c.item.same_string (c.item.as_upper) end + +;note + copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, 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/router/wsf_routed_service.e b/library/server/wsf/router/wsf_routed_service.e index e6445e60..a91d45a9 100644 --- a/library/server/wsf/router/wsf_routed_service.e +++ b/library/server/wsf/router/wsf_routed_service.e @@ -51,6 +51,7 @@ feature -- Execution msg: WSF_DEFAULT_ROUTER_RESPONSE do create msg.make_with_router (req, router) + msg.set_documentation_included (True) res.send (msg) end diff --git a/library/server/wsf/router/wsf_router.e b/library/server/wsf/router/wsf_router.e index dd7a5940..f25c8578 100644 --- a/library/server/wsf/router/wsf_router.e +++ b/library/server/wsf/router/wsf_router.e @@ -56,7 +56,7 @@ feature -- Mapping map_with_request_methods (a_mapping, Void) end - map_with_request_methods (a_mapping: WSF_ROUTER_MAPPING; rqst_methods: detachable WSF_ROUTER_METHODS) + map_with_request_methods (a_mapping: WSF_ROUTER_MAPPING; rqst_methods: detachable WSF_REQUEST_METHODS) -- Map `a_mapping' for request methods `rqst_methods' do debug ("router") @@ -81,7 +81,7 @@ feature -- Mapping handler handle_with_request_methods (a_resource, f, Void) end - handle_with_request_methods (a_resource: READABLE_STRING_8; f: WSF_ROUTER_MAPPING_FACTORY; rqst_methods: detachable WSF_ROUTER_METHODS) + handle_with_request_methods (a_resource: READABLE_STRING_8; f: WSF_ROUTER_MAPPING_FACTORY; rqst_methods: detachable WSF_REQUEST_METHODS) -- Map the mapping created by factory `f' for resource `a_resource' -- and only for request methods `rqst_methods' do @@ -150,7 +150,7 @@ feature {NONE} -- Dispatch implementation feature -- Status report - has_item_associated_with_resource (a_resource: READABLE_STRING_8; rqst_methods: detachable WSF_ROUTER_METHODS): BOOLEAN + has_item_associated_with_resource (a_resource: READABLE_STRING_8; rqst_methods: detachable WSF_REQUEST_METHODS): BOOLEAN local m: WSF_ROUTER_MAPPING ok: BOOLEAN @@ -177,7 +177,7 @@ feature -- Status report end end - item_associated_with_resource (a_resource: READABLE_STRING_8; rqst_methods: detachable WSF_ROUTER_METHODS): detachable WSF_ROUTER_ITEM + item_associated_with_resource (a_resource: READABLE_STRING_8; rqst_methods: detachable WSF_REQUEST_METHODS): detachable WSF_ROUTER_ITEM local m: WSF_ROUTER_MAPPING ok: BOOLEAN @@ -206,11 +206,11 @@ feature -- Status report end end - allowed_methods_for_request (req: WSF_REQUEST): WSF_ROUTER_METHODS + allowed_methods_for_request (req: WSF_REQUEST): WSF_REQUEST_METHODS -- Allowed methods for `req' local m: WSF_ROUTER_MAPPING - l_rqsmethods: detachable WSF_ROUTER_METHODS + l_rqsmethods: detachable WSF_REQUEST_METHODS do create Result @@ -286,49 +286,49 @@ feature -- Traversing feature -- Request methods helper - methods_head: WSF_ROUTER_METHODS + methods_head: WSF_REQUEST_METHODS once ("THREAD") create Result Result.enable_head Result.lock end - methods_options: WSF_ROUTER_METHODS + methods_options: WSF_REQUEST_METHODS once ("THREAD") create Result Result.enable_options Result.lock end - methods_get: WSF_ROUTER_METHODS + methods_get: WSF_REQUEST_METHODS once ("THREAD") create Result Result.enable_get Result.lock end - methods_post: WSF_ROUTER_METHODS + methods_post: WSF_REQUEST_METHODS once ("THREAD") create Result Result.enable_post Result.lock end - methods_put: WSF_ROUTER_METHODS + methods_put: WSF_REQUEST_METHODS once ("THREAD") create Result Result.enable_put Result.lock end - methods_delete: WSF_ROUTER_METHODS + methods_delete: WSF_REQUEST_METHODS once ("THREAD") create Result Result.enable_delete Result.lock end - methods_head_get_post: WSF_ROUTER_METHODS + methods_head_get_post: WSF_REQUEST_METHODS once ("THREAD") create Result.make (3) Result.enable_head @@ -337,7 +337,7 @@ feature -- Request methods helper Result.lock end - methods_get_put_delete: WSF_ROUTER_METHODS + methods_get_put_delete: WSF_REQUEST_METHODS once ("THREAD") create Result.make (3) Result.enable_get @@ -346,7 +346,7 @@ feature -- Request methods helper Result.lock end - methods_head_get: WSF_ROUTER_METHODS + methods_head_get: WSF_REQUEST_METHODS once ("THREAD") create Result.make (2) Result.enable_head @@ -354,7 +354,7 @@ feature -- Request methods helper Result.lock end - methods_get_post: WSF_ROUTER_METHODS + methods_get_post: WSF_REQUEST_METHODS once ("THREAD") create Result.make (2) Result.enable_get @@ -362,7 +362,7 @@ feature -- Request methods helper Result.lock end - methods_put_post: WSF_ROUTER_METHODS + methods_put_post: WSF_REQUEST_METHODS once ("THREAD") create Result.make (2) Result.enable_put @@ -401,7 +401,7 @@ feature {NONE} -- Access: Implementation end end - is_matching_request_methods (a_request_method: READABLE_STRING_8; a_rqst_methods: detachable WSF_ROUTER_METHODS): BOOLEAN + is_matching_request_methods (a_request_method: READABLE_STRING_8; a_rqst_methods: detachable WSF_REQUEST_METHODS): BOOLEAN -- `a_request_method' is matching `a_rqst_methods' contents do if a_rqst_methods /= Void and then not a_rqst_methods.is_empty then diff --git a/library/server/wsf/router/wsf_router_agent_iterator.e b/library/server/wsf/router/wsf_router_agent_iterator.e new file mode 100644 index 00000000..c44d4ebc --- /dev/null +++ b/library/server/wsf/router/wsf_router_agent_iterator.e @@ -0,0 +1,67 @@ +note + description: "Summary description for {WSF_ROUTER_AGENT_ITERATOR}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + WSF_ROUTER_AGENT_ITERATOR + +inherit + WSF_ROUTER_ITERATOR + redefine + default_create, + process_router, + process_item, + process_mapping, + process_handler + end + +feature {NONE} -- Initialization + + default_create + do + Precursor + create on_router_actions.make + create on_item_actions.make + create on_mapping_actions.make + create on_handler_actions.make + end + +feature -- Actions + + on_router_actions: ACTION_SEQUENCE [TUPLE [WSF_ROUTER]] + + on_item_actions: ACTION_SEQUENCE [TUPLE [WSF_ROUTER_ITEM]] + + on_mapping_actions: ACTION_SEQUENCE [TUPLE [WSF_ROUTER_MAPPING]] + + on_handler_actions: ACTION_SEQUENCE [TUPLE [WSF_HANDLER]] + +feature -- Visitor + + process_router (r: WSF_ROUTER) + do + on_router_actions.call ([r]) + Precursor (r) + end + + process_item (i: WSF_ROUTER_ITEM) + do + on_item_actions.call ([i]) + Precursor (i) + end + + process_mapping (m: WSF_ROUTER_MAPPING) + do + on_mapping_actions.call ([m]) + Precursor (m) + end + + process_handler (h: WSF_HANDLER) + do + on_handler_actions.call ([h]) + Precursor (h) + end + +end diff --git a/library/server/wsf/router/wsf_router_item.e b/library/server/wsf/router/wsf_router_item.e index 7978fbd1..1800e7b9 100644 --- a/library/server/wsf/router/wsf_router_item.e +++ b/library/server/wsf/router/wsf_router_item.e @@ -36,7 +36,7 @@ feature -- Access mapping: WSF_ROUTER_MAPPING - request_methods: detachable WSF_ROUTER_METHODS + request_methods: detachable WSF_REQUEST_METHODS feature -- Status report diff --git a/library/server/wsf/router/wsf_router_iterator.e b/library/server/wsf/router/wsf_router_iterator.e new file mode 100644 index 00000000..cbf3e9a9 --- /dev/null +++ b/library/server/wsf/router/wsf_router_iterator.e @@ -0,0 +1,41 @@ +note + description: "Summary description for {WSF_ROUTER_ITERATOR}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + WSF_ROUTER_ITERATOR + +inherit + WSF_ROUTER_VISITOR + +feature -- Visitor + + process_router (r: WSF_ROUTER) + do + across + r as c + loop + process_item (c.item) + end + end + + process_item (i: WSF_ROUTER_ITEM) + do + process_mapping (i.mapping) + end + + process_mapping (m: WSF_ROUTER_MAPPING) + do + process_handler (m.handler) + end + + process_handler (h: WSF_HANDLER) + do + if attached {WSF_ROUTING_HANDLER} h as r then + process_router (r.router) + end + end + +end diff --git a/library/server/wsf/router/wsf_router_methods.e b/library/server/wsf/router/wsf_router_methods.e index d0577775..d89dd1ca 100644 --- a/library/server/wsf/router/wsf_router_methods.e +++ b/library/server/wsf/router/wsf_router_methods.e @@ -24,15 +24,13 @@ note class WSF_ROUTER_METHODS -inherit - ITERABLE [READABLE_STRING_8] - redefine - default_create - end +obsolete + "Use WSF_REQUEST_METHODS" - HTTP_REQUEST_METHODS +inherit + WSF_REQUEST_METHODS redefine - default_create + plus end create @@ -46,364 +44,21 @@ convert make_from_iterable ({ITERABLE [READABLE_STRING_8], ITERABLE [STRING_8], ARRAY [READABLE_STRING_8], ARRAY [STRING_8]}), make_from_string ({READABLE_STRING_8, STRING_8}) -feature {NONE} -- Initialization - - default_create - do - Precursor - make (1) - end - - make (n: INTEGER) - do - create methods.make (n) - end - - make_from_iterable (v: ITERABLE [READABLE_STRING_8]) - do - make (1) - add_methods (v) - end - - make_from_string (v: READABLE_STRING_8) - do - make_from_iterable (v.split (',')) - end - -feature -- Status report - - is_locked: BOOLEAN - -- Is Current locked? And then can not be modified? - - is_empty: BOOLEAN - do - Result := methods.count = 0 - end - - has (a_method: READABLE_STRING_8): BOOLEAN - -- Has `a_method' enabled? - require - a_method_is_uppercase: a_method.same_string (a_method.as_upper) - do - -- First look for string object itself, - -- in case `a_method' comes from one of the HTTP_REQUEST_METHODS constants - Result := across methods as c some c.item = a_method end - if not Result then - -- If not found, look for the same string value - Result := across methods as c some c.item.same_string_general (a_method) end - end - end - -feature -- Access - - new_cursor: INDEXABLE_ITERATION_CURSOR [READABLE_STRING_8] - -- Fresh cursor associated with current structure - do - Result := methods.new_cursor - end - -feature -- Status change - - lock - -- Lock current and prevent any change in methods - -- Once it is locked, it is impossible to unlock. - do - is_locked := True - end - feature -- Basic operations - add alias "+" (a_other: WSF_ROUTER_METHODS): WSF_ROUTER_METHODS + add (a_other: like plus): like plus + obsolete "Use `plus' or `alias +'" + do + Result := plus (a_other) + end + + plus alias "+" (a_other: WSF_ROUTER_METHODS): WSF_ROUTER_METHODS -- Merge Current and a_other into Result - require - a_other_not_void: a_other /= Void do create Result.make_from_iterable (Current) Result.add_methods (a_other) end -feature -- Element change - - enable_get - require - is_not_locked: not is_locked - get_disabled: not has (method_get) - do - methods.extend (method_get) - ensure - get_enabled: has (method_get) - end - - disable_get - require - is_not_locked: not is_locked - get_enabled: has (method_get) - do - prune_method (method_get) - ensure - get_disabled: not has (method_get) - end - - enable_post - require - is_not_locked: not is_locked - post_disabled: not has (method_post) - do - methods.extend (method_post) - ensure - post_enabled: has (method_post) - end - - disable_post - require - is_not_locked: not is_locked - post_enabled: has (method_post) - do - prune_method (method_post) - ensure - post_disabled: not has (method_post) - end - - enable_put - require - is_not_locked: not is_locked - put_disabled: not has (method_put) - do - methods.extend (method_put) - ensure - put_enabled: has (method_put) - end - - disable_put - require - is_not_locked: not is_locked - put_enabled: has (method_put) - do - prune_method (method_put) - ensure - put_disabled: not has (method_put) - end - - enable_delete - require - is_not_locked: not is_locked - delete_disabled: not has (method_delete) - do - methods.extend (method_delete) - ensure - delete_enabled: has (method_delete) - end - - disable_delete - require - is_not_locked: not is_locked - delete_enabled: has (method_delete) - do - prune_method (method_delete) - ensure - delete_disabled: not has (method_delete) - end - - enable_options - require - is_not_locked: not is_locked - options_disabled: not has (method_options) - do - methods.extend (method_options) - ensure - options_enabled: has (method_options) - end - - disable_options - require - is_not_locked: not is_locked - options_enabled: has (method_options) - do - prune_method (method_options) - ensure - options_disabled: not has (method_options) - end - - enable_head - require - is_not_locked: not is_locked - head_disabled: not has (method_head) - do - methods.extend (method_head) - ensure - head_enabled: has (method_head) - end - - disable_head - require - is_not_locked: not is_locked - head_enabled: has (method_head) - do - prune_method (method_head) - ensure - head_disabled: not has (method_head) - end - - enable_trace - require - is_not_locked: not is_locked - trace_disabled: not has (method_trace) - do - methods.extend (method_trace) - ensure - trace_enabled: has (method_trace) - end - - disable_trace - require - is_not_locked: not is_locked - trace_enabled: has (method_trace) - do - prune_method (method_trace) - ensure - trace_disabled: not has (method_trace) - end - - enable_connect - require - is_not_locked: not is_locked - connect_disabled: not has (method_connect) - do - methods.extend (method_connect) - ensure - connect_enabled: has (method_connect) - end - - disable_connect - require - is_not_locked: not is_locked - connect_enabled: has (method_connect) - do - prune_method (method_connect) - ensure - connect_disabled: not has (method_connect) - end - - enable_patch - require - is_not_locked: not is_locked - patch_disabled: not has (method_patch) - do - methods.extend (method_patch) - ensure - patch_enabled: has (method_patch) - end - - disable_patch - require - is_not_locked: not is_locked - patch_enabled: has (method_patch) - do - prune_method (method_patch) - ensure - patch_disabled: not has (method_patch) - end - - enable_custom (m: READABLE_STRING_8) - require - is_not_locked: not is_locked - not_blank: not across m as mc some mc.item.is_space end - custom_disabled: not has (m.as_upper) - do - methods.extend (m.as_upper) - ensure - custom_enabled: has (m.as_upper) - end - - disable_custom (m: READABLE_STRING_8) - require - is_not_locked: not is_locked - not_blank: not across m as mc some mc.item.is_space end - custom_enabled: has (m.as_upper) - do - prune_method (m.as_upper) - ensure - custom_disabled: not has (m.as_upper) - end - -feature -- Access - - methods: ARRAYED_LIST [READABLE_STRING_8] - - to_array: ARRAY [READABLE_STRING_8] - do - Result := methods.to_array - end - -feature {WSF_ROUTER_METHODS} -- Implementation - - add_methods (lst: ITERABLE [READABLE_STRING_8]) - -- Enable methods from `lst' - do - if not is_locked then - across - lst as c - loop - add_method_using_constant (c.item) - end - end - end - -feature {NONE} -- Implementation - - add_method_using_constant (v: READABLE_STRING_8) - -- Add method `v' using method_* constant - do - if v.is_case_insensitive_equal (method_get) then - enable_get - elseif v.is_case_insensitive_equal (method_post) then - enable_post - elseif v.is_case_insensitive_equal (method_put) then - enable_put - elseif v.is_case_insensitive_equal (method_delete) then - enable_delete - elseif v.is_case_insensitive_equal (method_head) then - enable_head - elseif v.is_case_insensitive_equal (method_options) then - enable_options - elseif v.is_case_insensitive_equal (method_trace) then - enable_trace - elseif v.is_case_insensitive_equal (method_connect) then - enable_connect - elseif v.is_case_insensitive_equal (method_patch) then - enable_patch - else - enable_custom (v) - end - ensure - method_set: has (v.as_upper) - end - - prune_method (v: READABLE_STRING_8) - require - is_upper_case: v.same_string (v.as_upper) - local - m: READABLE_STRING_8 - do - if not is_locked then - from - methods.start - until - methods.after - loop - m := methods.item - if m = v or else m.same_string (v) then - methods.remove - else - methods.forth - end - end - end - end - -invariant - methods_are_uppercase: across methods as c all c.item.same_string (c.item.as_upper) end - ;note copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" diff --git a/library/server/wsf/router/wsf_router_visitor.e b/library/server/wsf/router/wsf_router_visitor.e new file mode 100644 index 00000000..051987cb --- /dev/null +++ b/library/server/wsf/router/wsf_router_visitor.e @@ -0,0 +1,28 @@ +note + description: "Summary description for {WSF_ROUTER_VISITOR}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + WSF_ROUTER_VISITOR + +feature -- Visitor + + process_router (r: WSF_ROUTER) + deferred + end + + process_item (i: WSF_ROUTER_ITEM) + deferred + end + + process_mapping (m: WSF_ROUTER_MAPPING) + deferred + end + + process_handler (h: WSF_HANDLER) + deferred + end + +end diff --git a/library/server/wsf/src/response/wsf_default_response.e b/library/server/wsf/src/response/wsf_default_response.e index f1ae9d32..664b7aca 100644 --- a/library/server/wsf/src/response/wsf_default_response.e +++ b/library/server/wsf/src/response/wsf_default_response.e @@ -36,18 +36,26 @@ feature {WSF_RESPONSE} -- Output local msg: WSF_RESPONSE_MESSAGE req: like request - not_found: WSF_NOT_FOUND_RESPONSE - trace: WSF_TRACE_RESPONSE do req := request if req.is_request_method ({HTTP_REQUEST_METHODS}.method_trace) then - create trace.make (req) - msg := trace + msg := trace_message (req) else - create not_found.make (req) - msg := not_found + msg := not_found_message (req) end res.send (msg) end +feature {NONE} -- Implementation + + trace_message (req: WSF_REQUEST): WSF_TRACE_RESPONSE + do + create Result.make (req) + end + + not_found_message (req: WSF_REQUEST): WSF_NOT_FOUND_RESPONSE + do + create Result.make (req) + end + end diff --git a/library/server/wsf/src/response/wsf_default_router_response.e b/library/server/wsf/src/response/wsf_default_router_response.e index 22d4a329..7c91fe29 100644 --- a/library/server/wsf/src/response/wsf_default_router_response.e +++ b/library/server/wsf/src/response/wsf_default_router_response.e @@ -9,7 +9,8 @@ class inherit WSF_DEFAULT_RESPONSE redefine - send_to + send_to, + not_found_message end create @@ -30,6 +31,18 @@ feature -- Access router: WSF_ROUTER -- Associated router. +feature -- Settings + + documentation_included: BOOLEAN + -- Include self-documentation from `router' in the response? + +feature -- Change + + set_documentation_included (b: BOOLEAN) + do + documentation_included := b + end + feature {WSF_RESPONSE} -- Output send_to (res: WSF_RESPONSE) @@ -40,24 +53,100 @@ feature {WSF_RESPONSE} -- Output local msg: WSF_RESPONSE_MESSAGE req: like request - not_found: WSF_NOT_FOUND_RESPONSE - not_allowed: WSF_METHOD_NOT_ALLOWED_RESPONSE - trace: WSF_TRACE_RESPONSE do req := request if req.is_request_method ({HTTP_REQUEST_METHODS}.method_trace) then - create trace.make (req) - msg := trace - elseif attached router.allowed_methods_for_request (req) as mtds and then not mtds.is_empty then - create not_allowed.make (req) - not_allowed.set_suggested_methods (mtds) + msg := trace_message (req) + elseif attached method_not_allowed_message (req) as not_allowed then msg := not_allowed else - create not_found.make (req) - - msg := not_found + msg := not_found_message (req) end res.send (msg) end +feature {NONE} -- Implementation + + method_not_allowed_message (req: WSF_REQUEST): detachable WSF_METHOD_NOT_ALLOWED_RESPONSE + local + vis: WSF_ROUTER_AGENT_ITERATOR + do + if attached router.allowed_methods_for_request (req) as l_allowed_mtds and then not l_allowed_mtds.is_empty then + create Result.make (req) + Result.set_suggested_methods (l_allowed_mtds) + + if documentation_included then + create vis + vis.on_item_actions.extend (agent (i: WSF_ROUTER_ITEM; r: WSF_METHOD_NOT_ALLOWED_RESPONSE) + local + l_is_hidden: BOOLEAN + s: STRING_32 + do + -- Keep only mapping for the request's method + if + not attached i.request_methods as l_methods or else + l_methods.has (request.request_method) + then + if attached {WSF_SELF_DOCUMENTED_ROUTER_MAPPING} i.mapping as l_doc_mapping then + l_is_hidden := l_doc_mapping.documentation (i.request_methods).is_hidden + end + if not l_is_hidden then + create s.make_from_string (i.mapping.associated_resource) + if attached i.request_methods as mtds then + s.append (" [ ") + across + mtds as mtds_c + loop + s.append (mtds_c.item) + s.append_character (' ') + end + s.append ("]") + else + s.append (" [*]") + end + r.add_suggested_text (s, Void) + end + end + end (?, Result)) + vis.process_router (router) + end + end + end + + not_found_message (req: WSF_REQUEST): WSF_NOT_FOUND_RESPONSE + local + vis: WSF_ROUTER_AGENT_ITERATOR + do + Result := Precursor (req) + if documentation_included then + create vis + vis.on_item_actions.extend (agent (i: WSF_ROUTER_ITEM; r: WSF_NOT_FOUND_RESPONSE) + local + l_is_hidden: BOOLEAN + s: STRING_32 + do + if attached {WSF_SELF_DOCUMENTED_ROUTER_MAPPING} i.mapping as l_doc_mapping then + l_is_hidden := l_doc_mapping.documentation (i.request_methods).is_hidden + end + if not l_is_hidden then + create s.make_from_string (i.mapping.associated_resource) + if attached i.request_methods as mtds then + s.append (" [ ") + across + mtds as mtds_c + loop + s.append (mtds_c.item) + s.append_character (' ') + end + s.append ("]") + else + s.append (" [*]") + end + r.add_suggested_text (s, Void) + end + end (?, Result)) + vis.process_router (router) + end + end + end diff --git a/library/server/wsf/src/response/wsf_method_not_allowed_response.e b/library/server/wsf/src/response/wsf_method_not_allowed_response.e index 83a32384..5e647c63 100644 --- a/library/server/wsf/src/response/wsf_method_not_allowed_response.e +++ b/library/server/wsf/src/response/wsf_method_not_allowed_response.e @@ -23,6 +23,7 @@ feature {NONE} -- Initialization request := req create header.make create suggested_methods + create suggested_items.make (0) end feature -- Header @@ -33,10 +34,18 @@ feature -- Header request: WSF_REQUEST -- Associated request. - suggested_methods: WSF_ROUTER_METHODS + suggested_methods: WSF_REQUEST_METHODS -- Optional suggestions -- First is the default. + suggested_items: ARRAYED_LIST [TUPLE [location: detachable READABLE_STRING_8; text: detachable READABLE_STRING_GENERAL; description: detachable READABLE_STRING_GENERAL]] + -- Optional suggestions + -- First is the default. + + body: detachable READABLE_STRING_8 + -- Optional body + -- Displayed as extra content + feature -- Element change set_suggested_methods (m: like suggested_methods) @@ -45,11 +54,31 @@ feature -- Element change suggested_methods := m end + add_suggested_location (a_loc: READABLE_STRING_8; a_title: detachable READABLE_STRING_GENERAL; a_description: detachable READABLE_STRING_GENERAL) + -- Add `a_loc' to `suggested_items' + do + suggested_items.force ([a_loc, a_title, a_description]) + end + + add_suggested_text (a_text: READABLE_STRING_GENERAL; a_description: detachable READABLE_STRING_GENERAL) + -- Add `a_text' to `suggested_items' + do + suggested_items.force ([Void, a_text, a_description]) + end + + set_body (b: like body) + -- Set `body' to `b' + do + body := b + end + feature {WSF_RESPONSE} -- Output send_to (res: WSF_RESPONSE) local s: STRING + l_text: detachable READABLE_STRING_GENERAL + l_loc: detachable READABLE_STRING_8 h: like header do h := header @@ -62,7 +91,7 @@ feature {WSF_RESPONSE} -- Output s := "Not allowed" if request.is_content_type_accepted ({HTTP_MIME_TYPES}.text_html) then - s := "" + s := "" s.append ("") s.append (html_encoder.encoded_string (request.request_uri)) s.append ("Error 405 (Method Not Allowed)!!") @@ -103,6 +132,48 @@ feature {WSF_RESPONSE} -- Output end s.append ("%N") end + + if attached suggested_items as lst and then not lst.is_empty then + s.append ("<div id=%"suggestions%"><strong>Perhaps your are looking for:</strong><ul>") + from + lst.start + until + lst.after + loop + l_text := lst.item.text + l_loc := lst.item.location + if l_loc /= Void then + if l_text = Void then + l_text := l_loc + end + s.append ("<li>") + s.append ("<a href=%"" + l_loc + "%">" + html_encoder.encoded_string (l_text.to_string_32) + "</a>") + elseif l_text /= Void then + + s.append ("<li>") + s.append (html_encoder.encoded_string (l_text.to_string_32)) + s.append ("</li>%N") + end + if (l_loc /= Void or l_text /= Void) then + if attached lst.item.description as l_desc then + s.append ("<br/> - ") + s.append (html_encoder.encoded_string (l_desc.to_string_32)) + s.append ("%N") + end + s.append ("</li>%N") + end + + lst.forth + end + s.append ("</ul></div>%N") + end + if attached body as b then + s.append ("<div>") + s.append (b) + s.append ("</div>%N") + end + + s.append ("<div id=%"footer%"></div>") s.append ("</body>%N") s.append ("</html>%N") @@ -122,6 +193,43 @@ feature {WSF_RESPONSE} -- Output end s.append ("%N") end + if attached suggested_items as lst and then not lst.is_empty then + s.append ("%NPerhaps your are looking for:%N") + from + lst.start + until + lst.after + loop + l_text := lst.item.text + l_loc := lst.item.location + if l_loc /= Void then + s.append (" - ") + if l_text = Void then + s.append (l_loc) + else + s.append (" : ") + s.append (l_text.to_string_8) + end + elseif l_text /= Void then + s.append (" - ") + s.append (l_text.to_string_8) + end + if (l_loc /= Void or l_text /= Void) then + s.append ("%N") + if attached lst.item.description as l_desc then + s.append (" ") + s.append (l_desc.to_string_8) + s.append ("%N") + end + end + lst.forth + end + end + if attached body as b then + s.append ("%N") + s.append (b) + s.append ("%N") + end h.put_content_type_text_plain end diff --git a/library/server/wsf/src/response/wsf_not_found_response.e b/library/server/wsf/src/response/wsf_not_found_response.e index 0f6ecc5c..c5e72aaf 100644 --- a/library/server/wsf/src/response/wsf_not_found_response.e +++ b/library/server/wsf/src/response/wsf_not_found_response.e @@ -22,7 +22,7 @@ feature {NONE} -- Initialization do request := req create header.make - create suggested_locations.make (0) + create suggested_items.make (0) end feature -- Header @@ -33,16 +33,32 @@ feature -- Header request: WSF_REQUEST -- Associated request. - suggested_locations: ARRAYED_LIST [TUPLE [location: READABLE_STRING_8; title: detachable READABLE_STRING_GENERAL]] + suggested_items: ARRAYED_LIST [TUPLE [location: detachable READABLE_STRING_8; text: detachable READABLE_STRING_GENERAL; description: detachable READABLE_STRING_GENERAL]] -- Optional suggestions -- First is the default. + body: detachable READABLE_STRING_8 + -- Optional body + -- Displayed as extra content + feature -- Element change - add_suggested_location (a_loc: READABLE_STRING_8; a_title: detachable READABLE_STRING_GENERAL) - -- Add `a_loc' to `suggested_locations' + add_suggested_location (a_loc: READABLE_STRING_8; a_title: detachable READABLE_STRING_GENERAL; a_description: detachable READABLE_STRING_GENERAL) + -- Add `a_loc' to `suggested_items' do - suggested_locations.force ([a_loc, a_title]) + suggested_items.force ([a_loc, a_title, a_description]) + end + + add_suggested_text (a_text: READABLE_STRING_GENERAL; a_description: detachable READABLE_STRING_GENERAL) + -- Add `a_text' to `suggested_items' + do + suggested_items.force ([Void, a_text, a_description]) + end + + set_body (b: like body) + -- Set `body' to `b' + do + body := b end feature {WSF_RESPONSE} -- Output @@ -50,7 +66,8 @@ feature {WSF_RESPONSE} -- Output send_to (res: WSF_RESPONSE) local s: STRING - l_title: detachable READABLE_STRING_GENERAL + l_text: detachable READABLE_STRING_GENERAL + l_loc: detachable READABLE_STRING_8 h: like header do h := header @@ -85,25 +102,46 @@ feature {WSF_RESPONSE} -- Output s.append ("</div>") s.append ("Error 404 (Not Found)</div>") s.append ("<div id=%"message%">Error 404 (Not Found): <code>" + html_encoder.encoded_string (request.request_uri) + "</code></div>") - if attached suggested_locations as lst and then not lst.is_empty then + if attached suggested_items as lst and then not lst.is_empty then s.append ("<div id=%"suggestions%"><strong>Perhaps your are looking for:</strong><ul>") from lst.start until lst.after loop - s.append ("<li>") - l_title := lst.item.title - if l_title = Void then - l_title := lst.item.location + l_text := lst.item.text + l_loc := lst.item.location + if l_loc /= Void then + if l_text = Void then + l_text := l_loc + end + s.append ("<li>") + s.append ("<a href=%"" + l_loc + "%">" + html_encoder.encoded_string (l_text.to_string_32) + "</a>") + elseif l_text /= Void then + + s.append ("<li>") + s.append (html_encoder.encoded_string (l_text.to_string_32)) + s.append ("</li>%N") + end + if (l_loc /= Void or l_text /= Void) then + if attached lst.item.description as l_desc then + s.append ("<br/> - ") + s.append (html_encoder.encoded_string (l_desc.to_string_32)) + s.append ("%N") + end + s.append ("</li>%N") end - s.append ("<a href=%"" + lst.item.location + "%">" + html_encoder.encoded_string (l_title.to_string_32) + "</a>") - s.append ("</li>%N") lst.forth end s.append ("</ul></div>%N") end + if attached body as b then + s.append ("<div>") + s.append (b) + s.append ("</div>%N") + end + s.append ("<div id=%"footer%"></div>") s.append ("</body>%N") s.append ("</html>%N") @@ -113,24 +151,43 @@ feature {WSF_RESPONSE} -- Output s := "Error 404 (Not Found): " s.append (request.request_uri) s.append_character ('%N') - if attached suggested_locations as lst and then not lst.is_empty then + if attached suggested_items as lst and then not lst.is_empty then s.append ("%NPerhaps your are looking for:%N") from lst.start until lst.after loop - s.append (" - ") - l_title := lst.item.title - if l_title = Void then - l_title := lst.item.location + l_text := lst.item.text + l_loc := lst.item.location + if l_loc /= Void then + s.append (" - ") + if l_text = Void then + s.append (l_loc) + else + s.append (" : ") + s.append (l_text.to_string_8) + end + elseif l_text /= Void then + s.append (" - ") + s.append (l_text.to_string_8) + end + if (l_loc /= Void or l_text /= Void) then + s.append ("%N") + if attached lst.item.description as l_desc then + s.append (" ") + s.append (l_desc.to_string_8) + s.append ("%N") + end end - s.append (lst.item.location) - s.append ("%N") - lst.forth end end + if attached body as b then + s.append ("%N") + s.append (b) + s.append ("%N") + end h.put_content_type_text_plain end