From a6fbed22fe3250b880fd364402dad2acf400d73c Mon Sep 17 00:00:00 2001 From: Colin Adams Date: Sat, 16 Mar 2013 14:08:33 +0000 Subject: [PATCH 01/19] Implemented 503 and 414 responses in WSF_ROUTED_SERVICE --- .../network/protocol/http/src/http_header.e | 2 + .../server/wsf/router/wsf_routed_service.e | 121 +++++++++++++++++- 2 files changed, 121 insertions(+), 2 deletions(-) diff --git a/library/network/protocol/http/src/http_header.e b/library/network/protocol/http/src/http_header.e index a9cee805..e1bb19a7 100644 --- a/library/network/protocol/http/src/http_header.e +++ b/library/network/protocol/http/src/http_header.e @@ -819,6 +819,8 @@ feature {NONE} -- Implementation h.append_character ('%N') end +feature -- Access + date_to_rfc1123_http_date_format (dt: DATE_TIME): STRING_8 -- String representation of `dt' using the RFC 1123 local diff --git a/library/server/wsf/router/wsf_routed_service.e b/library/server/wsf/router/wsf_routed_service.e index 5f2c3499..9e94e806 100644 --- a/library/server/wsf/router/wsf_routed_service.e +++ b/library/server/wsf/router/wsf_routed_service.e @@ -35,13 +35,17 @@ feature -- Initialization feature -- Execution execute (req: WSF_REQUEST; res: WSF_RESPONSE) - -- Dispatch the request + -- If the service is available, and request URI is not too long, dispatch the request -- and if handler is not found, execute the default procedure `execute_default'. require req_attached: req /= Void res_attached: res /= Void do - if attached router.dispatch_and_return_handler (req, res) as p then + if unavailable then + handle_unavailable (res) + elseif maximum_uri_length > 0 and then req.request_uri.count.to_natural_32 > maximum_uri_length then + handle_request_uri_too_long (res) + elseif attached router.dispatch_and_return_handler (req, res) as p then -- executed else execute_default (req, res) @@ -67,6 +71,119 @@ feature -- Access -- Router used to dispatch the request according to the WSF_REQUEST object -- and associated request methods +feature -- Measurement + + maximum_uri_length: NATURAL + -- Maximum length in characters (or zero for no limit) permitted + -- for {WSF_REQUEST}.request_uri + +feature -- Status report + + unavailable: BOOLEAN + -- Is service currently unavailable? + + unavailablity_message: detachable READABLE_STRING_8 + -- Message to be included as text of response body for {HTTP_STATUS_CODE}.service_unavailable + + unavailability_duration: NATURAL + -- Delta seconds for service unavailability (0 if not known) + + unavailable_until: detachable DATE_TIME + -- Time at which service becomes availabile again (if known) + +feature -- Status setting + + set_available + -- Set `unavailable' to `False'. + do + unavailable := False + unavailablity_message := Void + unavailable_until := Void + ensure + available: unavailable = False + unavailablity_message_detached: unavailablity_message = Void + unavailable_until_detached: unavailable_until = Void + end + + set_unavailable (a_message: READABLE_STRING_8; a_duration: NATURAL; a_until: detachable DATE_TIME) + -- Set `unavailable' to `True'. + require + a_message_attached: a_message /= Void + a_duration_xor_a_until: a_duration > 0 implies a_until = Void + do + unavailable := True + unavailablity_message := a_message + unavailability_duration := a_duration + ensure + unavailable: unavailable = True + unavailablity_message_aliased: unavailablity_message = a_message + unavailability_duration_set: unavailability_duration = a_duration + unavailable_until_aliased: unavailable_until = a_until + end + + set_maximum_uri_length (a_len: NATURAL) + -- Set `maximum_uri_length' to `a_len'. + -- Can pass zero to mean no restrictions. + do + maximum_uri_length := a_len + ensure + maximum_uri_length_set: maximum_uri_length = a_len + end + +feature {NONE} -- Implementation + + handle_unavailable (res: WSF_RESPONSE) + -- Write "Service unavailable" response to `res'. + require + unavailable: unavailable = True + res_attached: res /= Void + local + h: HTTP_HEADER + do + create h.make + h.put_content_type_text_plain + check attached {READABLE_STRING_8} unavailablity_message as m then + -- invariant + h.put_content_length (m.count) + h.put_current_date + res.set_status_code ({HTTP_STATUS_CODE}.service_unavailable) + if unavailability_duration > 0 then + h.put_header_key_value ({HTTP_HEADER_NAMES}.header_retry_after, unavailability_duration.out) + elseif unavailable_until /= Void then + check attached {DATE_TIME} unavailable_until as u then + -- $£#$%#! compiler! + h.put_header_key_value ({HTTP_HEADER_NAMES}.header_retry_after, + h.date_to_rfc1123_http_date_format (u)) + end + end + res.put_header_text (h.string) + res.put_string (m) + end + end + + handle_request_uri_too_long (res: WSF_RESPONSE) + -- Write "Request URI too long" response to `res'. + require + res_attached: res /= Void + local + h: HTTP_HEADER + m: READABLE_STRING_8 + do + create h.make + h.put_content_type_text_plain + h.put_current_date + m := "Maximum permitted length for request URI is " + maximum_uri_length.out + " characters" + h.put_content_length (m.count) + res.set_status_code ({HTTP_STATUS_CODE}.request_uri_too_long) + res.put_header_text (h.string) + res.put_string (m) + end + +invariant + + unavailblity_message_attached: unavailable implies unavailablity_message /= Void + unavailablity_duration_xor_unavailable_until: unavailability_duration > 0 implies unavailable_until = Void + ;note copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" From d01f47f1ee7930df20634677c3abb1cc556ba4e5 Mon Sep 17 00:00:00 2001 From: Colin Adams Date: Sat, 16 Mar 2013 15:12:58 +0000 Subject: [PATCH 02/19] Implemented 414 and 503 responses on WSF_ROUTED_SERVICE --- .../src/resource/order_handler.e | 28 +++++-------------- examples/restbucksCRUD/src/restbucks_server.e | 14 +--------- .../server/wsf/router/wsf_routed_service.e | 3 ++ 3 files changed, 11 insertions(+), 34 deletions(-) diff --git a/examples/restbucksCRUD/src/resource/order_handler.e b/examples/restbucksCRUD/src/resource/order_handler.e index c11883d1..0bddd924 100644 --- a/examples/restbucksCRUD/src/resource/order_handler.e +++ b/examples/restbucksCRUD/src/resource/order_handler.e @@ -4,22 +4,10 @@ note date: "$Date$" revision: "$Revision$" -class - ORDER_HANDLER +class ORDER_HANDLER inherit - WSF_URI_HANDLER - rename - execute as uri_execute, - new_mapping as new_uri_mapping - end WSF_URI_TEMPLATE_HANDLER - rename - execute as uri_template_execute, - new_mapping as new_uri_template_mapping - select - new_uri_template_mapping - end WSF_RESOURCE_HANDLER_HELPER redefine @@ -28,22 +16,20 @@ inherit do_put, do_delete end + SHARED_DATABASE_API + SHARED_EJSON + REFACTORING_HELPER + SHARED_ORDER_VALIDATION WSF_SELF_DOCUMENTED_HANDLER -feature -- execute +feature -- Execute - uri_execute (req: WSF_REQUEST; res: WSF_RESPONSE) - -- Execute request handler - do - execute_methods (req, res) - end - - uri_template_execute (req: WSF_REQUEST; res: WSF_RESPONSE) + execute (req: WSF_REQUEST; res: WSF_RESPONSE) -- Execute request handler do execute_methods (req, res) diff --git a/examples/restbucksCRUD/src/restbucks_server.e b/examples/restbucksCRUD/src/restbucks_server.e index 3fbd8add..56409c57 100644 --- a/examples/restbucksCRUD/src/restbucks_server.e +++ b/examples/restbucksCRUD/src/restbucks_server.e @@ -10,9 +10,6 @@ inherit ANY WSF_URI_TEMPLATE_ROUTED_SERVICE - redefine - execute_default - end WSF_HANDLER_HELPER @@ -42,18 +39,9 @@ feature {NONE} -- Initialization router.handle_with_request_methods ("/api/doc", doc, router.methods_GET) end -feature -- Execution - - execute_default (req: WSF_REQUEST; res: WSF_RESPONSE) - -- 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. - do - Precursor (req, res) - end note - copyright: "2011-2012, Javier Velilla and others" + copyright: "2011-2013, Javier Velilla and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/library/server/wsf/router/wsf_routed_service.e b/library/server/wsf/router/wsf_routed_service.e index 9e94e806..a437eadb 100644 --- a/library/server/wsf/router/wsf_routed_service.e +++ b/library/server/wsf/router/wsf_routed_service.e @@ -41,6 +41,8 @@ feature -- Execution req_attached: req /= Void res_attached: res /= Void do + --| When we reach here, the request has already passed check for 400 (Bad request), + --| which is implemented in WSF_REQUEST.make_from_wgi (when it calls `analyze'). if unavailable then handle_unavailable (res) elseif maximum_uri_length > 0 and then req.request_uri.count.to_natural_32 > maximum_uri_length then @@ -60,6 +62,7 @@ feature -- Execution local msg: WSF_DEFAULT_ROUTER_RESPONSE do + --| TODO: update this to distinguish between 501, 403 and 404 results. create msg.make_with_router (req, router) msg.set_documentation_included (True) res.send (msg) From cda8e75f4ce90d3133af93525f7bd5ba1a378199 Mon Sep 17 00:00:00 2001 From: Colin Adams Date: Sun, 17 Mar 2013 08:09:04 +0000 Subject: [PATCH 03/19] implemented OPTIONS * except for Allow header --- .gitignore | 1 + .../server/wsf/router/wsf_routed_service.e | 80 ++++++++++++++++++- 2 files changed, 78 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index b9eb7ce4..c4d48214 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ EIFGENs tests/temp/ .svn/ *.swp +*~ diff --git a/library/server/wsf/router/wsf_routed_service.e b/library/server/wsf/router/wsf_routed_service.e index a437eadb..e9a2db31 100644 --- a/library/server/wsf/router/wsf_routed_service.e +++ b/library/server/wsf/router/wsf_routed_service.e @@ -4,8 +4,11 @@ note date: "$Date$" revision: "$Revision$" -deferred class - WSF_ROUTED_SERVICE +deferred class WSF_ROUTED_SERVICE + +inherit + + WSF_SYSTEM_OPTIONS_ACCESS_POLICY feature -- Initialization @@ -47,6 +50,9 @@ feature -- Execution handle_unavailable (res) elseif maximum_uri_length > 0 and then req.request_uri.count.to_natural_32 > maximum_uri_length then handle_request_uri_too_long (res) + elseif req.request_method.as_upper.same_string ({HTTP_REQUEST_METHODS}.method_options) and then + req.request_uri.same_string ("*") then + handle_server_options (req, res) elseif attached router.dispatch_and_return_handler (req, res) as p then -- executed else @@ -165,7 +171,7 @@ feature {NONE} -- Implementation end handle_request_uri_too_long (res: WSF_RESPONSE) - -- Write "Request URI too long" response to `res'. + -- Write "Request URI too long" response into `res'. require res_attached: res /= Void local @@ -182,6 +188,74 @@ feature {NONE} -- Implementation res.put_string (m) end + handle_server_options (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Write response to OPTIONS * into `res'. + require + req_attached: req /= Void + res_attached: res /= Void + method_is_options: req.request_method.as_upper.same_string ({HTTP_REQUEST_METHODS}.method_options) + server_options_requested: req.request_uri.same_string ("*") + do + --| TODO - should first check if forbidden. + --| (N.B. authentication requires an absoluteURI (RFC3617 page 3), and so cannot be used for OPTIONS *. + --| Otherwise construct an Allow response automatically from the router. + if is_system_options_forbidden then + handle_system_options_forbidden (req, res) + else + handle_system_options (req, res) + end + end + + handle_system_options_forbidden (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Write a 403 Forbidden or a 404 Not found response into `res'. + require + req_attached: req /= Void + res_attached: res /= Void + method_is_options: req.request_method.as_upper.same_string ({HTTP_REQUEST_METHODS}.method_options) + server_options_requested: req.request_uri.same_string ("*") + local + m: detachable READABLE_STRING_8 + h: HTTP_HEADER + do + m := system_options_forbidden_text (req) + if attached {READABLE_STRING_8} m as l_msg then + create h.make + h.put_content_type_text_plain + h.put_current_date + h.put_content_length (l_msg.count) + res.set_status_code ({HTTP_STATUS_CODE}.forbidden) + res.put_header_text (h.string) + res.put_string (l_msg) + else + create h.make + h.put_content_type_text_plain + h.put_current_date + h.put_content_length (0) + res.set_status_code ({HTTP_STATUS_CODE}.not_found) + res.put_header_text (h.string) + end + end + + handle_system_options (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Write response to OPTIONS * into `res'. + -- This may be redefined by the user, but normally this will not be necessary. + require + req_attached: req /= Void + res_attached: res /= Void + method_is_options: req.request_method.as_upper.same_string ({HTTP_REQUEST_METHODS}.method_options) + server_options_requested: req.request_uri.same_string ("*") + local + h: HTTP_HEADER + do + create h.make + h.put_content_type_text_plain + h.put_current_date + --| TODO - add Allow header for all permitted methods. + h.put_content_length (0) + res.set_status_code ({HTTP_STATUS_CODE}.ok) + res.put_header_text (h.string) + end + invariant unavailblity_message_attached: unavailable implies unavailablity_message /= Void From 767328287a290a5a9bcc8ac0184308e92fe4599a Mon Sep 17 00:00:00 2001 From: Colin Adams Date: Sun, 17 Mar 2013 09:49:36 +0000 Subject: [PATCH 04/19] added contracts and polished forbidden for OPTIONS * --- .../server/wsf/router/wsf_routed_service.e | 54 +++++++++++++++---- 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/library/server/wsf/router/wsf_routed_service.e b/library/server/wsf/router/wsf_routed_service.e index e9a2db31..32c6a085 100644 --- a/library/server/wsf/router/wsf_routed_service.e +++ b/library/server/wsf/router/wsf_routed_service.e @@ -13,14 +13,16 @@ inherit feature -- Initialization initialize_router - -- Initialize router + -- Initialize router. do create_router setup_router + ensure + router_created: router /= Void end create_router - -- Create `router' + -- Create `router'. --| could be redefine to initialize with proper capacity do create router.make (10) @@ -29,7 +31,7 @@ feature -- Initialization end setup_router - -- Setup `router' + -- Setup `router'. require router_created: router /= Void deferred @@ -58,6 +60,9 @@ feature -- Execution else execute_default (req, res) end + ensure + response_status_is_set: res.status_is_set + header_sent: res.header_committed and res.message_committed end execute_default (req: WSF_REQUEST; res: WSF_RESPONSE) @@ -68,10 +73,13 @@ feature -- Execution local msg: WSF_DEFAULT_ROUTER_RESPONSE do - --| TODO: update this to distinguish between 501, 403 and 404 results. + --| TODO (colin-adams): update this to distinguish between 501, 403 and 404 results. create msg.make_with_router (req, router) msg.set_documentation_included (True) res.send (msg) + ensure + response_status_is_set: res.status_is_set + message_sent: res.header_committed and res.message_committed end feature -- Access @@ -98,7 +106,7 @@ feature -- Status report -- Delta seconds for service unavailability (0 if not known) unavailable_until: detachable DATE_TIME - -- Time at which service becomes availabile again (if known) + -- Time at which service becomes available again (if known) feature -- Status setting @@ -168,6 +176,11 @@ feature {NONE} -- Implementation res.put_header_text (h.string) res.put_string (m) end + ensure + response_status_is_set: res.status_is_set + status_is_service_unavailable: res.status_code = {HTTP_STATUS_CODE}.service_unavailable + body_sent: res.message_committed and then res.transfered_content_length > 0 + body_content_was_unavailablity_message: True -- doesn't seem to be any way to check end handle_request_uri_too_long (res: WSF_RESPONSE) @@ -186,9 +199,13 @@ feature {NONE} -- Implementation res.set_status_code ({HTTP_STATUS_CODE}.request_uri_too_long) res.put_header_text (h.string) res.put_string (m) + ensure + response_status_is_set: res.status_is_set + status_is_request_uri_too_long: res.status_code = {HTTP_STATUS_CODE}.request_uri_too_long + body_sent: res.message_committed and then res.transfered_content_length > 0 end - handle_server_options (req: WSF_REQUEST; res: WSF_RESPONSE) + frozen handle_server_options (req: WSF_REQUEST; res: WSF_RESPONSE) -- Write response to OPTIONS * into `res'. require req_attached: req /= Void @@ -199,14 +216,19 @@ feature {NONE} -- Implementation --| TODO - should first check if forbidden. --| (N.B. authentication requires an absoluteURI (RFC3617 page 3), and so cannot be used for OPTIONS *. --| Otherwise construct an Allow response automatically from the router. - if is_system_options_forbidden then + if is_system_options_forbidden (req) then handle_system_options_forbidden (req, res) else handle_system_options (req, res) end + ensure + response_status_is_set: res.status_is_set + valid_response_code: res.status_code = {HTTP_STATUS_CODE}.forbidden or + res.status_code = {HTTP_STATUS_CODE}.not_found or res.status_code = {HTTP_STATUS_CODE}.ok + header_sent: res.header_committed and res.message_committed end - handle_system_options_forbidden (req: WSF_REQUEST; res: WSF_RESPONSE) + frozen handle_system_options_forbidden (req: WSF_REQUEST; res: WSF_RESPONSE) -- Write a 403 Forbidden or a 404 Not found response into `res'. require req_attached: req /= Void @@ -234,6 +256,12 @@ feature {NONE} -- Implementation res.set_status_code ({HTTP_STATUS_CODE}.not_found) res.put_header_text (h.string) end + ensure + response_status_is_set: res.status_is_set + valid_response_code: res.status_code = {HTTP_STATUS_CODE}.forbidden or + res.status_code = {HTTP_STATUS_CODE}.not_found + header_sent: res.header_committed + message_sent: res.message_committed end handle_system_options (req: WSF_REQUEST; res: WSF_RESPONSE) @@ -254,12 +282,18 @@ feature {NONE} -- Implementation h.put_content_length (0) res.set_status_code ({HTTP_STATUS_CODE}.ok) res.put_header_text (h.string) + ensure + response_status_is_set: res.status_is_set + response_code_ok: res.status_code = {HTTP_STATUS_CODE}.ok + header_sent: res.header_committed and res.message_committed + empty_body: res.transfered_content_length = 0 end invariant - unavailblity_message_attached: unavailable implies unavailablity_message /= Void - unavailablity_duration_xor_unavailable_until: unavailability_duration > 0 implies unavailable_until = Void + unavailability_message_attached: unavailable implies attached {READABLE_STRING_8} unavailablity_message as m and then + m.count > 0 + unavailability_duration_xor_unavailable_until: unavailability_duration > 0 implies unavailable_until = Void ;note copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" From 4c946f58292f8c05f7458d53cb2d11d99431e03a Mon Sep 17 00:00:00 2001 From: Colin Adams Date: Sun, 17 Mar 2013 09:57:00 +0000 Subject: [PATCH 05/19] minor polishing --- library/server/wsf/router/wsf_routed_service.e | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/server/wsf/router/wsf_routed_service.e b/library/server/wsf/router/wsf_routed_service.e index 32c6a085..b83c9dc7 100644 --- a/library/server/wsf/router/wsf_routed_service.e +++ b/library/server/wsf/router/wsf_routed_service.e @@ -213,7 +213,7 @@ feature {NONE} -- Implementation method_is_options: req.request_method.as_upper.same_string ({HTTP_REQUEST_METHODS}.method_options) server_options_requested: req.request_uri.same_string ("*") do - --| TODO - should first check if forbidden. + --| First check if forbidden. --| (N.B. authentication requires an absoluteURI (RFC3617 page 3), and so cannot be used for OPTIONS *. --| Otherwise construct an Allow response automatically from the router. if is_system_options_forbidden (req) then From dd63042ec46aa3f625038520cbe604dc1530d770 Mon Sep 17 00:00:00 2001 From: Colin Adams Date: Sun, 17 Mar 2013 10:38:00 +0000 Subject: [PATCH 06/19] Added missing class --- .../router/wsf_system_options_access_policy.e | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 library/server/wsf/router/wsf_system_options_access_policy.e diff --git a/library/server/wsf/router/wsf_system_options_access_policy.e b/library/server/wsf/router/wsf_system_options_access_policy.e new file mode 100644 index 00000000..6915af52 --- /dev/null +++ b/library/server/wsf/router/wsf_system_options_access_policy.e @@ -0,0 +1,40 @@ +note + + description: "[ + Policy to decide if OPTIONS * is honoured. + Servers that wish to forbid OPTIONS * requests + can redefine `is_system_options_forbidden'. + + Response 403 Forbidden is meant to be accompanied + by an entity body describing the reason for the refusal. + Since authentication cannot be used for OPTIONS *, there + are limited grounds for selective refusal (the IP address might + be used though), so we provide a convenient default for + `system_options_forbidden_text'. + ]" + + date: "$Date$" + revision: "$Revision$" + +class WSF_SYSTEM_OPTIONS_ACCESS_POLICY + +feature -- Access + + is_system_options_forbidden (req: WSF_REQUEST): BOOLEAN + -- Should we return 403 Forbidden in response to OPTIONS * requests? + require + req_attached: req /= Void + do + -- by default, unconditionally no. + end + + system_options_forbidden_text (req: WSF_REQUEST): detachable READABLE_STRING_8 + -- Content of 403 Forbidden response; + -- Returning `Void' means instead respond with 403 Not found + require + req_attached: req /= Void + do + Result := "OPTIONS * is not permitted" + end + +end From d56f4e6c7dc6dc904193cfe1cf98978e11bae6aa Mon Sep 17 00:00:00 2001 From: Colin Adams Date: Mon, 18 Mar 2013 14:21:53 +0000 Subject: [PATCH 07/19] prior to refactoring for WSF_ROUTED_SKELETON_SERVICE --- examples/restbucksCRUD/src/restbucks_server.e | 5 ++ .../server/wsf/router/wsf_no_proxy_policy.e | 35 ++++++++ .../server/wsf/router/wsf_proxy_use_policy.e | 76 +++++++++++++++++ .../server/wsf/router/wsf_routed_service.e | 61 +++++++++----- library/server/wsf/router/wsf_router.e | 20 +++++ .../wsf_method_not_allowed_response.e | 82 +++++++++++++++++-- 6 files changed, 251 insertions(+), 28 deletions(-) create mode 100644 library/server/wsf/router/wsf_no_proxy_policy.e create mode 100644 library/server/wsf/router/wsf_proxy_use_policy.e diff --git a/examples/restbucksCRUD/src/restbucks_server.e b/examples/restbucksCRUD/src/restbucks_server.e index 56409c57..d9ebead2 100644 --- a/examples/restbucksCRUD/src/restbucks_server.e +++ b/examples/restbucksCRUD/src/restbucks_server.e @@ -10,11 +10,16 @@ inherit ANY WSF_URI_TEMPLATE_ROUTED_SERVICE + undefine + requires_proxy + end WSF_HANDLER_HELPER WSF_DEFAULT_SERVICE + WSF_NO_PROXY_POLICY + create make diff --git a/library/server/wsf/router/wsf_no_proxy_policy.e b/library/server/wsf/router/wsf_no_proxy_policy.e new file mode 100644 index 00000000..3397b30f --- /dev/null +++ b/library/server/wsf/router/wsf_no_proxy_policy.e @@ -0,0 +1,35 @@ +note + + description: "[ + Policy that no client ever need use a proxy. + + Users of this policy cannot safely use chunked transfer-encoding, or any + HTTP/1.1-specific features. So best used only for examples. + ]" + + date: "$Date$" + revision: "$Revision$" + +class WSF_NO_PROXY_POLICY + +inherit + + WSF_PROXY_USE_POLICY + redefine + requires_proxy + end + +feature -- Access + + requires_proxy (req: WSF_REQUEST): BOOLEAN + -- Does `req' require use of `proxy_server'? + do + end + + proxy_server (req: WSF_REQUEST): READABLE_STRING_8 -- We can't currently use UT_URI + -- Absolute URI of proxy server which `req' must use + do + Result := "" -- doesn't meet the postcondition, but the precondition is never true. + end + +end diff --git a/library/server/wsf/router/wsf_proxy_use_policy.e b/library/server/wsf/router/wsf_proxy_use_policy.e new file mode 100644 index 00000000..7c1c046c --- /dev/null +++ b/library/server/wsf/router/wsf_proxy_use_policy.e @@ -0,0 +1,76 @@ +note + + description: "[ + Policies that determine if the client must use a proxy server + to access the resource. + + The default policy implemented here is to require + use of the proxy for HTTP/1.0 clients (only) for all requests. + ]" + + date: "$Date$" + revision: "$Revision$" + +deferred class WSF_PROXY_USE_POLICY + +feature -- Access + + requires_proxy (req: WSF_REQUEST): BOOLEAN + -- Does `req' require use of `proxy_server'? + require + req_attached: req /= Void + do + if is_http_1_0 (req) then + Result := True + end + end + + proxy_server (req: WSF_REQUEST): READABLE_STRING_8 -- We can't currently use UT_URI + -- Absolute URI of proxy server which `req' must use + --| An alternative design would allow a relative URI (relative to the server host), + --| which will only work if both the server and the proxy use the default ports. + require + req_attached: req /= Void + proxy_required: requires_proxy (req) + deferred + ensure + absolute_uri: True -- We can't currently use UT_URI to check this. Have we got another class? + end + + is_http_1_0 (req: WSF_REQUEST): BOOLEAN + -- Does `req' come from an HTTP/1.0 client? + require + req_attached: req /= Void + local + l_protocol: READABLE_STRING_8 + l_tokens: LIST [READABLE_STRING_8] + l_protocol_name, l_protocol_version, l_major, l_minor: STRING_8 + do + l_protocol := req.server_protocol + l_tokens := l_protocol.split ('/') + if l_tokens.count = 2 then + l_protocol_name := l_tokens [1].as_string_8 + l_protocol_name.left_adjust + l_protocol_name.right_adjust + if l_protocol_name.is_case_insensitive_equal ({HTTP_CONSTANTS}.http_version_1_0.substring (1, 4)) then + l_protocol_version := l_tokens [2].as_string_8 + l_protocol_version.left_adjust + l_protocol_version.right_adjust + l_tokens := l_protocol_version.split ('.') + if l_tokens.count = 2 then + l_major := l_tokens [1].as_string_8 + l_major.left_adjust + l_major.right_adjust + l_minor := l_tokens [2].as_string_8 + l_minor.left_adjust + l_minor.right_adjust + if l_major.is_integer and then l_major.to_integer = 1 and then + l_minor.is_integer and then l_minor.to_integer = 0 then + Result := True + end + end + end + end + end + +end diff --git a/library/server/wsf/router/wsf_routed_service.e b/library/server/wsf/router/wsf_routed_service.e index b83c9dc7..bca46767 100644 --- a/library/server/wsf/router/wsf_routed_service.e +++ b/library/server/wsf/router/wsf_routed_service.e @@ -10,6 +10,8 @@ inherit WSF_SYSTEM_OPTIONS_ACCESS_POLICY + WSF_PROXY_USE_POLICY + feature -- Initialization initialize_router @@ -50,9 +52,11 @@ feature -- Execution --| which is implemented in WSF_REQUEST.make_from_wgi (when it calls `analyze'). if unavailable then handle_unavailable (res) + elseif requires_proxy (req) then + handle_use_proxy (req, res) elseif maximum_uri_length > 0 and then req.request_uri.count.to_natural_32 > maximum_uri_length then handle_request_uri_too_long (res) - elseif req.request_method.as_upper.same_string ({HTTP_REQUEST_METHODS}.method_options) and then + elseif req.is_request_method ({HTTP_REQUEST_METHODS}.method_options) and then req.request_uri.same_string ("*") then handle_server_options (req, res) elseif attached router.dispatch_and_return_handler (req, res) as p then @@ -73,7 +77,6 @@ feature -- Execution local msg: WSF_DEFAULT_ROUTER_RESPONSE do - --| TODO (colin-adams): update this to distinguish between 501, 403 and 404 results. create msg.make_with_router (req, router) msg.set_documentation_included (True) res.send (msg) @@ -152,26 +155,23 @@ feature {NONE} -- Implementation handle_unavailable (res: WSF_RESPONSE) -- Write "Service unavailable" response to `res'. require - unavailable: unavailable = True + unavailable: unavailable res_attached: res /= Void local h: HTTP_HEADER do create h.make h.put_content_type_text_plain - check attached {READABLE_STRING_8} unavailablity_message as m then - -- invariant + check attached unavailablity_message as m then + -- invariant plus precondition h.put_content_length (m.count) h.put_current_date res.set_status_code ({HTTP_STATUS_CODE}.service_unavailable) if unavailability_duration > 0 then h.put_header_key_value ({HTTP_HEADER_NAMES}.header_retry_after, unavailability_duration.out) - elseif unavailable_until /= Void then - check attached {DATE_TIME} unavailable_until as u then - -- $£#$%#! compiler! + elseif attached unavailable_until as u then h.put_header_key_value ({HTTP_HEADER_NAMES}.header_retry_after, h.date_to_rfc1123_http_date_format (u)) - end end res.put_header_text (h.string) res.put_string (m) @@ -210,7 +210,7 @@ feature {NONE} -- Implementation require req_attached: req /= Void res_attached: res /= Void - method_is_options: req.request_method.as_upper.same_string ({HTTP_REQUEST_METHODS}.method_options) + method_is_options: req.is_request_method ({HTTP_REQUEST_METHODS}.method_options) server_options_requested: req.request_uri.same_string ("*") do --| First check if forbidden. @@ -233,7 +233,7 @@ feature {NONE} -- Implementation require req_attached: req /= Void res_attached: res /= Void - method_is_options: req.request_method.as_upper.same_string ({HTTP_REQUEST_METHODS}.method_options) + method_is_options: req.is_request_method ({HTTP_REQUEST_METHODS}.method_options) server_options_requested: req.request_uri.same_string ("*") local m: detachable READABLE_STRING_8 @@ -270,18 +270,18 @@ feature {NONE} -- Implementation require req_attached: req /= Void res_attached: res /= Void - method_is_options: req.request_method.as_upper.same_string ({HTTP_REQUEST_METHODS}.method_options) + method_is_options: req.is_request_method ({HTTP_REQUEST_METHODS}.method_options) server_options_requested: req.request_uri.same_string ("*") local h: HTTP_HEADER do - create h.make - h.put_content_type_text_plain - h.put_current_date - --| TODO - add Allow header for all permitted methods. - h.put_content_length (0) - res.set_status_code ({HTTP_STATUS_CODE}.ok) - res.put_header_text (h.string) + create h.make + h.put_content_type_text_plain + h.put_current_date + h.put_allow (router.all_allowed_methods) + h.put_content_length (0) + res.set_status_code ({HTTP_STATUS_CODE}.ok) + res.put_header_text (h.string) ensure response_status_is_set: res.status_is_set response_code_ok: res.status_code = {HTTP_STATUS_CODE}.ok @@ -289,9 +289,30 @@ feature {NONE} -- Implementation empty_body: res.transfered_content_length = 0 end + frozen handle_use_proxy (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Write response to OPTIONS * into `res'. + require + res_attached: res /= Void + req_attached: req /= Void + proxy_required: requires_proxy (req) + local + h: HTTP_HEADER + do + create h.make + h.put_content_type_text_plain + h.put_current_date + h.put_location (proxy_server (req)) + h.put_content_length (0) + res.set_status_code ({HTTP_STATUS_CODE}.use_proxy) + ensure + response_status_is_set: res.status_is_set + response_code_use_proxy: res.status_code = {HTTP_STATUS_CODE}.use_proxy + header_sent: res.header_committed and res.message_committed + end + invariant - unavailability_message_attached: unavailable implies attached {READABLE_STRING_8} unavailablity_message as m and then + unavailability_message_attached: unavailable implies attached unavailablity_message as m and then m.count > 0 unavailability_duration_xor_unavailable_until: unavailability_duration > 0 implies unavailable_until = Void diff --git a/library/server/wsf/router/wsf_router.e b/library/server/wsf/router/wsf_router.e index 08a9c965..30785eb7 100644 --- a/library/server/wsf/router/wsf_router.e +++ b/library/server/wsf/router/wsf_router.e @@ -277,6 +277,26 @@ feature -- Status report end end + all_allowed_methods: WSF_REQUEST_METHODS + -- Methods allowed for ALL requests handled by `Current' + local + l_mapping: WSF_ROUTER_MAPPING + do + create Result + across + mappings as c + loop + if attached c.item.request_methods as m then + Result := Result + m + end + l_mapping := c.item.mapping + if attached {WSF_ROUTING_HANDLER} l_mapping.handler as l_routing then + Result := Result + l_routing.router.all_allowed_methods + end + --| not sure if that covers everything - Jocelyn, please comment + end + end + feature -- Hook execute_before (a_mapping: WSF_ROUTER_MAPPING) 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 5e647c63..17478ccd 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 @@ -76,25 +76,44 @@ feature {WSF_RESPONSE} -- Output send_to (res: WSF_RESPONSE) local - s: STRING + s, l_html_error_code_text: STRING l_text: detachable READABLE_STRING_GENERAL l_loc: detachable READABLE_STRING_8 h: like header + l_recognized: BOOLEAN + l_messages: HTTP_STATUS_CODE_MESSAGES do + create l_messages h := header - res.set_status_code ({HTTP_STATUS_CODE}.method_not_allowed) + l_recognized := recognized_methods.has (request.request_method.as_upper) + if l_recognized then + res.set_status_code (l_messages.method_not_allowed) + else + res.set_status_code (l_messages.not_implemented) + end if attached suggested_methods as lst and then not lst.is_empty then h.put_allow (lst) end - s := "Not allowed" + if attached l_messages.http_status_code_message (res.status_code) as l_msg then + s := l_msg + else + check + impossible: False + -- as res.status_code is set to one of the codes that will produce + -- a non-void response, even though there is no postcondition to prove it + end + s := "Bug in server" + end + l_html_error_code_text := html_error_code_text (l_messages, l_recognized) + if request.is_content_type_accepted ({HTTP_MIME_TYPES}.text_html) then s := "" s.append ("") s.append (html_encoder.encoded_string (request.request_uri)) - s.append ("Error 405 (Method Not Allowed)!!") + s.append (l_html_error_code_text + "!!") s.append ("%N") s.append ( "[ @@ -111,15 +130,15 @@ feature {WSF_RESPONSE} -- Output - + ]") s.append ("
") s.append ("
") s.append ("
") s.append ("
") s.append ("
") - s.append ("Error 405 (Method Not Allowed)
") - s.append ("
Error 405 (Method Not Allowed): the request method ") + s.append (l_html_error_code_text + "
") + s.append ("
" + l_html_error_code_text + ": the request method ") s.append (request.request_method) s.append (" is inappropriate for the URL for " + html_encoder.encoded_string (request.request_uri) + ".
") if attached suggested_methods as lst and then not lst.is_empty then @@ -180,7 +199,7 @@ feature {WSF_RESPONSE} -- Output h.put_content_type_text_html else - s := "Error 405 (Method Not Allowed): the request method " + s := l_html_error_code_text + ": the request method " s.append (request.request_method) s.append (" is inappropriate for the URL for '" + html_encoder.encoded_string (request.request_uri) + "'.%N") if attached suggested_methods as lst and then not lst.is_empty then @@ -239,6 +258,53 @@ feature {WSF_RESPONSE} -- Output res.flush end +feature {NONE} -- Implementation + + recognized_methods: WSF_REQUEST_METHODS + -- All methods defined in HTTP/1.1 specification + --| Should this include CONNECT? It probably shouldn't be recognized by an origin server, + --| We will need a way to extend this for additional methods that the server implements. E.g. PATCH. + do + create Result.make_from_iterable (<< + {HTTP_REQUEST_METHODS}.method_head, + {HTTP_REQUEST_METHODS}.method_get, + {HTTP_REQUEST_METHODS}.method_trace, + {HTTP_REQUEST_METHODS}.method_options, + {HTTP_REQUEST_METHODS}.method_post, + {HTTP_REQUEST_METHODS}.method_put, + {HTTP_REQUEST_METHODS}.method_delete + >>) + ensure + recognized_methods_not_void: Result /= Void + end + + html_error_code_text (a_messages: HTTP_STATUS_CODE_MESSAGES; a_recognized: BOOLEAN): READABLE_STRING_8 + -- Message for including in HTML error text according to `a_recognized' + require + a_messages_attached: a_messages /= Void + local + l_code: INTEGER + do + if a_recognized then + l_code := a_messages.method_not_allowed + else + l_code := a_messages.not_implemented + end + if attached a_messages.http_status_code_message (l_code) as l_msg then + Result := "Error " + l_code.out + " (" + l_msg + ")" + else + check + impossible: False + -- as res.status_code is set to one of the codes that will produce + -- a non-void response, even though there is no postcondition to prove it. + -- The postcondition wouldn't be needed if there was a precondition using is_valid_http_status_code + end + Result := "Bug in server" + end + ensure + html_error_code_text_attached: Result /= Void + 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)" From 10ffa2066d59ade71b3a4c09faf548de0c11bc3a Mon Sep 17 00:00:00 2001 From: Colin Adams Date: Mon, 18 Mar 2013 14:25:44 +0000 Subject: [PATCH 08/19] prior to refactoring for WSF_ROUTED_SKELETON_SERVICE --- .../server/wsf/router/wsf_routed_service.e | 34 ++++--------------- 1 file changed, 6 insertions(+), 28 deletions(-) diff --git a/library/server/wsf/router/wsf_routed_service.e b/library/server/wsf/router/wsf_routed_service.e index bca46767..b4d16f23 100644 --- a/library/server/wsf/router/wsf_routed_service.e +++ b/library/server/wsf/router/wsf_routed_service.e @@ -4,41 +4,19 @@ note date: "$Date$" revision: "$Revision$" -deferred class WSF_ROUTED_SERVICE +deferred class WSF_ROUTED_SKELETON_SERVICE inherit + WSF_ROUTED_SERVICE + redefine + execute + end + WSF_SYSTEM_OPTIONS_ACCESS_POLICY WSF_PROXY_USE_POLICY -feature -- Initialization - - initialize_router - -- Initialize router. - do - create_router - setup_router - ensure - router_created: router /= Void - end - - create_router - -- Create `router'. - --| could be redefine to initialize with proper capacity - do - create router.make (10) - ensure - router_created: router /= Void - end - - setup_router - -- Setup `router'. - require - router_created: router /= Void - deferred - end - feature -- Execution execute (req: WSF_REQUEST; res: WSF_RESPONSE) From 7435b4f454396cfa8136e934aaa2aec9c91c58ac Mon Sep 17 00:00:00 2001 From: Colin Adams Date: Mon, 18 Mar 2013 14:45:04 +0000 Subject: [PATCH 09/19] refactored for WSF_ROUTED_SKELETON_SERVICE --- examples/restbucksCRUD/src/restbucks_server.e | 8 +- ...f_uri_template_helper_for_routed_service.e | 62 ++++ .../helpers/wsf_uri_template_routed_service.e | 44 +-- .../server/wsf/router/wsf_routed_service.e | 274 ++--------------- .../wsf/router/wsf_routed_skeleton_service.e | 279 ++++++++++++++++++ 5 files changed, 373 insertions(+), 294 deletions(-) create mode 100644 library/server/wsf/router/support/uri_template/helpers/wsf_uri_template_helper_for_routed_service.e create mode 100644 library/server/wsf/router/wsf_routed_skeleton_service.e diff --git a/examples/restbucksCRUD/src/restbucks_server.e b/examples/restbucksCRUD/src/restbucks_server.e index d9ebead2..653ce132 100644 --- a/examples/restbucksCRUD/src/restbucks_server.e +++ b/examples/restbucksCRUD/src/restbucks_server.e @@ -3,16 +3,16 @@ note date : "$Date$" revision : "$Revision$" -class - RESTBUCKS_SERVER +class RESTBUCKS_SERVER inherit - ANY - WSF_URI_TEMPLATE_ROUTED_SERVICE + WSF_ROUTED_SKELETON_SERVICE undefine requires_proxy end + + WSF_URI_TEMPLATE_HELPER_FOR_ROUTED_SERVICE WSF_HANDLER_HELPER diff --git a/library/server/wsf/router/support/uri_template/helpers/wsf_uri_template_helper_for_routed_service.e b/library/server/wsf/router/support/uri_template/helpers/wsf_uri_template_helper_for_routed_service.e new file mode 100644 index 00000000..e304aae0 --- /dev/null +++ b/library/server/wsf/router/support/uri_template/helpers/wsf_uri_template_helper_for_routed_service.e @@ -0,0 +1,62 @@ +note + + description: "Facilities inheritance to add URI template-base routing to a routed service" + + date: "$Date$" + revision: "$Revision$" + +deferred class WSF_URI_TEMPLATE_HELPER_FOR_ROUTED_SERVICE + +feature -- Access + + router: WSF_ROUTER + -- Router used to dispatch the request according to the WSF_REQUEST object + -- and associated request methods; + -- This should not be implemented by descendants. Instead, you gain an effective + -- version by also inheriting from WSF_ROUTED_SERVICE, or one of it's descendants. + deferred + ensure + router_not_void: Result /= Void + end + +feature -- Mapping helper: uri + + map_uri_template (a_tpl: STRING; h: WSF_URI_TEMPLATE_HANDLER) + -- Map `h' as handler for `a_tpl' + require + a_tpl_attached: a_tpl /= Void + h_attached: h /= Void + do + 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_REQUEST_METHODS) + -- Map `h' as handler for `a_tpl' for request methods `rqst_methods'. + require + a_tpl_attached: a_tpl /= Void + h_attached: h /= Void + do + router.map_with_request_methods (create {WSF_URI_TEMPLATE_MAPPING}.make (a_tpl, h), rqst_methods) + end + +feature -- Mapping helper: uri agent + + map_uri_template_agent (a_tpl: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [req: WSF_REQUEST; res: WSF_RESPONSE]]) + -- Map `proc' as handler for `a_tpl' + require + a_tpl_attached: a_tpl /= Void + proc_attached: proc /= Void + 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_REQUEST_METHODS) + -- Map `proc' as handler for `a_tpl' for request methods `rqst_methods'. + require + a_tpl_attached: a_tpl /= Void + proc_attached: proc /= Void + do + map_uri_template_with_request_methods (a_tpl, create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (proc), rqst_methods) + end + +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 7dc8b5a6..51b27375 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 @@ -4,51 +4,13 @@ note date: "$Date$" revision: "$Revision$" -deferred class - WSF_URI_TEMPLATE_ROUTED_SERVICE +deferred class WSF_URI_TEMPLATE_ROUTED_SERVICE inherit + WSF_ROUTED_SERVICE -feature -- Mapping helper: uri - - map_uri_template (a_tpl: STRING; h: WSF_URI_TEMPLATE_HANDLER) - -- Map `h' as handler for `a_tpl' - require - a_tpl_attached: a_tpl /= Void - h_attached: h /= Void - do - 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_REQUEST_METHODS) - -- Map `h' as handler for `a_tpl' for request methods `rqst_methods'. - require - a_tpl_attached: a_tpl /= Void - h_attached: h /= Void - do - router.map_with_request_methods (create {WSF_URI_TEMPLATE_MAPPING}.make (a_tpl, h), rqst_methods) - end - -feature -- Mapping helper: uri agent - - map_uri_template_agent (a_tpl: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [req: WSF_REQUEST; res: WSF_RESPONSE]]) - -- Map `proc' as handler for `a_tpl' - require - a_tpl_attached: a_tpl /= Void - proc_attached: proc /= Void - 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_REQUEST_METHODS) - -- Map `proc' as handler for `a_tpl' for request methods `rqst_methods'. - require - a_tpl_attached: a_tpl /= Void - proc_attached: proc /= Void - do - map_uri_template_with_request_methods (a_tpl, create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (proc), rqst_methods) - end + WSF_URI_TEMPLATE_HELPER_FOR_ROUTED_SERVICE note copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" diff --git a/library/server/wsf/router/wsf_routed_service.e b/library/server/wsf/router/wsf_routed_service.e index b4d16f23..22f7a0c1 100644 --- a/library/server/wsf/router/wsf_routed_service.e +++ b/library/server/wsf/router/wsf_routed_service.e @@ -4,40 +4,44 @@ note date: "$Date$" revision: "$Revision$" -deferred class WSF_ROUTED_SKELETON_SERVICE - -inherit - +deferred class WSF_ROUTED_SERVICE - redefine - execute + +feature -- Initialization + + initialize_router + -- Initialize router + do + create_router + setup_router end - WSF_SYSTEM_OPTIONS_ACCESS_POLICY + create_router + -- Create `router' + --| could be redefine to initialize with proper capacity + do + create router.make (10) + ensure + router_created: router /= Void + end - WSF_PROXY_USE_POLICY + setup_router + -- Setup `router' + require + router_created: router /= Void + deferred + end feature -- Execution execute (req: WSF_REQUEST; res: WSF_RESPONSE) - -- If the service is available, and request URI is not too long, dispatch the request + -- Dispatch the request -- and if handler is not found, execute the default procedure `execute_default'. require req_attached: req /= Void res_attached: res /= Void do - --| When we reach here, the request has already passed check for 400 (Bad request), - --| which is implemented in WSF_REQUEST.make_from_wgi (when it calls `analyze'). - if unavailable then - handle_unavailable (res) - elseif requires_proxy (req) then - handle_use_proxy (req, res) - elseif maximum_uri_length > 0 and then req.request_uri.count.to_natural_32 > maximum_uri_length then - handle_request_uri_too_long (res) - elseif req.is_request_method ({HTTP_REQUEST_METHODS}.method_options) and then - req.request_uri.same_string ("*") then - handle_server_options (req, res) - elseif attached router.dispatch_and_return_handler (req, res) as p then + if attached router.dispatch_and_return_handler (req, res) as p then -- executed else execute_default (req, res) @@ -58,9 +62,6 @@ feature -- Execution create msg.make_with_router (req, router) msg.set_documentation_included (True) res.send (msg) - ensure - response_status_is_set: res.status_is_set - message_sent: res.header_committed and res.message_committed end feature -- Access @@ -69,231 +70,6 @@ feature -- Access -- Router used to dispatch the request according to the WSF_REQUEST object -- and associated request methods -feature -- Measurement - - maximum_uri_length: NATURAL - -- Maximum length in characters (or zero for no limit) permitted - -- for {WSF_REQUEST}.request_uri - -feature -- Status report - - unavailable: BOOLEAN - -- Is service currently unavailable? - - unavailablity_message: detachable READABLE_STRING_8 - -- Message to be included as text of response body for {HTTP_STATUS_CODE}.service_unavailable - - unavailability_duration: NATURAL - -- Delta seconds for service unavailability (0 if not known) - - unavailable_until: detachable DATE_TIME - -- Time at which service becomes available again (if known) - -feature -- Status setting - - set_available - -- Set `unavailable' to `False'. - do - unavailable := False - unavailablity_message := Void - unavailable_until := Void - ensure - available: unavailable = False - unavailablity_message_detached: unavailablity_message = Void - unavailable_until_detached: unavailable_until = Void - end - - set_unavailable (a_message: READABLE_STRING_8; a_duration: NATURAL; a_until: detachable DATE_TIME) - -- Set `unavailable' to `True'. - require - a_message_attached: a_message /= Void - a_duration_xor_a_until: a_duration > 0 implies a_until = Void - do - unavailable := True - unavailablity_message := a_message - unavailability_duration := a_duration - ensure - unavailable: unavailable = True - unavailablity_message_aliased: unavailablity_message = a_message - unavailability_duration_set: unavailability_duration = a_duration - unavailable_until_aliased: unavailable_until = a_until - end - - set_maximum_uri_length (a_len: NATURAL) - -- Set `maximum_uri_length' to `a_len'. - -- Can pass zero to mean no restrictions. - do - maximum_uri_length := a_len - ensure - maximum_uri_length_set: maximum_uri_length = a_len - end - -feature {NONE} -- Implementation - - handle_unavailable (res: WSF_RESPONSE) - -- Write "Service unavailable" response to `res'. - require - unavailable: unavailable - res_attached: res /= Void - local - h: HTTP_HEADER - do - create h.make - h.put_content_type_text_plain - check attached unavailablity_message as m then - -- invariant plus precondition - h.put_content_length (m.count) - h.put_current_date - res.set_status_code ({HTTP_STATUS_CODE}.service_unavailable) - if unavailability_duration > 0 then - h.put_header_key_value ({HTTP_HEADER_NAMES}.header_retry_after, unavailability_duration.out) - elseif attached unavailable_until as u then - h.put_header_key_value ({HTTP_HEADER_NAMES}.header_retry_after, - h.date_to_rfc1123_http_date_format (u)) - end - res.put_header_text (h.string) - res.put_string (m) - end - ensure - response_status_is_set: res.status_is_set - status_is_service_unavailable: res.status_code = {HTTP_STATUS_CODE}.service_unavailable - body_sent: res.message_committed and then res.transfered_content_length > 0 - body_content_was_unavailablity_message: True -- doesn't seem to be any way to check - end - - handle_request_uri_too_long (res: WSF_RESPONSE) - -- Write "Request URI too long" response into `res'. - require - res_attached: res /= Void - local - h: HTTP_HEADER - m: READABLE_STRING_8 - do - create h.make - h.put_content_type_text_plain - h.put_current_date - m := "Maximum permitted length for request URI is " + maximum_uri_length.out + " characters" - h.put_content_length (m.count) - res.set_status_code ({HTTP_STATUS_CODE}.request_uri_too_long) - res.put_header_text (h.string) - res.put_string (m) - ensure - response_status_is_set: res.status_is_set - status_is_request_uri_too_long: res.status_code = {HTTP_STATUS_CODE}.request_uri_too_long - body_sent: res.message_committed and then res.transfered_content_length > 0 - end - - frozen handle_server_options (req: WSF_REQUEST; res: WSF_RESPONSE) - -- Write response to OPTIONS * into `res'. - require - req_attached: req /= Void - res_attached: res /= Void - method_is_options: req.is_request_method ({HTTP_REQUEST_METHODS}.method_options) - server_options_requested: req.request_uri.same_string ("*") - do - --| First check if forbidden. - --| (N.B. authentication requires an absoluteURI (RFC3617 page 3), and so cannot be used for OPTIONS *. - --| Otherwise construct an Allow response automatically from the router. - if is_system_options_forbidden (req) then - handle_system_options_forbidden (req, res) - else - handle_system_options (req, res) - end - ensure - response_status_is_set: res.status_is_set - valid_response_code: res.status_code = {HTTP_STATUS_CODE}.forbidden or - res.status_code = {HTTP_STATUS_CODE}.not_found or res.status_code = {HTTP_STATUS_CODE}.ok - header_sent: res.header_committed and res.message_committed - end - - frozen handle_system_options_forbidden (req: WSF_REQUEST; res: WSF_RESPONSE) - -- Write a 403 Forbidden or a 404 Not found response into `res'. - require - req_attached: req /= Void - res_attached: res /= Void - method_is_options: req.is_request_method ({HTTP_REQUEST_METHODS}.method_options) - server_options_requested: req.request_uri.same_string ("*") - local - m: detachable READABLE_STRING_8 - h: HTTP_HEADER - do - m := system_options_forbidden_text (req) - if attached {READABLE_STRING_8} m as l_msg then - create h.make - h.put_content_type_text_plain - h.put_current_date - h.put_content_length (l_msg.count) - res.set_status_code ({HTTP_STATUS_CODE}.forbidden) - res.put_header_text (h.string) - res.put_string (l_msg) - else - create h.make - h.put_content_type_text_plain - h.put_current_date - h.put_content_length (0) - res.set_status_code ({HTTP_STATUS_CODE}.not_found) - res.put_header_text (h.string) - end - ensure - response_status_is_set: res.status_is_set - valid_response_code: res.status_code = {HTTP_STATUS_CODE}.forbidden or - res.status_code = {HTTP_STATUS_CODE}.not_found - header_sent: res.header_committed - message_sent: res.message_committed - end - - handle_system_options (req: WSF_REQUEST; res: WSF_RESPONSE) - -- Write response to OPTIONS * into `res'. - -- This may be redefined by the user, but normally this will not be necessary. - require - req_attached: req /= Void - res_attached: res /= Void - method_is_options: req.is_request_method ({HTTP_REQUEST_METHODS}.method_options) - server_options_requested: req.request_uri.same_string ("*") - local - h: HTTP_HEADER - do - create h.make - h.put_content_type_text_plain - h.put_current_date - h.put_allow (router.all_allowed_methods) - h.put_content_length (0) - res.set_status_code ({HTTP_STATUS_CODE}.ok) - res.put_header_text (h.string) - ensure - response_status_is_set: res.status_is_set - response_code_ok: res.status_code = {HTTP_STATUS_CODE}.ok - header_sent: res.header_committed and res.message_committed - empty_body: res.transfered_content_length = 0 - end - - frozen handle_use_proxy (req: WSF_REQUEST; res: WSF_RESPONSE) - -- Write response to OPTIONS * into `res'. - require - res_attached: res /= Void - req_attached: req /= Void - proxy_required: requires_proxy (req) - local - h: HTTP_HEADER - do - create h.make - h.put_content_type_text_plain - h.put_current_date - h.put_location (proxy_server (req)) - h.put_content_length (0) - res.set_status_code ({HTTP_STATUS_CODE}.use_proxy) - ensure - response_status_is_set: res.status_is_set - response_code_use_proxy: res.status_code = {HTTP_STATUS_CODE}.use_proxy - header_sent: res.header_committed and res.message_committed - end - -invariant - - unavailability_message_attached: unavailable implies attached unavailablity_message as m and then - m.count > 0 - unavailability_duration_xor_unavailable_until: unavailability_duration > 0 implies unavailable_until = Void - ;note copyright: "2011-2013, 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_routed_skeleton_service.e b/library/server/wsf/router/wsf_routed_skeleton_service.e new file mode 100644 index 00000000..8f50331f --- /dev/null +++ b/library/server/wsf/router/wsf_routed_skeleton_service.e @@ -0,0 +1,279 @@ +note + description: "Summary description for {WSF_ROUTED_SERVICE}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class WSF_ROUTED_SKELETON_SERVICE + +inherit + + WSF_ROUTED_SERVICE + redefine + execute + end + + WSF_SYSTEM_OPTIONS_ACCESS_POLICY + + WSF_PROXY_USE_POLICY + +feature -- Execution + + execute (req: WSF_REQUEST; res: WSF_RESPONSE) + -- If the service is available, and request URI is not too long, dispatch the request + -- and if handler is not found, execute the default procedure `execute_default'. + do + --| When we reach here, the request has already passed check for 400 (Bad request), + --| which is implemented in WSF_REQUEST.make_from_wgi (when it calls `analyze'). + if unavailable then + handle_unavailable (res) + elseif requires_proxy (req) then + handle_use_proxy (req, res) + elseif maximum_uri_length > 0 and then req.request_uri.count.to_natural_32 > maximum_uri_length then + handle_request_uri_too_long (res) + elseif req.is_request_method ({HTTP_REQUEST_METHODS}.method_options) and then + req.request_uri.same_string ("*") then + handle_server_options (req, res) + elseif attached router.dispatch_and_return_handler (req, res) as p then + -- executed + else + execute_default (req, res) + end + end + +feature -- Measurement + + maximum_uri_length: NATURAL + -- Maximum length in characters (or zero for no limit) permitted + -- for {WSF_REQUEST}.request_uri + +feature -- Status report + + unavailable: BOOLEAN + -- Is service currently unavailable? + + unavailablity_message: detachable READABLE_STRING_8 + -- Message to be included as text of response body for {HTTP_STATUS_CODE}.service_unavailable + + unavailability_duration: NATURAL + -- Delta seconds for service unavailability (0 if not known) + + unavailable_until: detachable DATE_TIME + -- Time at which service becomes available again (if known) + +feature -- Status setting + + set_available + -- Set `unavailable' to `False'. + do + unavailable := False + unavailablity_message := Void + unavailable_until := Void + ensure + available: unavailable = False + unavailablity_message_detached: unavailablity_message = Void + unavailable_until_detached: unavailable_until = Void + end + + set_unavailable (a_message: READABLE_STRING_8; a_duration: NATURAL; a_until: detachable DATE_TIME) + -- Set `unavailable' to `True'. + require + a_message_attached: a_message /= Void + a_duration_xor_a_until: a_duration > 0 implies a_until = Void + do + unavailable := True + unavailablity_message := a_message + unavailability_duration := a_duration + ensure + unavailable: unavailable = True + unavailablity_message_aliased: unavailablity_message = a_message + unavailability_duration_set: unavailability_duration = a_duration + unavailable_until_aliased: unavailable_until = a_until + end + + set_maximum_uri_length (a_len: NATURAL) + -- Set `maximum_uri_length' to `a_len'. + -- Can pass zero to mean no restrictions. + do + maximum_uri_length := a_len + ensure + maximum_uri_length_set: maximum_uri_length = a_len + end + +feature {NONE} -- Implementation + + handle_unavailable (res: WSF_RESPONSE) + -- Write "Service unavailable" response to `res'. + require + unavailable: unavailable + res_attached: res /= Void + local + h: HTTP_HEADER + do + create h.make + h.put_content_type_text_plain + check attached unavailablity_message as m then + -- invariant plus precondition + h.put_content_length (m.count) + h.put_current_date + res.set_status_code ({HTTP_STATUS_CODE}.service_unavailable) + if unavailability_duration > 0 then + h.put_header_key_value ({HTTP_HEADER_NAMES}.header_retry_after, unavailability_duration.out) + elseif attached unavailable_until as u then + h.put_header_key_value ({HTTP_HEADER_NAMES}.header_retry_after, + h.date_to_rfc1123_http_date_format (u)) + end + res.put_header_text (h.string) + res.put_string (m) + end + ensure + response_status_is_set: res.status_is_set + status_is_service_unavailable: res.status_code = {HTTP_STATUS_CODE}.service_unavailable + body_sent: res.message_committed and then res.transfered_content_length > 0 + body_content_was_unavailablity_message: True -- doesn't seem to be any way to check + end + + handle_request_uri_too_long (res: WSF_RESPONSE) + -- Write "Request URI too long" response into `res'. + require + res_attached: res /= Void + local + h: HTTP_HEADER + m: READABLE_STRING_8 + do + create h.make + h.put_content_type_text_plain + h.put_current_date + m := "Maximum permitted length for request URI is " + maximum_uri_length.out + " characters" + h.put_content_length (m.count) + res.set_status_code ({HTTP_STATUS_CODE}.request_uri_too_long) + res.put_header_text (h.string) + res.put_string (m) + ensure + response_status_is_set: res.status_is_set + status_is_request_uri_too_long: res.status_code = {HTTP_STATUS_CODE}.request_uri_too_long + body_sent: res.message_committed and then res.transfered_content_length > 0 + end + + frozen handle_server_options (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Write response to OPTIONS * into `res'. + require + req_attached: req /= Void + res_attached: res /= Void + method_is_options: req.is_request_method ({HTTP_REQUEST_METHODS}.method_options) + server_options_requested: req.request_uri.same_string ("*") + do + --| First check if forbidden. + --| (N.B. authentication requires an absoluteURI (RFC3617 page 3), and so cannot be used for OPTIONS *. + --| Otherwise construct an Allow response automatically from the router. + if is_system_options_forbidden (req) then + handle_system_options_forbidden (req, res) + else + handle_system_options (req, res) + end + ensure + response_status_is_set: res.status_is_set + valid_response_code: res.status_code = {HTTP_STATUS_CODE}.forbidden or + res.status_code = {HTTP_STATUS_CODE}.not_found or res.status_code = {HTTP_STATUS_CODE}.ok + header_sent: res.header_committed and res.message_committed + end + + frozen handle_system_options_forbidden (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Write a 403 Forbidden or a 404 Not found response into `res'. + require + req_attached: req /= Void + res_attached: res /= Void + method_is_options: req.is_request_method ({HTTP_REQUEST_METHODS}.method_options) + server_options_requested: req.request_uri.same_string ("*") + local + m: detachable READABLE_STRING_8 + h: HTTP_HEADER + do + m := system_options_forbidden_text (req) + if attached {READABLE_STRING_8} m as l_msg then + create h.make + h.put_content_type_text_plain + h.put_current_date + h.put_content_length (l_msg.count) + res.set_status_code ({HTTP_STATUS_CODE}.forbidden) + res.put_header_text (h.string) + res.put_string (l_msg) + else + create h.make + h.put_content_type_text_plain + h.put_current_date + h.put_content_length (0) + res.set_status_code ({HTTP_STATUS_CODE}.not_found) + res.put_header_text (h.string) + end + ensure + response_status_is_set: res.status_is_set + valid_response_code: res.status_code = {HTTP_STATUS_CODE}.forbidden or + res.status_code = {HTTP_STATUS_CODE}.not_found + header_sent: res.header_committed + message_sent: res.message_committed + end + + handle_system_options (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Write response to OPTIONS * into `res'. + -- This may be redefined by the user, but normally this will not be necessary. + require + req_attached: req /= Void + res_attached: res /= Void + method_is_options: req.is_request_method ({HTTP_REQUEST_METHODS}.method_options) + server_options_requested: req.request_uri.same_string ("*") + local + h: HTTP_HEADER + do + create h.make + h.put_content_type_text_plain + h.put_current_date + h.put_allow (router.all_allowed_methods) + h.put_content_length (0) + res.set_status_code ({HTTP_STATUS_CODE}.ok) + res.put_header_text (h.string) + ensure + response_status_is_set: res.status_is_set + response_code_ok: res.status_code = {HTTP_STATUS_CODE}.ok + header_sent: res.header_committed and res.message_committed + empty_body: res.transfered_content_length = 0 + end + + frozen handle_use_proxy (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Write response to OPTIONS * into `res'. + require + res_attached: res /= Void + req_attached: req /= Void + proxy_required: requires_proxy (req) + local + h: HTTP_HEADER + do + create h.make + h.put_content_type_text_plain + h.put_current_date + h.put_location (proxy_server (req)) + h.put_content_length (0) + res.set_status_code ({HTTP_STATUS_CODE}.use_proxy) + ensure + response_status_is_set: res.status_is_set + response_code_use_proxy: res.status_code = {HTTP_STATUS_CODE}.use_proxy + header_sent: res.header_committed and res.message_committed + end + +invariant + + unavailability_message_attached: unavailable implies attached unavailablity_message as m and then + m.count > 0 + unavailability_duration_xor_unavailable_until: unavailability_duration > 0 implies unavailable_until = Void + +;note + copyright: "2011-2013, 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 From d34c940c91c208c7418d810d7176526b30ff7ebc Mon Sep 17 00:00:00 2001 From: Colin Adams Date: Tue, 19 Mar 2013 15:59:17 +0000 Subject: [PATCH 10/19] added reference to assertion tags in check justiciation --- .../wsf/router/wsf_routed_skeleton_service.e | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/library/server/wsf/router/wsf_routed_skeleton_service.e b/library/server/wsf/router/wsf_routed_skeleton_service.e index 8f50331f..40eb870a 100644 --- a/library/server/wsf/router/wsf_routed_skeleton_service.e +++ b/library/server/wsf/router/wsf_routed_skeleton_service.e @@ -113,7 +113,7 @@ feature {NONE} -- Implementation create h.make h.put_content_type_text_plain check attached unavailablity_message as m then - -- invariant plus precondition + -- invariant `unavailability_message_attached' plus precondition `unavailable' h.put_content_length (m.count) h.put_current_date res.set_status_code ({HTTP_STATUS_CODE}.service_unavailable) @@ -142,7 +142,7 @@ feature {NONE} -- Implementation m: READABLE_STRING_8 do create h.make - h.put_content_type_text_plain + h.put_content_type_text_plain h.put_current_date m := "Maximum permitted length for request URI is " + maximum_uri_length.out + " characters" h.put_content_length (m.count) @@ -192,7 +192,7 @@ feature {NONE} -- Implementation m := system_options_forbidden_text (req) if attached {READABLE_STRING_8} m as l_msg then create h.make - h.put_content_type_text_plain + h.put_content_type_text_plain h.put_current_date h.put_content_length (l_msg.count) res.set_status_code ({HTTP_STATUS_CODE}.forbidden) @@ -200,7 +200,7 @@ feature {NONE} -- Implementation res.put_string (l_msg) else create h.make - h.put_content_type_text_plain + h.put_content_type_text_plain h.put_current_date h.put_content_length (0) res.set_status_code ({HTTP_STATUS_CODE}.not_found) @@ -211,7 +211,7 @@ feature {NONE} -- Implementation valid_response_code: res.status_code = {HTTP_STATUS_CODE}.forbidden or res.status_code = {HTTP_STATUS_CODE}.not_found header_sent: res.header_committed - message_sent: res.message_committed + message_sent: res.message_committed end handle_system_options (req: WSF_REQUEST; res: WSF_RESPONSE) @@ -226,7 +226,7 @@ feature {NONE} -- Implementation h: HTTP_HEADER do create h.make - h.put_content_type_text_plain + h.put_content_type_text_plain h.put_current_date h.put_allow (router.all_allowed_methods) h.put_content_length (0) @@ -249,7 +249,7 @@ feature {NONE} -- Implementation h: HTTP_HEADER do create h.make - h.put_content_type_text_plain + h.put_content_type_text_plain h.put_current_date h.put_location (proxy_server (req)) h.put_content_length (0) @@ -259,7 +259,7 @@ feature {NONE} -- Implementation response_code_use_proxy: res.status_code = {HTTP_STATUS_CODE}.use_proxy header_sent: res.header_committed and res.message_committed end - + invariant unavailability_message_attached: unavailable implies attached unavailablity_message as m and then From 91a3b8176ff31af3dbfbf6113983ecadabba5a59 Mon Sep 17 00:00:00 2001 From: Colin Adams Date: Wed, 20 Mar 2013 20:10:54 +0000 Subject: [PATCH 11/19] Amedned class header of WSF_METHOD_NOT_ALLOWED_RESPONSE --- .../wsf/src/response/wsf_method_not_allowed_response.e | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) 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 17478ccd..ee8a6b8b 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 @@ -1,6 +1,8 @@ note description: "[ - This class is used to report a 405 Method not allowed response + This class is used to report a 405 Method not allowed response, + or a 501 not implemented response, depending upon whether + the method is known to the server. ]" date: "$Date$" revision: "$Revision$" @@ -108,7 +110,7 @@ feature {WSF_RESPONSE} -- Output end l_html_error_code_text := html_error_code_text (l_messages, l_recognized) - + if request.is_content_type_accepted ({HTTP_MIME_TYPES}.text_html) then s := "" s.append ("") @@ -304,9 +306,9 @@ feature {NONE} -- Implementation ensure html_error_code_text_attached: Result /= Void end - + note - copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" + copyright: "2011-2013, 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 From ad5ccd6585cf1a30d04a908724f6be3d1de6cc16 Mon Sep 17 00:00:00 2001 From: Colin Adams <colinpauladams@gmail.com> Date: Sat, 23 Mar 2013 17:15:17 +0000 Subject: [PATCH 12/19] Corrected header comment --- library/server/wsf/router/wsf_routed_skeleton_service.e | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/server/wsf/router/wsf_routed_skeleton_service.e b/library/server/wsf/router/wsf_routed_skeleton_service.e index 40eb870a..94440c6e 100644 --- a/library/server/wsf/router/wsf_routed_skeleton_service.e +++ b/library/server/wsf/router/wsf_routed_skeleton_service.e @@ -240,7 +240,7 @@ feature {NONE} -- Implementation end frozen handle_use_proxy (req: WSF_REQUEST; res: WSF_RESPONSE) - -- Write response to OPTIONS * into `res'. + -- Write Use Proxy response `res'. require res_attached: res /= Void req_attached: req /= Void From 14088f126bea4115b648a36ef8e2598aea3f3e00 Mon Sep 17 00:00:00 2001 From: Colin Adams <colinpauladams@gmail.com> Date: Tue, 26 Mar 2013 16:10:32 +0000 Subject: [PATCH 13/19] Use class URI --- .../helpers/wsf_uri_template_routed_service.e | 28 -------- .../helpers/wsf_uri_template_router_helper.e | 66 ------------------- .../server/wsf/router/wsf_no_proxy_policy.e | 5 +- .../server/wsf/router/wsf_proxy_use_policy.e | 22 +++++-- .../wsf/router/wsf_routed_skeleton_service.e | 2 +- library/server/wsf/wsf-safe.ecf | 4 +- library/server/wsf/wsf.ecf | 4 +- tests/all-safe.ecf | 25 ++++--- 8 files changed, 39 insertions(+), 117 deletions(-) delete mode 100644 library/server/wsf/router/support/uri_template/helpers/wsf_uri_template_routed_service.e delete mode 100644 library/server/wsf/router/support/uri_template/helpers/wsf_uri_template_router_helper.e 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 deleted file mode 100644 index d595c3e4..00000000 --- a/library/server/wsf/router/support/uri_template/helpers/wsf_uri_template_routed_service.e +++ /dev/null @@ -1,28 +0,0 @@ -note - description: "Summary description for {WSF_URI_TEMPLATE_ROUTED_SERVICE}." - author: "" - date: "$Date$" - revision: "$Revision$" - -deferred class WSF_URI_TEMPLATE_ROUTED_SERVICE - -obsolete "Inherit from WSF_ROUTED_SERVICE and WSF_URI_ROUTER_HELPER [2013-mar-19]" - -inherit - - WSF_ROUTED_SERVICE - - WSF_URI_TEMPLATE_ROUTER_HELPER - - -note - copyright: "2011-2013, 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/support/uri_template/helpers/wsf_uri_template_router_helper.e b/library/server/wsf/router/support/uri_template/helpers/wsf_uri_template_router_helper.e deleted file mode 100644 index cf60b7f0..00000000 --- a/library/server/wsf/router/support/uri_template/helpers/wsf_uri_template_router_helper.e +++ /dev/null @@ -1,66 +0,0 @@ -note - description: "Summary description for {WSF_URI_TEMPLATE_ROUTER_HELPER}." - author: "" - date: "$Date$" - revision: "$Revision$" - -deferred class - WSF_URI_TEMPLATE_ROUTER_HELPER - -feature -- Access - - router: WSF_ROUTER - deferred - end - -feature -- Mapping helper: uri - - map_uri_template (a_tpl: STRING; h: WSF_URI_TEMPLATE_HANDLER) - -- Map `h' as handler for `a_tpl' - require - a_tpl_attached: a_tpl /= Void - h_attached: h /= Void - do - 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_REQUEST_METHODS) - -- Map `h' as handler for `a_tpl' for request methods `rqst_methods'. - require - a_tpl_attached: a_tpl /= Void - h_attached: h /= Void - do - router.map_with_request_methods (create {WSF_URI_TEMPLATE_MAPPING}.make (a_tpl, h), rqst_methods) - end - -feature -- Mapping helper: uri agent - - map_uri_template_agent (a_tpl: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [req: WSF_REQUEST; res: WSF_RESPONSE]]) - -- Map `proc' as handler for `a_tpl' - require - a_tpl_attached: a_tpl /= Void - proc_attached: proc /= Void - 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_REQUEST_METHODS) - -- Map `proc' as handler for `a_tpl' for request methods `rqst_methods'. - require - a_tpl_attached: a_tpl /= Void - proc_attached: proc /= Void - do - map_uri_template_with_request_methods (a_tpl, create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (proc), rqst_methods) - end - -note - copyright: "2011-2013, 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_no_proxy_policy.e b/library/server/wsf/router/wsf_no_proxy_policy.e index 3397b30f..36aa4d7e 100644 --- a/library/server/wsf/router/wsf_no_proxy_policy.e +++ b/library/server/wsf/router/wsf_no_proxy_policy.e @@ -26,10 +26,11 @@ feature -- Access do end - proxy_server (req: WSF_REQUEST): READABLE_STRING_8 -- We can't currently use UT_URI + proxy_server (req: WSF_REQUEST): URI -- Absolute URI of proxy server which `req' must use do - Result := "" -- doesn't meet the postcondition, but the precondition is never true. + create Result.make_from_string ("") + -- doesn't meet the postcondition, but the precondition is never true. end end diff --git a/library/server/wsf/router/wsf_proxy_use_policy.e b/library/server/wsf/router/wsf_proxy_use_policy.e index 7c1c046c..a788c977 100644 --- a/library/server/wsf/router/wsf_proxy_use_policy.e +++ b/library/server/wsf/router/wsf_proxy_use_policy.e @@ -7,7 +7,7 @@ note The default policy implemented here is to require use of the proxy for HTTP/1.0 clients (only) for all requests. ]" - + date: "$Date$" revision: "$Revision$" @@ -25,16 +25,18 @@ feature -- Access end end - proxy_server (req: WSF_REQUEST): READABLE_STRING_8 -- We can't currently use UT_URI + proxy_server (req: WSF_REQUEST): URI -- Absolute URI of proxy server which `req' must use - --| An alternative design would allow a relative URI (relative to the server host), - --| which will only work if both the server and the proxy use the default ports. require req_attached: req /= Void proxy_required: requires_proxy (req) deferred ensure - absolute_uri: True -- We can't currently use UT_URI to check this. Have we got another class? + proxy_server_attached: Result /= Void + valid_uri: Result.is_valid + absolute_uri: not Result.scheme.is_empty + http_or_https: Result.scheme.is_case_insensitive_equal ("http") or + Result.scheme.is_case_insensitive_equal ("https") end is_http_1_0 (req: WSF_REQUEST): BOOLEAN @@ -73,4 +75,14 @@ feature -- Access end end +note + copyright: "2011-2013, 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_skeleton_service.e b/library/server/wsf/router/wsf_routed_skeleton_service.e index 94440c6e..9aff9444 100644 --- a/library/server/wsf/router/wsf_routed_skeleton_service.e +++ b/library/server/wsf/router/wsf_routed_skeleton_service.e @@ -251,7 +251,7 @@ feature {NONE} -- Implementation create h.make h.put_content_type_text_plain h.put_current_date - h.put_location (proxy_server (req)) + h.put_location (proxy_server (req).string) h.put_content_length (0) res.set_status_code ({HTTP_STATUS_CODE}.use_proxy) ensure diff --git a/library/server/wsf/wsf-safe.ecf b/library/server/wsf/wsf-safe.ecf index 5c654920..dbb91df7 100644 --- a/library/server/wsf/wsf-safe.ecf +++ b/library/server/wsf/wsf-safe.ecf @@ -16,7 +16,9 @@ <library name="error" location="../../utility/general/error/error-safe.ecf"/> <library name="http" location="../../network/protocol/http/http-safe.ecf"/> <library name="uri_template" location="../../text/parser/uri_template/uri_template-safe.ecf"/> - <library name="encoder" location="..\..\text\encoder\encoder-safe.ecf"/> + <library name="encoder" + location="..\..\text\encoder\encoder-safe.ecf"/> + <library name="uri" location="$ISE_LIBRARY\library\text\uri\uri-safe.ecf" readonly="true"/> <cluster name="src" location=".\src" recursive="true"/> <cluster name="router" location=".\router" recursive="true"/> </target> diff --git a/library/server/wsf/wsf.ecf b/library/server/wsf/wsf.ecf index 7c540415..3d19ec4d 100644 --- a/library/server/wsf/wsf.ecf +++ b/library/server/wsf/wsf.ecf @@ -16,7 +16,9 @@ <library name="error" location="../../utility/general/error/error.ecf"/> <library name="http" location="../../network/protocol/http/http.ecf"/> <library name="uri_template" location="../../text/parser/uri_template/uri_template.ecf"/> - <library name="encoder" location="..\..\text\encoder\encoder.ecf"/> + <library name="encoder" + location="..\..\text\encoder\encoder.ecf"/> + <library name="uri" location="$ISE_LIBRARY\library\text\uri\uri.ecf" readonly="true"/> <cluster name="src" location=".\src" recursive="true"/> <cluster name="router" location=".\router" recursive="true"/> </target> diff --git a/tests/all-safe.ecf b/tests/all-safe.ecf index 736905b6..314749de 100644 --- a/tests/all-safe.ecf +++ b/tests/all-safe.ecf @@ -11,33 +11,33 @@ <option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="standard"> </option> <library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/> + <library name="cms" location="..\draft\application\cms\cms-safe.ecf" readonly="false"/> <library name="connector_cgi" location="..\library\server\ewsgi\connectors\cgi\cgi-safe.ecf" readonly="false"/> <library name="connector_libfcgi" location="..\library\server\ewsgi\connectors\libfcgi\libfcgi-safe.ecf" readonly="false"/> <library name="connector_nino" location="..\library\server\ewsgi\connectors\nino\nino-safe.ecf" readonly="false"/> <library name="connector_null" location="..\library\server\ewsgi\connectors\null\null-safe.ecf" readonly="false"/> - <library name="encoder" location="..\library\text\encoder\encoder-safe.ecf" readonly="false"/> - <library name="wsf_connector_nino" location="..\library\server\wsf\connector\nino-safe.ecf" readonly="false"/> - <library name="wsf_connector_openshift" location="..\library\server\wsf\connector\openshift-safe.ecf" readonly="false"/> - <library name="dft_connector_libfcgi" location="..\library\server\wsf\default\libfcgi-safe.ecf" readonly="false"/> + <library name="conneg" location="..\library\network\protocol\CONNEG\conneg-safe.ecf" readonly="false"/> + <library name="css" location="..\draft\library\text\css\css-safe.ecf" readonly="false"/> <library name="dft_connector_cgi" location="..\library\server\wsf\default\cgi-safe.ecf" readonly="false"/> + <library name="dft_connector_libfcgi" location="..\library\server\wsf\default\libfcgi-safe.ecf" readonly="false"/> <library name="dft_connector_nino" location="..\library\server\wsf\default\nino-safe.ecf" readonly="false"/> <library name="dft_connector_openshift" location="..\library\server\wsf\default\openshift-safe.ecf" readonly="false"/> - <library name="conneg" location="../library/network/protocol/CONNEG/conneg-safe.ecf" readonly="false"/> + <library name="encoder" location="..\library\text\encoder\encoder-safe.ecf" readonly="false"/> + <library name="ewf_support" location="..\library\server\ewf_support\ewf_support-safe.ecf" readonly="false"/> <library name="ewsgi" location="..\library\server\ewsgi\ewsgi-safe.ecf" readonly="false"/> + <library name="ex_filter" location="..\examples\filter\filter-safe.ecf" readonly="false"/> + <library name="ex_restbuck" location="..\examples\restbucksCRUD\restbucks-safe.ecf" readonly="false"/> + <library name="ex_simple" location="..\examples\simple\simple.ecf" readonly="false"/> <library name="http" location="..\library\network\protocol\http\http-safe.ecf" readonly="false"/> <library name="http_authorization" location="..\library\server\authentication\http_authorization\http_authorization-safe.ecf" readonly="false"/> <library name="http_client" location="..\library\network\http_client\http_client-safe.ecf" readonly="false"/> <library name="thread" location="$ISE_LIBRARY\library\thread\thread-safe.ecf"/> <library name="wsf" location="..\library\server\wsf\wsf-safe.ecf" readonly="false"/> - <library name="ewf_support" location="..\library\server\ewf_support\ewf_support-safe.ecf" readonly="false"/> + <library name="wsf_connector_nino" location="..\library\server\wsf\connector\nino-safe.ecf" readonly="false"/> + <library name="wsf_connector_openshift" location="..\library\server\wsf\connector\openshift-safe.ecf" readonly="false"/> <library name="wsf_extension" location="..\library\server\wsf\wsf_extension-safe.ecf" readonly="false"/> - <library name="wsf_session" location="..\library\server\wsf\wsf_session-safe.ecf" readonly="false"/> <library name="wsf_router_context" location="..\library\server\wsf\wsf_router_context-safe.ecf" readonly="false"/> - <library name="ex_restbuck" location="..\examples\restbucksCRUD\restbucks-safe.ecf" readonly="false"/> - <library name="ex_simple" location="..\examples\simple\simple.ecf" readonly="false"/> - <library name="ex_filter" location="..\examples\filter\filter-safe.ecf" readonly="false"/> - <library name="cms" location="..\draft\application\cms\cms-safe.ecf" readonly="false"/> - <library name="css" location="..\draft\library\text\css\css-safe.ecf" readonly="false"/> + <library name="wsf_session" location="..\library\server\wsf\wsf_session-safe.ecf" readonly="false"/> </target> <target name="all_windows" extends="all"> <description>Compiling as Windows , on other platforms than Windows</description> @@ -49,5 +49,4 @@ <root all_classes="true"/> <setting name="platform" value="unix"/> </target> - </system> From 7c6980860c606faabc00dc64d7163d077a7e23e4 Mon Sep 17 00:00:00 2001 From: Colin Adams <colinpauladams@gmail.com> Date: Tue, 26 Mar 2013 17:10:09 +0000 Subject: [PATCH 14/19] merging from upstream - stage 2 --- tests/all-safe.ecf | 53 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 tests/all-safe.ecf diff --git a/tests/all-safe.ecf b/tests/all-safe.ecf new file mode 100644 index 00000000..0cb7a441 --- /dev/null +++ b/tests/all-safe.ecf @@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-10-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-10-0 http://www.eiffel.com/developers/xml/configuration-1-10-0.xsd" name="all" uuid="1172C52C-6979-4293-8F01-80FADA5A2B69"> + <description>compile many lib from EWF</description> + <target name="all"> + <root all_classes="true"/> + <file_rule> + <exclude>/.git$</exclude> + <exclude>/EIFGENs$</exclude> + <exclude>/.svn$</exclude> + </file_rule> + <option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="standard"> + </option> + <library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/> + <library name="connector_cgi" location="..\library\server\ewsgi\connectors\cgi\cgi-safe.ecf" readonly="false"/> + <library name="connector_libfcgi" location="..\library\server\ewsgi\connectors\libfcgi\libfcgi-safe.ecf" readonly="false"/> + <library name="connector_nino" location="..\library\server\ewsgi\connectors\nino\nino-safe.ecf" readonly="false"/> + <library name="connector_null" location="..\library\server\ewsgi\connectors\null\null-safe.ecf" readonly="false"/> + <library name="encoder" location="..\library\text\encoder\encoder-safe.ecf" readonly="false"/> + <library name="wsf_connector_nino" location="..\library\server\wsf\connector\nino-safe.ecf" readonly="false"/> + <library name="wsf_connector_openshift" location="..\library\server\wsf\connector\openshift-safe.ecf" readonly="false"/> + <library name="dft_connector_libfcgi" location="..\library\server\wsf\default\libfcgi-safe.ecf" readonly="false"/> + <library name="dft_connector_cgi" location="..\library\server\wsf\default\cgi-safe.ecf" readonly="false"/> + <library name="dft_connector_nino" location="..\library\server\wsf\default\nino-safe.ecf" readonly="false"/> + <library name="dft_connector_openshift" location="..\library\server\wsf\default\openshift-safe.ecf" readonly="false"/> + <library name="conneg" location="../library/network/protocol/CONNEG/conneg-safe.ecf" readonly="false"/> + <library name="ewsgi" location="..\library\server\ewsgi\ewsgi-safe.ecf" readonly="false"/> + <library name="http" location="..\library\network\protocol\http\http-safe.ecf" readonly="false"/> + <library name="http_authorization" location="..\library\server\authentication\http_authorization\http_authorization-safe.ecf" readonly="false"/> + <library name="http_client" location="..\library\network\http_client\http_client-safe.ecf" readonly="false"/> + <library name="thread" location="$ISE_LIBRARY\library\thread\thread-safe.ecf"/> + <library name="wsf" location="..\library\server\wsf\wsf-safe.ecf" readonly="false"/> + <library name="ewf_support" location="..\library\server\ewf_support\ewf_support-safe.ecf" readonly="false"/> + <library name="wsf_extension" location="..\library\server\wsf\wsf_extension-safe.ecf" readonly="false"/> + <library name="wsf_session" location="..\library\server\wsf\wsf_session-safe.ecf" readonly="false"/> + <library name="wsf_router_context" location="..\library\server\wsf\wsf_router_context-safe.ecf" readonly="false"/> + <library name="ex_restbuck" location="..\examples\restbucksCRUD\restbucks-safe.ecf" readonly="false"/> + <library name="ex_simple" location="..\examples\simple\simple.ecf" readonly="false"/> + <library name="ex_filter" location="..\examples\filter\filter-safe.ecf" readonly="false"/> + <library name="cms" location="..\draft\application\cms\cms-safe.ecf" readonly="false"/> + <library name="wsf_html" location="..\library\server\wsf_html\wsf_html-safe.ecf" readonly="false"/> + </target> + <target name="all_windows" extends="all"> + <description>Compiling as Windows , on other platforms than Windows</description> + <root all_classes="true"/> + <setting name="platform" value="windows"/> + </target> + <target name="all_unix" extends="all"> + <description>Compiling as UNIX , on other platforms than Unix</description> + <root all_classes="true"/> + <setting name="platform" value="unix"/> + </target> + +</system> From 0507a1d34738b4c8e723e4e5beac23a45f95822b Mon Sep 17 00:00:00 2001 From: Colin Adams <colinpauladams@gmail.com> Date: Tue, 26 Mar 2013 17:19:04 +0000 Subject: [PATCH 15/19] merging from upstream - stage 3 --- library/server/wsf/wsf-safe.ecf | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 library/server/wsf/wsf-safe.ecf diff --git a/library/server/wsf/wsf-safe.ecf b/library/server/wsf/wsf-safe.ecf new file mode 100644 index 00000000..95a12d0c --- /dev/null +++ b/library/server/wsf/wsf-safe.ecf @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-11-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-11-0 http://www.eiffel.com/developers/xml/configuration-1-11-0.xsd" name="wsf" uuid="A37CE5AA-4D2A-4441-BC6A-0A1D7EC49647" library_target="wsf"> + <target name="wsf"> + <root all_classes="true"/> + <file_rule> + <exclude>/.git$</exclude> + <exclude>/EIFGENs$</exclude> + <exclude>/.svn$</exclude> + </file_rule> + <option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="provisional"> + </option> + <library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/> + <library name="base_extension" location="$ISE_LIBRARY\library\base_extension\base_extension-safe.ecf"/> + <library name="encoder" location="..\..\text\encoder\encoder-safe.ecf"/> + <library name="error" location="..\..\utility\general\error\error-safe.ecf"/> + <library name="ewsgi" location="..\ewsgi\ewsgi-safe.ecf"/> + <library name="http" location="..\..\network\protocol\http\http-safe.ecf"/> + <library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/> + <library name="uri_template" location="..\..\text\parser\uri_template\uri_template-safe.ecf"/> + <cluster name="router" location=".\router\" recursive="true"/> + <cluster name="src" location=".\src\" recursive="true"/> + </target> +</system> From 8ebaf2a917f4b90453ade2d2d1e3bac288675ffe Mon Sep 17 00:00:00 2001 From: Colin Adams <colinpauladams@gmail.com> Date: Tue, 26 Mar 2013 17:33:50 +0000 Subject: [PATCH 16/19] merging from upstream - stage 4 --- library/server/wsf/wsf-safe.ecf | 3 ++- tests/all-safe.ecf | 25 ++++++++++++------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/library/server/wsf/wsf-safe.ecf b/library/server/wsf/wsf-safe.ecf index 95a12d0c..4fb23bbf 100644 --- a/library/server/wsf/wsf-safe.ecf +++ b/library/server/wsf/wsf-safe.ecf @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="ISO-8859-1"?> -<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-11-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-11-0 http://www.eiffel.com/developers/xml/configuration-1-11-0.xsd" name="wsf" uuid="A37CE5AA-4D2A-4441-BC6A-0A1D7EC49647" library_target="wsf"> +<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-10-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-10-0 http://www.eiffel.com/developers/xml/configuration-1-10-0.xsd" name="wsf" uuid="A37CE5AA-4D2A-4441-BC6A-0A1D7EC49647" library_target="wsf"> <target name="wsf"> <root all_classes="true"/> <file_rule> @@ -16,6 +16,7 @@ <library name="ewsgi" location="..\ewsgi\ewsgi-safe.ecf"/> <library name="http" location="..\..\network\protocol\http\http-safe.ecf"/> <library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/> + <library name="uri" location="$ISE_LIBRARY\library\text\uri\uri-safe.ecf"/> <library name="uri_template" location="..\..\text\parser\uri_template\uri_template-safe.ecf"/> <cluster name="router" location=".\router\" recursive="true"/> <cluster name="src" location=".\src\" recursive="true"/> diff --git a/tests/all-safe.ecf b/tests/all-safe.ecf index 0cb7a441..ad0bc048 100644 --- a/tests/all-safe.ecf +++ b/tests/all-safe.ecf @@ -11,33 +11,33 @@ <option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="standard"> </option> <library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/> + <library name="cms" location="..\draft\application\cms\cms-safe.ecf" readonly="false"/> <library name="connector_cgi" location="..\library\server\ewsgi\connectors\cgi\cgi-safe.ecf" readonly="false"/> <library name="connector_libfcgi" location="..\library\server\ewsgi\connectors\libfcgi\libfcgi-safe.ecf" readonly="false"/> <library name="connector_nino" location="..\library\server\ewsgi\connectors\nino\nino-safe.ecf" readonly="false"/> <library name="connector_null" location="..\library\server\ewsgi\connectors\null\null-safe.ecf" readonly="false"/> - <library name="encoder" location="..\library\text\encoder\encoder-safe.ecf" readonly="false"/> - <library name="wsf_connector_nino" location="..\library\server\wsf\connector\nino-safe.ecf" readonly="false"/> - <library name="wsf_connector_openshift" location="..\library\server\wsf\connector\openshift-safe.ecf" readonly="false"/> - <library name="dft_connector_libfcgi" location="..\library\server\wsf\default\libfcgi-safe.ecf" readonly="false"/> + <library name="conneg" location="..\library\network\protocol\CONNEG\conneg-safe.ecf" readonly="false"/> <library name="dft_connector_cgi" location="..\library\server\wsf\default\cgi-safe.ecf" readonly="false"/> + <library name="dft_connector_libfcgi" location="..\library\server\wsf\default\libfcgi-safe.ecf" readonly="false"/> <library name="dft_connector_nino" location="..\library\server\wsf\default\nino-safe.ecf" readonly="false"/> <library name="dft_connector_openshift" location="..\library\server\wsf\default\openshift-safe.ecf" readonly="false"/> - <library name="conneg" location="../library/network/protocol/CONNEG/conneg-safe.ecf" readonly="false"/> + <library name="encoder" location="..\library\text\encoder\encoder-safe.ecf" readonly="false"/> + <library name="ewf_support" location="..\library\server\ewf_support\ewf_support-safe.ecf" readonly="false"/> <library name="ewsgi" location="..\library\server\ewsgi\ewsgi-safe.ecf" readonly="false"/> + <library name="ex_filter" location="..\examples\filter\filter-safe.ecf" readonly="false"/> + <library name="ex_restbuck" location="..\examples\restbucksCRUD\restbucks-safe.ecf" readonly="false"/> + <library name="ex_simple" location="..\examples\simple\simple.ecf" readonly="false"/> <library name="http" location="..\library\network\protocol\http\http-safe.ecf" readonly="false"/> <library name="http_authorization" location="..\library\server\authentication\http_authorization\http_authorization-safe.ecf" readonly="false"/> <library name="http_client" location="..\library\network\http_client\http_client-safe.ecf" readonly="false"/> <library name="thread" location="$ISE_LIBRARY\library\thread\thread-safe.ecf"/> <library name="wsf" location="..\library\server\wsf\wsf-safe.ecf" readonly="false"/> - <library name="ewf_support" location="..\library\server\ewf_support\ewf_support-safe.ecf" readonly="false"/> + <library name="wsf_connector_nino" location="..\library\server\wsf\connector\nino-safe.ecf" readonly="false"/> + <library name="wsf_connector_openshift" location="..\library\server\wsf\connector\openshift-safe.ecf" readonly="false"/> <library name="wsf_extension" location="..\library\server\wsf\wsf_extension-safe.ecf" readonly="false"/> - <library name="wsf_session" location="..\library\server\wsf\wsf_session-safe.ecf" readonly="false"/> - <library name="wsf_router_context" location="..\library\server\wsf\wsf_router_context-safe.ecf" readonly="false"/> - <library name="ex_restbuck" location="..\examples\restbucksCRUD\restbucks-safe.ecf" readonly="false"/> - <library name="ex_simple" location="..\examples\simple\simple.ecf" readonly="false"/> - <library name="ex_filter" location="..\examples\filter\filter-safe.ecf" readonly="false"/> - <library name="cms" location="..\draft\application\cms\cms-safe.ecf" readonly="false"/> <library name="wsf_html" location="..\library\server\wsf_html\wsf_html-safe.ecf" readonly="false"/> + <library name="wsf_router_context" location="..\library\server\wsf\wsf_router_context-safe.ecf" readonly="false"/> + <library name="wsf_session" location="..\library\server\wsf\wsf_session-safe.ecf" readonly="false"/> </target> <target name="all_windows" extends="all"> <description>Compiling as Windows , on other platforms than Windows</description> @@ -49,5 +49,4 @@ <root all_classes="true"/> <setting name="platform" value="unix"/> </target> - </system> From 8c5400915d637af274af47a4a4395c5663539837 Mon Sep 17 00:00:00 2001 From: Colin Adams <colinpauladams@gmail.com> Date: Wed, 27 Mar 2013 10:28:20 +0000 Subject: [PATCH 17/19] openid demo fixed --- library/security/openid/consumer/demo/application.e | 10 +++++++++- library/server/wsf/router/wsf_routed_service.e | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/library/security/openid/consumer/demo/application.e b/library/security/openid/consumer/demo/application.e index 542f101a..c92a7146 100644 --- a/library/security/openid/consumer/demo/application.e +++ b/library/security/openid/consumer/demo/application.e @@ -7,10 +7,18 @@ class APPLICATION inherit - WSF_URI_TEMPLATE_ROUTED_SERVICE + + WSF_ROUTED_SKELETON_SERVICE + undefine + requires_proxy + end + + WSF_URI_TEMPLATE_HELPER_FOR_ROUTED_SERVICE WSF_SERVICE + WSF_NO_PROXY_POLICY + create make_and_launch diff --git a/library/server/wsf/router/wsf_routed_service.e b/library/server/wsf/router/wsf_routed_service.e index 9c112317..7526088a 100644 --- a/library/server/wsf/router/wsf_routed_service.e +++ b/library/server/wsf/router/wsf_routed_service.e @@ -50,7 +50,7 @@ feature -- Execution end ensure response_status_is_set: res.status_is_set - header_sent: res.header_committed and res.message_committed + header_sent: res.header_committed end execute_default (req: WSF_REQUEST; res: WSF_RESPONSE) From 4875ca9ff1c87e925976304c42f20053fd537484 Mon Sep 17 00:00:00 2001 From: Colin Adams <colinpauladams@gmail.com> Date: Wed, 27 Mar 2013 14:44:14 +0000 Subject: [PATCH 18/19] now all-safe.ecf compiles again --- examples/upload_image/src/image_uploader.e | 9 ++- tests/all-safe.ecf | 74 ++++++++++++++++++++++ 2 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 tests/all-safe.ecf diff --git a/examples/upload_image/src/image_uploader.e b/examples/upload_image/src/image_uploader.e index 7e190261..87c03aeb 100644 --- a/examples/upload_image/src/image_uploader.e +++ b/examples/upload_image/src/image_uploader.e @@ -10,11 +10,14 @@ class inherit ANY - WSF_ROUTED_SERVICE + WSF_ROUTED_SKELETON_SERVICE + undefine + requires_proxy + end - WSF_URI_TEMPLATE_ROUTED_SERVICE + WSF_URI_TEMPLATE_HELPER_FOR_ROUTED_SERVICE - WSF_URI_ROUTED_SERVICE + WSF_NO_PROXY_POLICY WSF_DEFAULT_SERVICE diff --git a/tests/all-safe.ecf b/tests/all-safe.ecf new file mode 100644 index 00000000..6d973ec5 --- /dev/null +++ b/tests/all-safe.ecf @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-10-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-10-0 http://www.eiffel.com/developers/xml/configuration-1-10-0.xsd" name="all" uuid="1172C52C-6979-4293-8F01-80FADA5A2B69"> + <description>Integration project including many lib</description> + <target name="all"> + <root all_classes="true"/> + <file_rule> + <exclude>/.git$</exclude> + <exclude>/EIFGENs$</exclude> + <exclude>/.svn$</exclude> + </file_rule> + <option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="standard"> + </option> + <library name="curl" location="..\contrib\ise_library\cURL-safe.ecf" readonly="false"/> + <library name="curl-1" location="..\contrib\ise_library\cURL\cURL-safe.ecf" readonly="false"/> + <library name="uri" location="..\contrib\ise_library\text\uri\uri-safe.ecf" readonly="false"/> + <library name="nino" location="..\contrib\library\network\server\nino\nino-safe.ecf" readonly="false"/> + <library name="json" location="..\contrib\library\text\parser\json\library\json-safe.ecf" readonly="false"/> + <library name="cms" location="..\draft\application\cms\cms-safe.ecf" readonly="false"/> + <library name="demo" location="..\draft\application\cms\example\cms_demo-safe.ecf" readonly="false"/> + <library name="atom" location="..\draft\library\protocol\syndication\atom\atom-safe.ecf" readonly="false"/> + <library name="rss" location="..\draft\library\protocol\syndication\rss\rss-safe.ecf" readonly="false"/> + <library name="oauth" location="..\draft\library\security\oauth\oauth-safe.ecf" readonly="false"/> + <library name="filter" location="..\examples\filter\filter-safe.ecf" readonly="false"/> + <library name="restbucks" location="..\examples\restbucksCRUD\restbucks-safe.ecf" readonly="false"/> + <library name="client" location="..\examples\restbucksCRUD\client\client-safe.ecf" readonly="false"/> + <library name="upload_image" location="..\examples\upload_image\upload_image-safe.ecf" readonly="false"/> + <library name="http_client" location="..\library\network\http_client\http_client-safe.ecf" readonly="false"/> + <library name="conneg" location="..\library\network\protocol\CONNEG\conneg-safe.ecf" readonly="false"/> + <library name="http" location="..\library\network\protocol\http\http-safe.ecf" readonly="false"/> + <library name="openid" location="..\library\security\openid\consumer\openid-safe.ecf" readonly="false"/> + <library name="demo-1" location="..\library\security\openid\consumer\demo\demo-safe.ecf" readonly="false"/> + <library name="http_authorization" location="..\library\server\authentication\http_authorization\http_authorization-safe.ecf" readonly="false"/> + <library name="ewf_support" location="..\library\server\ewf_support\ewf_support-safe.ecf" readonly="false"/> + <library name="ewsgi" location="..\library\server\ewsgi\ewsgi-safe.ecf" readonly="false"/> + <library name="ewsgi_spec" location="..\library\server\ewsgi\ewsgi_spec-safe.ecf" readonly="false"/> + <library name="connector_cgi" location="..\library\server\ewsgi\connectors\cgi\cgi-safe.ecf" readonly="false"/> + <library name="connector_libfcgi" location="..\library\server\ewsgi\connectors\libfcgi\libfcgi-safe.ecf" readonly="false"/> + <library name="connector_nino" location="..\library\server\ewsgi\connectors\nino\nino-safe.ecf" readonly="false"/> + <library name="connector_null" location="..\library\server\ewsgi\connectors\null\null-safe.ecf" readonly="false"/> + <library name="hello_world" location="..\library\server\ewsgi\examples\hello_world\hello-safe.ecf" readonly="false"/> + <library name="libfcgi" location="..\library\server\libfcgi\libfcgi-safe.ecf" readonly="false"/> + <library name="wsf" location="..\library\server\wsf\wsf-safe.ecf" readonly="false"/> + <library name="wsf_extension" location="..\library\server\wsf\wsf_extension-safe.ecf" readonly="false"/> + <library name="wsf_router_context" location="..\library\server\wsf\wsf_router_context-safe.ecf" readonly="false"/> + <library name="wsf_session" location="..\library\server\wsf\wsf_session-safe.ecf" readonly="false"/> + <library name="wsf_all" location="..\library\server\wsf\connector\all-safe.ecf" readonly="false"/> + <library name="wsf_cgi" location="..\library\server\wsf\connector\cgi-safe.ecf" readonly="false"/> + <library name="wsf_libfcgi" location="..\library\server\wsf\connector\libfcgi-safe.ecf" readonly="false"/> + <library name="wsf_nino" location="..\library\server\wsf\connector\nino-safe.ecf" readonly="false"/> + <library name="wsf_openshift" location="..\library\server\wsf\connector\openshift-safe.ecf" readonly="false"/> + <library name="default_cgi" location="..\library\server\wsf\default\cgi-safe.ecf" readonly="false"/> + <library name="default_libfcgi" location="..\library\server\wsf\default\libfcgi-safe.ecf" readonly="false"/> + <library name="default_nino" location="..\library\server\wsf\default\nino-safe.ecf" readonly="false"/> + <library name="default_openshift" location="..\library\server\wsf\default\openshift-safe.ecf" readonly="false"/> + <library name="wsf_html" location="..\library\server\wsf_html\wsf_html-safe.ecf" readonly="false"/> + <library name="encoder" location="..\library\text\encoder\encoder-safe.ecf" readonly="false"/> + <library name="uri_template" location="..\library\text\parser\uri_template\uri_template-safe.ecf" readonly="false"/> + <library name="error" location="..\library\utility\general\error\error-safe.ecf" readonly="false"/> + <library name="precomp_wsf-mt" location="..\precomp\wsf-mt-safe.ecf" readonly="false"/> + <library name="precomp_wsf" location="..\precomp\wsf-safe.ecf" readonly="false"/> + <library name="precomp_wsf-scoop-safe" location="..\precomp\wsf-scoop-safe.ecf" readonly="false"/> + <library name="wizard" location="..\tools\ise_wizard\ewf_ise_wizard-safe.ecf" readonly="false"/> + </target> + <target name="all_windows" extends="all"> + <description>Compiling as Windows , on other platforms than Windows</description> + <root all_classes="true"/> + <setting name="platform" value="windows"/> + </target> + <target name="all_unix" extends="all"> + <description>Compiling as UNIX , on other platforms than Unix</description> + <root all_classes="true"/> + <setting name="platform" value="unix"/> + </target> +</system> From 5249275b23b39de0834b8d342cb99838c3deda78 Mon Sep 17 00:00:00 2001 From: Colin Adams <colinpauladams@gmail.com> Date: Wed, 27 Mar 2013 15:38:13 +0000 Subject: [PATCH 19/19] Further changes in response to review comments by Jocelyn --- .../helpers/wsf_uri_template_routed_service.e | 27 ++++++++ .../helpers/wsf_uri_template_router_helper.e | 68 +++++++++++++++++++ .../wsf/router/wsf_routed_skeleton_service.e | 14 ++-- .../wsf_method_not_allowed_response.e | 46 +++++++------ 4 files changed, 128 insertions(+), 27 deletions(-) create mode 100644 library/server/wsf/router/support/uri_template/helpers/wsf_uri_template_routed_service.e create mode 100644 library/server/wsf/router/support/uri_template/helpers/wsf_uri_template_router_helper.e 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 new file mode 100644 index 00000000..8db2b0e0 --- /dev/null +++ b/library/server/wsf/router/support/uri_template/helpers/wsf_uri_template_routed_service.e @@ -0,0 +1,27 @@ +note + description: "Summary description for {WSF_URI_TEMPLATE_ROUTED_SERVICE}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + WSF_URI_TEMPLATE_ROUTED_SERVICE + +obsolete "Inherit from WSF_ROUTED_SERVICE and WSF_URI_ROUTER_HELPER [2013-mar-19]" + +inherit + WSF_ROUTED_SERVICE + + WSF_URI_TEMPLATE_ROUTER_HELPER + +note + copyright: "2011-2013, 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/support/uri_template/helpers/wsf_uri_template_router_helper.e b/library/server/wsf/router/support/uri_template/helpers/wsf_uri_template_router_helper.e new file mode 100644 index 00000000..b1db35ad --- /dev/null +++ b/library/server/wsf/router/support/uri_template/helpers/wsf_uri_template_router_helper.e @@ -0,0 +1,68 @@ +note + description: "Summary description for {WSF_URI_TEMPLATE_ROUTER_HELPER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + WSF_URI_TEMPLATE_ROUTER_HELPER + + obsolete "Use class WSF_URI_TEMPLATE_HELPER_FOR_ROUTED_SERVICE in conjunction with WSF_ROUTED_SKELETON_SERVICE" + +feature -- Access + + router: WSF_ROUTER + deferred + end + +feature -- Mapping helper: uri + + map_uri_template (a_tpl: STRING; h: WSF_URI_TEMPLATE_HANDLER) + -- Map `h' as handler for `a_tpl' + require + a_tpl_attached: a_tpl /= Void + h_attached: h /= Void + do + 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_REQUEST_METHODS) + -- Map `h' as handler for `a_tpl' for request methods `rqst_methods'. + require + a_tpl_attached: a_tpl /= Void + h_attached: h /= Void + do + router.map_with_request_methods (create {WSF_URI_TEMPLATE_MAPPING}.make (a_tpl, h), rqst_methods) + end + +feature -- Mapping helper: uri agent + + map_uri_template_agent (a_tpl: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [req: WSF_REQUEST; res: WSF_RESPONSE]]) + -- Map `proc' as handler for `a_tpl' + require + a_tpl_attached: a_tpl /= Void + proc_attached: proc /= Void + 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_REQUEST_METHODS) + -- Map `proc' as handler for `a_tpl' for request methods `rqst_methods'. + require + a_tpl_attached: a_tpl /= Void + proc_attached: proc /= Void + do + map_uri_template_with_request_methods (a_tpl, create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (proc), rqst_methods) + end + +note + copyright: "2011-2013, 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_skeleton_service.e b/library/server/wsf/router/wsf_routed_skeleton_service.e index 9aff9444..6253c8cd 100644 --- a/library/server/wsf/router/wsf_routed_skeleton_service.e +++ b/library/server/wsf/router/wsf_routed_skeleton_service.e @@ -22,6 +22,8 @@ feature -- Execution execute (req: WSF_REQUEST; res: WSF_RESPONSE) -- If the service is available, and request URI is not too long, dispatch the request -- and if handler is not found, execute the default procedure `execute_default'. + local + l_sess: WSF_ROUTER_SESSION do --| When we reach here, the request has already passed check for 400 (Bad request), --| which is implemented in WSF_REQUEST.make_from_wgi (when it calls `analyze'). @@ -34,10 +36,12 @@ feature -- Execution elseif req.is_request_method ({HTTP_REQUEST_METHODS}.method_options) and then req.request_uri.same_string ("*") then handle_server_options (req, res) - elseif attached router.dispatch_and_return_handler (req, res) as p then - -- executed else - execute_default (req, res) + create l_sess + router.dispatch (req, res, l_sess) + if not l_sess.dispatched then + execute_default (req, res) + end end end @@ -180,7 +184,7 @@ feature {NONE} -- Implementation frozen handle_system_options_forbidden (req: WSF_REQUEST; res: WSF_RESPONSE) -- Write a 403 Forbidden or a 404 Not found response into `res'. - require + require req_attached: req /= Void res_attached: res /= Void method_is_options: req.is_request_method ({HTTP_REQUEST_METHODS}.method_options) @@ -217,7 +221,7 @@ feature {NONE} -- Implementation handle_system_options (req: WSF_REQUEST; res: WSF_RESPONSE) -- Write response to OPTIONS * into `res'. -- This may be redefined by the user, but normally this will not be necessary. - require + require req_attached: req /= Void res_attached: res /= Void method_is_options: req.is_request_method ({HTTP_REQUEST_METHODS}.method_options) 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 ee8a6b8b..4b1b580c 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 @@ -82,17 +82,18 @@ feature {WSF_RESPONSE} -- Output l_text: detachable READABLE_STRING_GENERAL l_loc: detachable READABLE_STRING_8 h: like header - l_recognized: BOOLEAN + --l_recognized: BOOLEAN l_messages: HTTP_STATUS_CODE_MESSAGES do create l_messages h := header - l_recognized := recognized_methods.has (request.request_method.as_upper) - if l_recognized then - res.set_status_code (l_messages.method_not_allowed) - else - res.set_status_code (l_messages.not_implemented) - end + -- To be considered later + --l_recognized := recognized_methods.has (request.request_method.as_upper) + --if l_recognized then + res.set_status_code (l_messages.method_not_allowed) + --else + -- res.set_status_code (l_messages.not_implemented) + --end if attached suggested_methods as lst and then not lst.is_empty then h.put_allow (lst) @@ -109,7 +110,7 @@ feature {WSF_RESPONSE} -- Output s := "Bug in server" end - l_html_error_code_text := html_error_code_text (l_messages, l_recognized) + l_html_error_code_text := html_error_code_text (l_messages, True) if request.is_content_type_accepted ({HTTP_MIME_TYPES}.text_html) then s := "<html lang=%"en%"><head>" @@ -262,23 +263,24 @@ feature {WSF_RESPONSE} -- Output feature {NONE} -- Implementation - recognized_methods: WSF_REQUEST_METHODS + -- To be discussed later... + --recognized_methods: WSF_REQUEST_METHODS -- All methods defined in HTTP/1.1 specification --| Should this include CONNECT? It probably shouldn't be recognized by an origin server, --| We will need a way to extend this for additional methods that the server implements. E.g. PATCH. - do - create Result.make_from_iterable (<< - {HTTP_REQUEST_METHODS}.method_head, - {HTTP_REQUEST_METHODS}.method_get, - {HTTP_REQUEST_METHODS}.method_trace, - {HTTP_REQUEST_METHODS}.method_options, - {HTTP_REQUEST_METHODS}.method_post, - {HTTP_REQUEST_METHODS}.method_put, - {HTTP_REQUEST_METHODS}.method_delete - >>) - ensure - recognized_methods_not_void: Result /= Void - end + -- do + -- create Result.make_from_iterable (<< + -- {HTTP_REQUEST_METHODS}.method_head, + -- {HTTP_REQUEST_METHODS}.method_get, + -- {HTTP_REQUEST_METHODS}.method_trace, + -- {HTTP_REQUEST_METHODS}.method_options, + -- {HTTP_REQUEST_METHODS}.method_post, + -- {HTTP_REQUEST_METHODS}.method_put, + -- {HTTP_REQUEST_METHODS}.method_delete + -- >>) + -- ensure + -- recognized_methods_not_void: Result /= Void + -- end html_error_code_text (a_messages: HTTP_STATUS_CODE_MESSAGES; a_recognized: BOOLEAN): READABLE_STRING_8 -- Message for including in HTML error text according to `a_recognized'