New ROUTER design, much simpler, less generic, easier to extend, and now one can mix uri map, uri_template map and so on.
Update the "tutorial" example.
This commit is contained in:
@@ -13,7 +13,7 @@ class
|
||||
HELLO_APPLICATION
|
||||
|
||||
inherit
|
||||
WSF_URI_TEMPLATE_ROUTED_SERVICE
|
||||
WSF_ROUTED_SERVICE
|
||||
|
||||
WSF_DEFAULT_SERVICE
|
||||
redefine
|
||||
@@ -27,12 +27,34 @@ feature {NONE} -- Initialization
|
||||
|
||||
setup_router
|
||||
do
|
||||
router.map_agent ("/hello", agent execute_hello)
|
||||
-- router.map (create {WSF_URI_MAPPING}.make ("/hello", create {WSF_AGENT_URI_HANDLER}.make (agent execute_hello)))
|
||||
map_agent_uri ("/hello", agent execute_hello, Void)
|
||||
|
||||
router.map_with_request_methods ("/users/{user}/message/{mesgid}", create {USER_MESSAGE_HANDLER}, router.methods_HEAD_GET_POST)
|
||||
router.map_with_request_methods ("/users/{user}/message/", create {USER_MESSAGE_HANDLER}, router.methods_GET_POST)
|
||||
-- router.map_with_request_methods (create {WSF_URI_TEMPLATE_MAPPING}.make ("/users/{user}/message/{mesgid}", create {USER_MESSAGE_HANDLER}), router.methods_HEAD_GET_POST)
|
||||
map_uri_template ("/users/{user}/message/{mesgid}", create {USER_MESSAGE_HANDLER}, router.methods_HEAD_GET_POST)
|
||||
|
||||
router.map_agent_response_with_request_methods ("/users/{user}/{?op}", agent response_user, router.methods_GET)
|
||||
-- router.map_with_request_methods (create {WSF_URI_TEMPLATE_MAPPING}.make ("/users/{user}/message/", create {USER_MESSAGE_HANDLER}), router.methods_GET_POST)
|
||||
map_uri_template ("/users/{user}/message/", create {USER_MESSAGE_HANDLER}, router.methods_GET_POST)
|
||||
|
||||
-- router.map_with_request_methods (create {WSF_URI_TEMPLATE_MAPPING}.make ("/users/{user}/{?op}", create {WSF_AGENT_URI_TEMPLATE_RESPONSE_HANDLER}.make (agent response_user)), router.methods_GET)
|
||||
map_agent_uri_template_response ("/users/{user}/{?op}", agent response_user, router.methods_GET)
|
||||
end
|
||||
|
||||
feature -- Helper: mapping
|
||||
|
||||
map_agent_uri (a_uri: READABLE_STRING_8; a_action: like {WSF_AGENT_URI_HANDLER}.action; rqst_methods: detachable WSF_ROUTER_METHODS)
|
||||
do
|
||||
router.map_with_request_methods (create {WSF_URI_MAPPING}.make (a_uri, create {WSF_AGENT_URI_HANDLER}.make (a_action)), rqst_methods)
|
||||
end
|
||||
|
||||
map_uri_template (a_tpl: READABLE_STRING_8; a_handler: WSF_URI_TEMPLATE_HANDLER; rqst_methods: detachable WSF_ROUTER_METHODS)
|
||||
do
|
||||
router.map_with_request_methods (create {WSF_URI_TEMPLATE_MAPPING}.make (a_tpl, a_handler), rqst_methods)
|
||||
end
|
||||
|
||||
map_agent_uri_template_response (a_tpl: READABLE_STRING_8; a_action: like {WSF_AGENT_URI_TEMPLATE_RESPONSE_HANDLER}.action; rqst_methods: detachable WSF_ROUTER_METHODS)
|
||||
do
|
||||
router.map_with_request_methods (create {WSF_URI_TEMPLATE_MAPPING}.make (a_tpl, create {WSF_AGENT_URI_TEMPLATE_RESPONSE_HANDLER}.make (a_action)), rqst_methods)
|
||||
end
|
||||
|
||||
feature -- Execution
|
||||
@@ -43,7 +65,7 @@ feature -- Execution
|
||||
res.redirect_now_with_content (req.script_url ("/hello"), "Redirection to " + req.script_url ("/hello"), "text/html")
|
||||
end
|
||||
|
||||
execute_hello (ctx: WSF_URI_TEMPLATE_HANDLER_CONTEXT; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
execute_hello (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Computed response message.
|
||||
local
|
||||
mesg: WSF_HTML_PAGE_RESPONSE
|
||||
@@ -107,8 +129,9 @@ feature -- Execution
|
||||
then
|
||||
if l_op.is_case_insensitive_equal ("quit") then
|
||||
create redir.make (req.script_url ("/hello"), 3)
|
||||
redir.set_title ("Bye " + u.url_encoded_value)
|
||||
redir.set_body ("Bye " + u.url_encoded_value + ",<br/> see you soon.<p>You will be redirected to " +
|
||||
create html.make
|
||||
redir.set_title ("Bye " + html.html_encoded_string (l_username))
|
||||
redir.set_body ("Bye " + html.html_encoded_string (l_username) + ",<br/> see you soon.<p>You will be redirected to " +
|
||||
redir.url_location + " in " + redir.delay.out + " second(s) ...</p>"
|
||||
)
|
||||
Result := redir
|
||||
|
||||
@@ -9,7 +9,7 @@ class
|
||||
USER_MESSAGE_HANDLER
|
||||
|
||||
inherit
|
||||
WSF_RESPONSE_HANDLER [WSF_URI_TEMPLATE_HANDLER_CONTEXT]
|
||||
WSF_URI_TEMPLATE_RESPONSE_HANDLER
|
||||
|
||||
feature -- Access
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Router
|
||||
|
||||
## Requirements
|
||||
* [URI Template](../../../protocol/rui_template)
|
||||
* [URI Template](../../../protocol/uri_template)
|
||||
|
||||
## Overview
|
||||
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
note
|
||||
description: "Summary description for {DEFAULT_ROUTED_SERVICE}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
WSF_ROUTED_SERVICE
|
||||
|
||||
inherit
|
||||
WSF_ROUTED_SERVICE_I [WSF_HANDLER [WSF_HANDLER_CONTEXT], WSF_HANDLER_CONTEXT]
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, 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
|
||||
@@ -5,12 +5,11 @@ note
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
WSF_ROUTED_SERVICE_I [H -> WSF_HANDLER [C], C -> WSF_HANDLER_CONTEXT]
|
||||
WSF_ROUTED_SERVICE
|
||||
|
||||
feature -- Setup
|
||||
feature -- Initialization
|
||||
|
||||
initialize_router
|
||||
-- Initialize `router'
|
||||
do
|
||||
create_router
|
||||
setup_router
|
||||
@@ -18,7 +17,8 @@ feature -- Setup
|
||||
|
||||
create_router
|
||||
-- Create `router'
|
||||
deferred
|
||||
do
|
||||
create router.make (10)
|
||||
ensure
|
||||
router_created: router /= Void
|
||||
end
|
||||
@@ -30,15 +30,12 @@ feature -- Setup
|
||||
deferred
|
||||
end
|
||||
|
||||
router: WSF_ROUTER [H, C]
|
||||
-- Request router
|
||||
|
||||
feature -- Execution
|
||||
|
||||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
do
|
||||
if attached router.route (req) as r then
|
||||
router.execute_route (r, req, res)
|
||||
if attached router.dispatch_and_return_handler (req, res) as p then
|
||||
-- executed
|
||||
else
|
||||
execute_default (req, res)
|
||||
end
|
||||
@@ -48,7 +45,11 @@ feature -- Execution
|
||||
deferred
|
||||
end
|
||||
|
||||
note
|
||||
feature -- Access
|
||||
|
||||
router: WSF_ROUTER
|
||||
|
||||
;note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
@@ -0,0 +1,19 @@
|
||||
note
|
||||
description: "Summary description for {WSF_STARTS_WITH_HANDLER}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
WSF_STARTS_WITH_HANDLER
|
||||
|
||||
inherit
|
||||
WSF_HANDLER
|
||||
|
||||
feature -- Execution
|
||||
|
||||
execute (a_start_path: READABLE_STRING_8; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
deferred
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,62 @@
|
||||
note
|
||||
description: "Summary description for EWF_URI_PATH."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
WSF_STARTS_WITH_MAPPING
|
||||
|
||||
inherit
|
||||
WSF_ROUTER_MAPPING
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (a_uri: READABLE_STRING_8; h: like handler)
|
||||
do
|
||||
handler := h
|
||||
uri := a_uri
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
handler: WSF_STARTS_WITH_HANDLER
|
||||
|
||||
uri: READABLE_STRING_8
|
||||
|
||||
feature -- Status
|
||||
|
||||
routed_handler (req: WSF_REQUEST; res: WSF_RESPONSE; a_router: WSF_ROUTER): detachable WSF_HANDLER
|
||||
local
|
||||
p: READABLE_STRING_8
|
||||
s: like based_uri
|
||||
do
|
||||
p := source_uri (req)
|
||||
s := based_uri (uri, a_router)
|
||||
if p.starts_with (s) then
|
||||
Result := handler
|
||||
a_router.execute_before (Current)
|
||||
handler.execute (s, req, res)
|
||||
a_router.execute_after (Current)
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
based_uri (a_uri: like uri; a_router: WSF_ROUTER): like uri
|
||||
local
|
||||
s: STRING_8
|
||||
do
|
||||
if attached a_router.base_url as l_base_url then
|
||||
create s.make_from_string (l_base_url)
|
||||
s.append_string (a_uri)
|
||||
Result := s
|
||||
else
|
||||
Result := a_uri
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,50 +0,0 @@
|
||||
note
|
||||
description: "[
|
||||
Default router based on URI map
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
WSF_URI_ROUTER
|
||||
|
||||
inherit
|
||||
WSF_URI_ROUTER_I [WSF_HANDLER [WSF_URI_HANDLER_CONTEXT], WSF_URI_HANDLER_CONTEXT]
|
||||
redefine
|
||||
map_agent_with_request_methods, map_agent_response_with_request_methods
|
||||
end
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Mapping agent
|
||||
|
||||
map_agent_with_request_methods (a_id: READABLE_STRING_8; a_action: PROCEDURE [ANY, TUPLE [ctx: WSF_URI_HANDLER_CONTEXT; req: WSF_REQUEST; res: WSF_RESPONSE]];
|
||||
rqst_methods: detachable WSF_ROUTER_METHODS)
|
||||
local
|
||||
h: WSF_AGENT_HANDLER [WSF_URI_HANDLER_CONTEXT]
|
||||
do
|
||||
create h.make (a_action)
|
||||
map_with_request_methods (a_id, h, rqst_methods)
|
||||
end
|
||||
|
||||
map_agent_response_with_request_methods (a_id: READABLE_STRING_8; a_action: FUNCTION [ANY, TUPLE [ctx: WSF_URI_HANDLER_CONTEXT; req: WSF_REQUEST], WSF_RESPONSE_MESSAGE];
|
||||
rqst_methods: detachable WSF_ROUTER_METHODS)
|
||||
local
|
||||
h: WSF_AGENT_RESPONSE_HANDLER [WSF_URI_HANDLER_CONTEXT]
|
||||
do
|
||||
create h.make (a_action)
|
||||
map_with_request_methods (a_id, h, rqst_methods)
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, 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
|
||||
@@ -1,35 +0,0 @@
|
||||
note
|
||||
description: "[
|
||||
WSF_URI_ROUTING_HANDLER is a default descendant of WSF_URI_ROUTING_HANDLER_I
|
||||
for WSF_URI_ROUTER
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
WSF_URI_ROUTING_HANDLER
|
||||
|
||||
inherit
|
||||
WSF_URI_ROUTING_HANDLER_I [WSF_HANDLER [WSF_URI_HANDLER_CONTEXT], WSF_URI_HANDLER_CONTEXT]
|
||||
redefine
|
||||
router
|
||||
end
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Routing
|
||||
|
||||
router: WSF_URI_ROUTER
|
||||
|
||||
;note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, 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
|
||||
@@ -1,33 +1,35 @@
|
||||
note
|
||||
description: "[
|
||||
This class helps to build Routing handler based for WSF_URI_ROUTER
|
||||
]"
|
||||
description: "Summary description for {WSF_AGENT_HANDLER}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
WSF_URI_ROUTING_HANDLER_I [H -> WSF_HANDLER [C],
|
||||
C -> WSF_URI_HANDLER_CONTEXT create make end]
|
||||
WSF_AGENT_URI_HANDLER
|
||||
|
||||
inherit
|
||||
WSF_ROUTING_HANDLER [H, C]
|
||||
WSF_URI_HANDLER
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (n: INTEGER)
|
||||
make (a_action: like action)
|
||||
do
|
||||
create router.make (n)
|
||||
action := a_action
|
||||
end
|
||||
|
||||
feature {NONE} -- Routing
|
||||
action: PROCEDURE [ANY, TUPLE [request: WSF_REQUEST; response: WSF_RESPONSE]]
|
||||
|
||||
router: WSF_URI_ROUTER_I [H, C]
|
||||
feature -- Execution
|
||||
|
||||
;note
|
||||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
do
|
||||
action.call ([req, res])
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
@@ -1,13 +1,14 @@
|
||||
note
|
||||
description: "Summary description for WSF_AGENT_RESPONSE_HANDLER."
|
||||
description: "Summary description for {WSF_AGENT_URI_TEMPLATE_RESPONSE_HANDLER}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
WSF_AGENT_RESPONSE_HANDLER [C -> WSF_HANDLER_CONTEXT]
|
||||
WSF_AGENT_URI_TEMPLATE_RESPONSE_HANDLER
|
||||
|
||||
inherit
|
||||
WSF_RESPONSE_HANDLER [C]
|
||||
WSF_URI_TEMPLATE_RESPONSE_HANDLER
|
||||
|
||||
create
|
||||
make
|
||||
@@ -21,11 +22,11 @@ feature -- Initialization
|
||||
|
||||
feature -- Access
|
||||
|
||||
action: FUNCTION [ANY, TUPLE [ctx: C; req: WSF_REQUEST], WSF_RESPONSE_MESSAGE]
|
||||
action: FUNCTION [ANY, TUPLE [ctx: WSF_URI_TEMPLATE_HANDLER_CONTEXT; req: WSF_REQUEST], WSF_RESPONSE_MESSAGE]
|
||||
|
||||
feature -- Execution
|
||||
|
||||
response (ctx: C; req: WSF_REQUEST): WSF_RESPONSE_MESSAGE
|
||||
response (ctx: WSF_URI_TEMPLATE_HANDLER_CONTEXT; req: WSF_REQUEST): WSF_RESPONSE_MESSAGE
|
||||
do
|
||||
Result := action.item ([ctx, req])
|
||||
end
|
||||
19
library/server/wsf/router/uri/wsf_uri_handler.e
Normal file
19
library/server/wsf/router/uri/wsf_uri_handler.e
Normal file
@@ -0,0 +1,19 @@
|
||||
note
|
||||
description: "Summary description for {EWF_ROUTER_URI_PATH_HANDLER}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
WSF_URI_HANDLER
|
||||
|
||||
inherit
|
||||
WSF_HANDLER
|
||||
|
||||
feature -- Execution
|
||||
|
||||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
deferred
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,60 +0,0 @@
|
||||
note
|
||||
description: "[
|
||||
Context for the handler execution
|
||||
|
||||
It does not provide additional information compared to {WSF_HANDLER_CONTEXT}
|
||||
- request: WSF_REQUEST -- Associated request
|
||||
- path: READABLE_STRING_8 -- Associated path
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
WSF_URI_HANDLER_CONTEXT
|
||||
|
||||
inherit
|
||||
WSF_HANDLER_CONTEXT
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (req: WSF_REQUEST; p: like path)
|
||||
do
|
||||
request := req
|
||||
path := p
|
||||
end
|
||||
|
||||
feature -- Request data
|
||||
|
||||
apply (req: WSF_REQUEST)
|
||||
-- <Precursor>
|
||||
do
|
||||
end
|
||||
|
||||
revert (req: WSF_REQUEST)
|
||||
-- <Precursor>
|
||||
do
|
||||
end
|
||||
|
||||
feature -- Item
|
||||
|
||||
item (a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE
|
||||
-- Variable value for parameter or variable `a_name'
|
||||
-- See `{WSF_REQUEST}.item(s)'
|
||||
do
|
||||
Result := request.item (a_name)
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, 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
|
||||
80
library/server/wsf/router/uri/wsf_uri_mapping.e
Normal file
80
library/server/wsf/router/uri/wsf_uri_mapping.e
Normal file
@@ -0,0 +1,80 @@
|
||||
note
|
||||
description: "Summary description for EWF_URI_PATH."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
WSF_URI_MAPPING
|
||||
|
||||
inherit
|
||||
WSF_ROUTER_MAPPING
|
||||
|
||||
create
|
||||
make,
|
||||
make_trailing_slash_ignored
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (a_uri: READABLE_STRING_8; h: like handler)
|
||||
do
|
||||
handler := h
|
||||
uri := a_uri
|
||||
end
|
||||
|
||||
make_trailing_slash_ignored (a_uri: READABLE_STRING_8; h: like handler)
|
||||
do
|
||||
make (a_uri, h)
|
||||
trailing_slash_ignored := True
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
handler: WSF_URI_HANDLER
|
||||
|
||||
uri: READABLE_STRING_8
|
||||
|
||||
trailing_slash_ignored: BOOLEAN
|
||||
|
||||
feature -- Status
|
||||
|
||||
routed_handler (req: WSF_REQUEST; res: WSF_RESPONSE; a_router: WSF_ROUTER): detachable WSF_HANDLER
|
||||
local
|
||||
p: READABLE_STRING_8
|
||||
l_uri: like uri
|
||||
do
|
||||
p := source_uri (req)
|
||||
l_uri := based_uri (uri, a_router)
|
||||
if l_uri.ends_with ("/") then
|
||||
if not p.ends_with ("/") then
|
||||
p := p + "/"
|
||||
end
|
||||
else
|
||||
if p.ends_with ("/") then
|
||||
p := p.substring (1, p.count - 1)
|
||||
end
|
||||
end
|
||||
if p.same_string (l_uri) then
|
||||
Result := handler
|
||||
a_router.execute_before (Current)
|
||||
handler.execute (req, res)
|
||||
a_router.execute_after (Current)
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
based_uri (a_uri: like uri; a_router: WSF_ROUTER): like uri
|
||||
local
|
||||
s: STRING_8
|
||||
do
|
||||
if attached a_router.base_url as l_base_url then
|
||||
create s.make_from_string (l_base_url)
|
||||
s.append_string (a_uri)
|
||||
Result := s
|
||||
else
|
||||
Result := a_uri
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
41
library/server/wsf/router/uri/wsf_uri_response_handler.e
Normal file
41
library/server/wsf/router/uri/wsf_uri_response_handler.e
Normal file
@@ -0,0 +1,41 @@
|
||||
note
|
||||
description: "Summary description for {WSF_URI_RESPONSE_HANDLER}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
WSF_URI_RESPONSE_HANDLER
|
||||
|
||||
inherit
|
||||
WSF_URI_HANDLER
|
||||
|
||||
feature -- Response
|
||||
|
||||
response (req: WSF_REQUEST): WSF_RESPONSE_MESSAGE
|
||||
require
|
||||
is_valid_context: is_valid_context (req)
|
||||
deferred
|
||||
ensure
|
||||
Result_attached: Result /= Void
|
||||
end
|
||||
|
||||
feature -- Execution
|
||||
|
||||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Execute request handler
|
||||
do
|
||||
res.send (response (req))
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, 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
|
||||
@@ -1,251 +0,0 @@
|
||||
note
|
||||
description: "[
|
||||
URL dispatcher/router based on simple URI mapping and request methods if precised
|
||||
The associated context {WSF_URI_HANDLER_CONTEXT} does not contains any additional information.
|
||||
|
||||
The matching check if the same path is mapped, or if a substring of the path is mapped
|
||||
|
||||
Examples:
|
||||
|
||||
map ("/users/", users_handler)
|
||||
map_with_request_methods ("/groups/", read_groups_handler, <<"GET">>)
|
||||
map_with_request_methods ("/groups/", write_groups_handler, <<"POST", "PUT", "DELETE">>)
|
||||
map_agent_with_request_methods ("/order/", agent do_get_order, <<"GET">>)
|
||||
map_agent_with_request_methods ("/order/", agent do_post_order, <<"POST">>)
|
||||
|
||||
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
WSF_URI_ROUTER_I [H -> WSF_HANDLER [C], C -> WSF_URI_HANDLER_CONTEXT create make end]
|
||||
|
||||
inherit
|
||||
WSF_ROUTER [H, C]
|
||||
|
||||
create
|
||||
make,
|
||||
make_with_base_url
|
||||
|
||||
feature -- Initialization
|
||||
|
||||
make (n: INTEGER)
|
||||
do
|
||||
create handlers.make (n)
|
||||
handlers.compare_objects
|
||||
initialize
|
||||
end
|
||||
|
||||
make_with_base_url (n: INTEGER; a_base_url: like base_url)
|
||||
-- Make router allocated for at least `n' maps,
|
||||
-- and use `a_base_url' as base_url
|
||||
do
|
||||
make (n)
|
||||
set_base_url (a_base_url)
|
||||
end
|
||||
|
||||
feature {WSF_ROUTED_SERVICE_I} -- Status report
|
||||
|
||||
handlers_matching_map (a_resource: READABLE_STRING_8; rqst_methods: detachable WSF_ROUTER_METHODS): detachable LIST [H]
|
||||
local
|
||||
l_res: READABLE_STRING_8
|
||||
do
|
||||
l_res := based_resource (a_resource)
|
||||
across
|
||||
handlers as c
|
||||
loop
|
||||
if c.item.resource.same_string (l_res) then
|
||||
if
|
||||
rqst_methods = Void or else
|
||||
across rqst_methods as rq some is_matching_request_methods (rq.item, c.item.request_methods) end
|
||||
then
|
||||
if Result = Void then
|
||||
create {ARRAYED_LIST [H]} Result.make (1)
|
||||
end
|
||||
Result.extend (c.item.handler)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feature {WSF_ROUTED_SERVICE_I} -- Default: implementation
|
||||
|
||||
default_handler_context (req: WSF_REQUEST): C
|
||||
-- <Precursor>
|
||||
do
|
||||
Result := handler_context (Void, req)
|
||||
end
|
||||
|
||||
feature -- Registration
|
||||
|
||||
map_with_request_methods (p: READABLE_STRING_8; h: H; rqst_methods: detachable WSF_ROUTER_METHODS)
|
||||
local
|
||||
l_uri: READABLE_STRING_8
|
||||
do
|
||||
if attached base_url as l_base_url then
|
||||
l_uri := l_base_url + p
|
||||
else
|
||||
l_uri := p
|
||||
end
|
||||
handlers.force ([h, l_uri, rqst_methods])
|
||||
h.on_handler_mapped (l_uri, rqst_methods)
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
based_resource (a_resource: READABLE_STRING_8): READABLE_STRING_8
|
||||
do
|
||||
if attached base_url as l_base_url then
|
||||
Result := l_base_url + a_resource
|
||||
else
|
||||
Result := a_resource
|
||||
end
|
||||
end
|
||||
|
||||
feature {WSF_ROUTED_SERVICE_I} -- Handler
|
||||
|
||||
matching_route (req: WSF_REQUEST): detachable WSF_ROUTE [H, C]
|
||||
local
|
||||
h: detachable H
|
||||
ctx: detachable C
|
||||
rq_method: READABLE_STRING_8
|
||||
do
|
||||
rq_method := request_method (req)
|
||||
|
||||
h := handler_by_path (source_uri (req), rq_method)
|
||||
if h = Void then
|
||||
if attached smart_handler_by_path (source_uri (req), rq_method) as info then
|
||||
h := info.handler
|
||||
ctx := handler_context (info.path, req)
|
||||
end
|
||||
end
|
||||
if h /= Void then
|
||||
if h.is_valid_context (req) then
|
||||
if ctx = Void then
|
||||
ctx := handler_context (Void, req)
|
||||
end
|
||||
create Result.make (h, ctx)
|
||||
else
|
||||
Result := Void
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Access: Implementation
|
||||
|
||||
handler_by_path (a_path: READABLE_STRING_GENERAL; rqst_method: READABLE_STRING_8): detachable H
|
||||
require
|
||||
a_path_valid: a_path /= Void
|
||||
local
|
||||
l_handlers: like handlers
|
||||
l_item: like handlers.item
|
||||
do
|
||||
l_handlers := handlers
|
||||
from
|
||||
l_handlers.start
|
||||
until
|
||||
l_handlers.after or Result /= Void
|
||||
loop
|
||||
l_item := l_handlers.item
|
||||
if is_matching_request_methods (rqst_method, l_item.request_methods) and a_path.same_string (l_item.resource) then
|
||||
Result := l_item.handler
|
||||
end
|
||||
l_handlers.forth
|
||||
end
|
||||
ensure
|
||||
a_path_unchanged: a_path.same_string (old a_path)
|
||||
end
|
||||
|
||||
smart_handler_by_path (a_path: READABLE_STRING_8; rqst_method: READABLE_STRING_8): detachable TUPLE [path: READABLE_STRING_8; handler: H]
|
||||
require
|
||||
a_path_valid: a_path /= Void
|
||||
local
|
||||
p: INTEGER
|
||||
l_context_path, l_path: READABLE_STRING_8
|
||||
h: detachable H
|
||||
do
|
||||
l_context_path := context_path (a_path)
|
||||
from
|
||||
p := l_context_path.count + 1
|
||||
until
|
||||
p <= 1 or Result /= Void
|
||||
loop
|
||||
l_path := l_context_path.substring (1, p - 1)
|
||||
h := handler_by_path (l_path, rqst_method)
|
||||
if h /= Void then
|
||||
Result := [l_path, h]
|
||||
else
|
||||
p := l_context_path.last_index_of ('/', p - 1)
|
||||
end
|
||||
variant
|
||||
p
|
||||
end
|
||||
ensure
|
||||
a_path_unchanged: a_path.same_string (old a_path)
|
||||
end
|
||||
|
||||
feature {NONE} -- Context factory
|
||||
|
||||
handler_context (p: detachable STRING; req: WSF_REQUEST): C
|
||||
local
|
||||
ctx: C
|
||||
do
|
||||
if p /= Void then
|
||||
create ctx.make (req, p)
|
||||
else
|
||||
create ctx.make (req, source_uri (req))
|
||||
end
|
||||
Result := ctx
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
new_cursor: ITERATION_CURSOR [TUPLE [handler: H; resource: READABLE_STRING_8; request_methods: detachable WSF_ROUTER_METHODS]]
|
||||
-- Fresh cursor associated with current structure
|
||||
do
|
||||
Result := handlers.new_cursor
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
handlers: ARRAYED_LIST [TUPLE [handler: H; resource: READABLE_STRING_8; request_methods: detachable WSF_ROUTER_METHODS]]
|
||||
-- Handlers indexed by the template expression
|
||||
-- see `templates'
|
||||
|
||||
context_path (a_path: READABLE_STRING_8): READABLE_STRING_8
|
||||
-- Prepared path from context which match requirement
|
||||
-- i.e: not empty, starting with '/'
|
||||
local
|
||||
p: INTEGER
|
||||
s: STRING_8
|
||||
do
|
||||
Result := a_path
|
||||
if Result.is_empty then
|
||||
Result := "/"
|
||||
else
|
||||
if Result[1] /= '/' then
|
||||
create s.make_from_string (Result)
|
||||
s.prepend_character ('/')
|
||||
Result := s
|
||||
end
|
||||
p := Result.index_of ('.', 1)
|
||||
if p > 0 then
|
||||
Result := Result.substring (1, p - 1)
|
||||
end
|
||||
end
|
||||
ensure
|
||||
result_not_empty: not Result.is_empty
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, 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
|
||||
@@ -1,25 +1,18 @@
|
||||
note
|
||||
description: "[
|
||||
Request handler object which is called by a WSF_ROUTER
|
||||
A response handler should implement the method
|
||||
|
||||
response (ctx: C; req: WSF_REQUEST): WSF_RESPONSE_MESSAGE
|
||||
|
||||
|
||||
The class is generic, this way one can use a custom WSF_HANDLER_CONTEXT if needed
|
||||
]"
|
||||
description: "Summary description for {WSF_URI_TEMPLATE_RESPONSE_HANDLER}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
WSF_RESPONSE_HANDLER [C -> WSF_HANDLER_CONTEXT]
|
||||
WSF_URI_TEMPLATE_RESPONSE_HANDLER
|
||||
|
||||
inherit
|
||||
WSF_HANDLER [C]
|
||||
WSF_URI_TEMPLATE_HANDLER
|
||||
|
||||
feature -- Response
|
||||
|
||||
response (ctx: C; req: WSF_REQUEST): WSF_RESPONSE_MESSAGE
|
||||
response (ctx: WSF_URI_TEMPLATE_HANDLER_CONTEXT; req: WSF_REQUEST): WSF_RESPONSE_MESSAGE
|
||||
require
|
||||
is_valid_context: is_valid_context (req)
|
||||
deferred
|
||||
@@ -29,7 +22,7 @@ feature -- Response
|
||||
|
||||
feature -- Execution
|
||||
|
||||
execute (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
execute (ctx: WSF_URI_TEMPLATE_HANDLER_CONTEXT; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Execute request handler
|
||||
do
|
||||
res.send (response (ctx, req))
|
||||
@@ -1,39 +0,0 @@
|
||||
note
|
||||
description: "Summary description for {DEFAULT_URI_TEMPLATE_ROUTED_SERVICE}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
WSF_URI_TEMPLATE_ROUTED_SERVICE
|
||||
|
||||
inherit
|
||||
WSF_ROUTED_SERVICE_I [WSF_HANDLER [WSF_URI_TEMPLATE_HANDLER_CONTEXT], WSF_URI_TEMPLATE_HANDLER_CONTEXT]
|
||||
redefine
|
||||
router
|
||||
end
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
create_router
|
||||
-- Create router
|
||||
--| it can be redefine to create with precise count if needed.
|
||||
do
|
||||
create router.make (0)
|
||||
end
|
||||
|
||||
feature -- Router
|
||||
|
||||
router: WSF_URI_TEMPLATE_ROUTER
|
||||
|
||||
;note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, 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
|
||||
@@ -1,52 +0,0 @@
|
||||
note
|
||||
description: "[
|
||||
Default router based on URI Template map
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
WSF_URI_TEMPLATE_ROUTER
|
||||
|
||||
inherit
|
||||
WSF_URI_TEMPLATE_ROUTER_I [WSF_HANDLER [WSF_URI_TEMPLATE_HANDLER_CONTEXT], WSF_URI_TEMPLATE_HANDLER_CONTEXT]
|
||||
redefine
|
||||
map_agent_with_request_methods,
|
||||
map_agent_response_with_request_methods
|
||||
end
|
||||
|
||||
create
|
||||
make,
|
||||
make_with_base_url
|
||||
|
||||
feature -- Mapping agent
|
||||
|
||||
map_agent_with_request_methods (a_id: READABLE_STRING_8; a_action: PROCEDURE [ANY, TUPLE [ctx: WSF_URI_TEMPLATE_HANDLER_CONTEXT; req: WSF_REQUEST; res: WSF_RESPONSE]];
|
||||
rqst_methods: detachable WSF_ROUTER_METHODS)
|
||||
local
|
||||
h: WSF_AGENT_HANDLER [WSF_URI_TEMPLATE_HANDLER_CONTEXT]
|
||||
do
|
||||
create h.make (a_action)
|
||||
map_with_request_methods (a_id, h, rqst_methods)
|
||||
end
|
||||
|
||||
map_agent_response_with_request_methods (a_id: READABLE_STRING_8; a_action: FUNCTION [ANY, TUPLE [ctx: WSF_URI_TEMPLATE_HANDLER_CONTEXT; req: WSF_REQUEST], WSF_RESPONSE_MESSAGE];
|
||||
rqst_methods: detachable WSF_ROUTER_METHODS)
|
||||
local
|
||||
h: WSF_AGENT_RESPONSE_HANDLER [WSF_URI_TEMPLATE_HANDLER_CONTEXT]
|
||||
do
|
||||
create h.make (a_action)
|
||||
map_with_request_methods (a_id, h, rqst_methods)
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, 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
|
||||
@@ -1,35 +0,0 @@
|
||||
note
|
||||
description: "[
|
||||
WSF_URI_TEMPLATE_ROUTING_HANDLER is a default descendant of WSF_URI_ROUTING_HANDLER_I
|
||||
for WSF_URI_TEMPLATE_ROUTER
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
WSF_URI_TEMPLATE_ROUTING_HANDLER
|
||||
|
||||
inherit
|
||||
WSF_URI_TEMPLATE_ROUTING_HANDLER_I [WSF_HANDLER [WSF_URI_TEMPLATE_HANDLER_CONTEXT], WSF_URI_TEMPLATE_HANDLER_CONTEXT]
|
||||
redefine
|
||||
router
|
||||
end
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Routing
|
||||
|
||||
router: WSF_URI_TEMPLATE_ROUTER
|
||||
|
||||
;note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, 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
|
||||
@@ -1,31 +1,30 @@
|
||||
note
|
||||
description: "Summary description for WSF_AGENT_HANDLER."
|
||||
description: "Summary description for {WSF_AGENT_URI_TEMPLATE_HANDLER}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
WSF_AGENT_HANDLER [C -> WSF_HANDLER_CONTEXT]
|
||||
WSF_AGENT_URI_TEMPLATE_HANDLER
|
||||
|
||||
inherit
|
||||
WSF_HANDLER [C]
|
||||
WSF_URI_TEMPLATE_HANDLER
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Initialization
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (act: like action)
|
||||
make (a_action: like action)
|
||||
do
|
||||
action := act
|
||||
action := a_action
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
action: PROCEDURE [ANY, TUPLE [ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE]]
|
||||
action: PROCEDURE [ANY, TUPLE [context: WSF_URI_TEMPLATE_HANDLER_CONTEXT; request: WSF_REQUEST; response: WSF_RESPONSE]]
|
||||
|
||||
feature -- Execution
|
||||
|
||||
execute (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
execute (ctx: WSF_URI_TEMPLATE_HANDLER_CONTEXT; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
do
|
||||
action.call ([ctx, req, res])
|
||||
end
|
||||
@@ -0,0 +1,19 @@
|
||||
note
|
||||
description: "Summary description for EWF_URI_TEMPLATE_HANDLER."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
WSF_URI_TEMPLATE_HANDLER
|
||||
|
||||
inherit
|
||||
WSF_HANDLER
|
||||
|
||||
feature -- Execution
|
||||
|
||||
execute (ctx: WSF_URI_TEMPLATE_HANDLER_CONTEXT; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
deferred
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,81 @@
|
||||
note
|
||||
description: "Summary description for {EWF_ROUTER_URI_TEMPLATE_PATH}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
WSF_URI_TEMPLATE_MAPPING
|
||||
|
||||
inherit
|
||||
WSF_ROUTER_MAPPING
|
||||
|
||||
create
|
||||
make,
|
||||
make_from_string
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make_from_string (s: READABLE_STRING_8; h: like handler)
|
||||
do
|
||||
make (create {URI_TEMPLATE}.make (s), h)
|
||||
end
|
||||
|
||||
make (tpl: URI_TEMPLATE; h: like handler)
|
||||
do
|
||||
template := tpl
|
||||
handler := h
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
handler: WSF_URI_TEMPLATE_HANDLER
|
||||
|
||||
template: URI_TEMPLATE
|
||||
|
||||
feature -- Element change
|
||||
|
||||
set_handler (h: like handler)
|
||||
do
|
||||
handler := h
|
||||
end
|
||||
|
||||
feature -- Status
|
||||
|
||||
routed_handler (req: WSF_REQUEST; res: WSF_RESPONSE; a_router: WSF_ROUTER): detachable WSF_HANDLER
|
||||
local
|
||||
tpl: URI_TEMPLATE
|
||||
p: READABLE_STRING_32
|
||||
ctx: detachable WSF_URI_TEMPLATE_HANDLER_CONTEXT
|
||||
do
|
||||
p := source_uri (req)
|
||||
tpl := based_uri_template (template, a_router)
|
||||
if attached tpl.match (p) as tpl_res then
|
||||
Result := handler
|
||||
create ctx.make (req, tpl, tpl_res, source_uri (req))
|
||||
a_router.execute_before (Current)
|
||||
ctx.apply (req)
|
||||
handler.execute (ctx, req, res)
|
||||
ctx.revert (req)
|
||||
a_router.execute_after (Current)
|
||||
end
|
||||
rescue
|
||||
if ctx /= Void then
|
||||
ctx.revert (req)
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
based_uri_template (a_tpl: like template; a_router: WSF_ROUTER): like template
|
||||
do
|
||||
if attached a_router.base_url as l_base_url then
|
||||
Result := a_tpl.duplicate
|
||||
Result.set_template (l_base_url + a_tpl.template)
|
||||
else
|
||||
Result := a_tpl
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
@@ -1,228 +0,0 @@
|
||||
note
|
||||
description: "[
|
||||
URL dispatcher/router based on URI Template mapping and request methods if precised
|
||||
The associated context {WSF_URI_TEMPLATE_HANDLER_CONTEXT} contains information about the matched map.
|
||||
|
||||
Examples:
|
||||
|
||||
map ("/users/", users_handler)
|
||||
map_with_request_methods ("/order/{order-id}", order_handler, <<"GET", "POST">>)
|
||||
map_agent_with_request_methods ("/order/{order-id}", agent do_get_order, <<"GET">>)
|
||||
map_agent_with_request_methods ("/order/{order-id}", agent do_post_order, <<"POST">>)
|
||||
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
WSF_URI_TEMPLATE_ROUTER_I [H -> WSF_HANDLER [C], C -> WSF_URI_TEMPLATE_HANDLER_CONTEXT create make end]
|
||||
|
||||
inherit
|
||||
WSF_ROUTER [H, C]
|
||||
|
||||
create
|
||||
make,
|
||||
make_with_base_url
|
||||
|
||||
feature -- Initialization
|
||||
|
||||
make (n: INTEGER)
|
||||
do
|
||||
create handlers.make (n)
|
||||
create templates.make (n)
|
||||
handlers.compare_objects
|
||||
initialize
|
||||
end
|
||||
|
||||
make_with_base_url (n: INTEGER; a_base_url: like base_url)
|
||||
-- Make router allocated for at least `n' maps,
|
||||
-- and use `a_base_url' as base_url
|
||||
do
|
||||
make (n)
|
||||
set_base_url (a_base_url)
|
||||
end
|
||||
|
||||
feature -- Status report
|
||||
|
||||
handlers_matching_map (a_resource: READABLE_STRING_8; rqst_methods: detachable WSF_ROUTER_METHODS): detachable LIST [H]
|
||||
local
|
||||
l_res: READABLE_STRING_8
|
||||
do
|
||||
l_res := based_resource (a_resource)
|
||||
across
|
||||
handlers as c
|
||||
loop
|
||||
if c.item.resource.same_string (l_res) then
|
||||
if
|
||||
rqst_methods = Void or else
|
||||
across rqst_methods as rq some is_matching_request_methods (rq.item, c.item.request_methods) end
|
||||
then
|
||||
if Result = Void then
|
||||
create {ARRAYED_LIST [H]} Result.make (1)
|
||||
end
|
||||
Result.extend (c.item.handler)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Registration
|
||||
|
||||
map_with_uri_template (uri: URI_TEMPLATE; h: H)
|
||||
require
|
||||
has_not_such_map: not has_map (uri.template, Void, h)
|
||||
do
|
||||
map_with_uri_template_and_request_methods (uri, h, Void)
|
||||
end
|
||||
|
||||
map_with_uri_template_and_request_methods (uri: URI_TEMPLATE; h: H; rqst_methods: detachable WSF_ROUTER_METHODS)
|
||||
require
|
||||
uri_is_valid: uri.is_valid
|
||||
has_not_such_map: not has_map (uri.template, rqst_methods, h)
|
||||
local
|
||||
l_tpl: like {URI_TEMPLATE}.template
|
||||
l_uri: URI_TEMPLATE
|
||||
do
|
||||
l_uri := based_uri (uri)
|
||||
l_tpl := l_uri.template
|
||||
|
||||
handlers.force ([h, l_tpl, rqst_methods])
|
||||
templates.force (l_uri, l_tpl)
|
||||
h.on_handler_mapped (l_tpl, rqst_methods)
|
||||
end
|
||||
|
||||
map_with_request_methods (tpl: READABLE_STRING_8; h: H; rqst_methods: detachable WSF_ROUTER_METHODS)
|
||||
do
|
||||
map_with_uri_template_and_request_methods (create {URI_TEMPLATE}.make (tpl), h, rqst_methods)
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
based_uri (uri: URI_TEMPLATE): URI_TEMPLATE
|
||||
do
|
||||
if attached base_url as l_base_url then
|
||||
Result := uri.duplicate
|
||||
Result.set_template (l_base_url + uri.template)
|
||||
else
|
||||
Result := uri
|
||||
end
|
||||
end
|
||||
|
||||
based_resource (a_resource: READABLE_STRING_8): READABLE_STRING_8
|
||||
do
|
||||
if attached base_url as l_base_url then
|
||||
Result := l_base_url + a_resource
|
||||
else
|
||||
Result := a_resource
|
||||
end
|
||||
end
|
||||
|
||||
feature {WSF_ROUTED_SERVICE_I} -- Handler
|
||||
|
||||
matching_route (req: WSF_REQUEST): detachable WSF_ROUTE [H, C]
|
||||
local
|
||||
l_handlers: like handlers
|
||||
t: READABLE_STRING_8
|
||||
p: READABLE_STRING_8
|
||||
l_req_method: READABLE_STRING_8
|
||||
l_res: URI_TEMPLATE_MATCH_RESULT
|
||||
do
|
||||
p := source_uri (req)
|
||||
from
|
||||
l_req_method := request_method (req)
|
||||
l_handlers := handlers
|
||||
l_handlers.start
|
||||
until
|
||||
l_handlers.after or Result /= Void
|
||||
loop
|
||||
if attached l_handlers.item as l_info then
|
||||
if is_matching_request_methods (l_req_method, l_info.request_methods) then
|
||||
t := l_info.resource
|
||||
if
|
||||
attached {WSF_ROUTING_HANDLER [H, C]} l_info.handler as rah and then
|
||||
p.starts_with (t)
|
||||
then
|
||||
create l_res.make_empty
|
||||
l_res.path_variables.force (p.substring (t.count + 1, p.count), "path")
|
||||
|
||||
create Result.make (l_info.handler, handler_context (p, req, create {URI_TEMPLATE}.make (t), l_res))
|
||||
elseif attached templates.item (t) as tpl and then
|
||||
attached tpl.match (p) as res
|
||||
then
|
||||
create Result.make (l_info.handler, handler_context (p, req, tpl, res))
|
||||
end
|
||||
end
|
||||
end
|
||||
l_handlers.forth
|
||||
end
|
||||
end
|
||||
|
||||
feature {WSF_ROUTED_SERVICE_I} -- Default: implementation
|
||||
|
||||
default_handler_context (req: WSF_REQUEST): C
|
||||
-- <Precursor>
|
||||
do
|
||||
Result := handler_context (Void, req, create {URI_TEMPLATE}.make ("/"), create {URI_TEMPLATE_MATCH_RESULT}.make_empty)
|
||||
end
|
||||
|
||||
feature {NONE} -- Context factory
|
||||
|
||||
handler_context (p: detachable READABLE_STRING_8; req: WSF_REQUEST; tpl: URI_TEMPLATE; tpl_res: URI_TEMPLATE_MATCH_RESULT): C
|
||||
do
|
||||
if p /= Void then
|
||||
create Result.make (req, tpl, tpl_res, p)
|
||||
else
|
||||
create Result.make (req, tpl, tpl_res, source_uri (req))
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Access: ITERABLE
|
||||
|
||||
new_cursor: ITERATION_CURSOR [TUPLE [handler: H; resource: READABLE_STRING_8; request_methods: detachable WSF_ROUTER_METHODS]]
|
||||
-- Fresh cursor associated with current structure
|
||||
do
|
||||
Result := handlers.new_cursor
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
handlers: ARRAYED_LIST [TUPLE [handler: H; resource: READABLE_STRING_8; request_methods: detachable WSF_ROUTER_METHODS]]
|
||||
-- Handlers indexed by the template expression
|
||||
-- see `templates'
|
||||
|
||||
templates: HASH_TABLE [URI_TEMPLATE, READABLE_STRING_8]
|
||||
-- URI Template indexed by the template expression
|
||||
|
||||
context_path (a_path: STRING): STRING
|
||||
-- Prepared path from context which match requirement
|
||||
-- i.e: not empty, starting with '/'
|
||||
local
|
||||
p: INTEGER
|
||||
do
|
||||
Result := a_path
|
||||
if Result.is_empty then
|
||||
Result := "/"
|
||||
else
|
||||
if Result[1] /= '/' then
|
||||
Result := "/" + Result
|
||||
end
|
||||
p := Result.index_of ('.', 1)
|
||||
if p > 0 then
|
||||
Result := Result.substring (1, p - 1)
|
||||
end
|
||||
end
|
||||
ensure
|
||||
result_not_empty: not Result.is_empty
|
||||
end
|
||||
|
||||
;note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, 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
|
||||
@@ -1,47 +0,0 @@
|
||||
note
|
||||
description: "[
|
||||
This class helps to build Routing handler based for WSF_URI_TEMPLATE_ROUTER
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
WSF_URI_TEMPLATE_ROUTING_HANDLER_I [H -> WSF_HANDLER [C],
|
||||
C -> WSF_URI_TEMPLATE_HANDLER_CONTEXT create make end]
|
||||
|
||||
inherit
|
||||
WSF_ROUTING_HANDLER [H, C]
|
||||
|
||||
create
|
||||
make,
|
||||
make_with_base_url
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (n: INTEGER)
|
||||
do
|
||||
create router.make (n)
|
||||
end
|
||||
|
||||
make_with_base_url (n: INTEGER; a_base_url: like base_url)
|
||||
-- Make allocated for at least `n' maps,
|
||||
-- and use `a_base_url' as base_url
|
||||
do
|
||||
create router.make_with_base_url (n, a_base_url)
|
||||
end
|
||||
|
||||
feature {NONE} -- Routing
|
||||
|
||||
router: WSF_URI_TEMPLATE_ROUTER_I [H, C]
|
||||
|
||||
;note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, 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
|
||||
@@ -1,43 +1,69 @@
|
||||
note
|
||||
description: "[
|
||||
Request handler used to respond file system request.
|
||||
]"
|
||||
description: "Summary description for {WSF_FILE_SYSTEM_HANDLER}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
WSF_FILE_SYSTEM_HANDLER [C -> WSF_HANDLER_CONTEXT]
|
||||
WSF_FILE_SYSTEM_HANDLER
|
||||
|
||||
inherit
|
||||
WSF_HANDLER [C]
|
||||
WSF_STARTS_WITH_HANDLER
|
||||
rename
|
||||
execute as execute_starts_with
|
||||
end
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (a_root: READABLE_STRING_8)
|
||||
make (d: like document_root)
|
||||
require
|
||||
a_root_exists: node_exists (a_root)
|
||||
valid_d: (d /= Void and then not d.is_empty) implies d.ends_with ("/")
|
||||
local
|
||||
e: EXECUTION_ENVIRONMENT
|
||||
do
|
||||
document_root := a_root
|
||||
if d.is_empty then
|
||||
create e
|
||||
document_root := e.current_working_directory
|
||||
else
|
||||
document_root := d
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
feature -- Access
|
||||
|
||||
document_root: READABLE_STRING_8
|
||||
-- Document root for the file system
|
||||
document_root: STRING
|
||||
max_age: INTEGER
|
||||
|
||||
index_disabled: BOOLEAN
|
||||
-- Index disabled?
|
||||
|
||||
directory_index: detachable ARRAY [READABLE_STRING_8]
|
||||
-- File serve if a directory index is requested
|
||||
|
||||
not_found_handler: detachable PROCEDURE [ANY, TUPLE [uri: READABLE_STRING_8; ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE]]
|
||||
|
||||
access_denied_handler: detachable PROCEDURE [ANY, TUPLE [uri: READABLE_STRING_8; ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE]]
|
||||
not_found_handler: detachable PROCEDURE [ANY, TUPLE [uri: READABLE_STRING_8; req: WSF_REQUEST; res: WSF_RESPONSE]]
|
||||
|
||||
access_denied_handler: detachable PROCEDURE [ANY, TUPLE [uri: READABLE_STRING_8; req: WSF_REQUEST; res: WSF_RESPONSE]]
|
||||
|
||||
feature -- Element change
|
||||
|
||||
enable_index
|
||||
do
|
||||
index_disabled := False
|
||||
end
|
||||
|
||||
disable_index
|
||||
do
|
||||
index_disabled := True
|
||||
end
|
||||
|
||||
set_max_age (a_seconds: like max_age)
|
||||
do
|
||||
max_age := a_seconds
|
||||
end
|
||||
|
||||
set_directory_index (idx: like directory_index)
|
||||
-- Set `directory_index' as `idx'
|
||||
do
|
||||
@@ -62,38 +88,25 @@ feature -- Element change
|
||||
|
||||
feature -- Execution
|
||||
|
||||
requested_path (ctx: C): detachable READABLE_STRING_8
|
||||
-- Path associated with the request
|
||||
-- i.e: path of the file system resource if any
|
||||
do
|
||||
if attached {WSF_STRING} ctx.item ("path") as v_path then
|
||||
Result := v_path.value.as_string_8
|
||||
end
|
||||
end
|
||||
|
||||
execute (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Execute request handler
|
||||
execute (a_start_path: READABLE_STRING_8; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
h: HTTP_HEADER
|
||||
s: STRING
|
||||
p: STRING
|
||||
do
|
||||
if attached requested_path (ctx) as uri then
|
||||
process_uri (uri, ctx, req, res)
|
||||
p := req.path_info
|
||||
if p.starts_with (a_start_path) then
|
||||
p.remove_head (a_start_path.count)
|
||||
else
|
||||
s := "Hello " + ctx.path + "%N"
|
||||
s.append ("root=" + document_root)
|
||||
|
||||
create h.make
|
||||
h.put_content_type_text_html
|
||||
h.put_content_length (s.count)
|
||||
|
||||
res.set_status_code ({HTTP_STATUS_CODE}.ok)
|
||||
res.put_header_text (h.string)
|
||||
res.put_string (s)
|
||||
check starts_with_base: False end
|
||||
end
|
||||
process_uri (p, req, res)
|
||||
end
|
||||
|
||||
process_uri (uri: READABLE_STRING_8; ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
execute_starts_with (a_start_path: READABLE_STRING_8; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
do
|
||||
execute (a_start_path,req, res)
|
||||
end
|
||||
|
||||
process_uri (uri: READABLE_STRING_8; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
f: RAW_FILE
|
||||
fn: READABLE_STRING_8
|
||||
@@ -103,19 +116,23 @@ feature -- Execution
|
||||
if f.exists then
|
||||
if f.is_readable then
|
||||
if f.is_directory then
|
||||
respond_index (req.request_uri, fn, ctx, req, res)
|
||||
if index_disabled then
|
||||
process_directory_index_disabled (uri, req, res)
|
||||
else
|
||||
process_index (req.request_uri, fn, req, res)
|
||||
end
|
||||
else
|
||||
respond_file (f, ctx, req, res)
|
||||
process_file (f, req, res)
|
||||
end
|
||||
else
|
||||
respond_access_denied (uri, ctx, req, res)
|
||||
process_access_denied (uri, req, res)
|
||||
end
|
||||
else
|
||||
respond_not_found (uri, ctx, req, res)
|
||||
process_not_found (uri, req, res)
|
||||
end
|
||||
end
|
||||
|
||||
respond_index (a_uri: READABLE_STRING_8; dn: READABLE_STRING_8; ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
process_index (a_uri: READABLE_STRING_8; dn: READABLE_STRING_8; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
h: HTTP_HEADER
|
||||
uri, s: STRING_8
|
||||
@@ -124,7 +141,7 @@ feature -- Execution
|
||||
do
|
||||
create d.make_open_read (dn)
|
||||
if attached directory_index_file (d) as f then
|
||||
respond_file (f, ctx, req, res)
|
||||
process_file (f, req, res)
|
||||
else
|
||||
uri := a_uri
|
||||
if not uri.is_empty and then uri [uri.count] /= '/' then
|
||||
@@ -170,31 +187,72 @@ feature -- Execution
|
||||
d.close
|
||||
end
|
||||
|
||||
respond_file (f: FILE; ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
process_file (f: FILE; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
ext: READABLE_STRING_8
|
||||
ct: detachable READABLE_STRING_8
|
||||
fres: WSF_FILE_RESPONSE
|
||||
dt: DATE_TIME
|
||||
do
|
||||
ext := extension (f.name)
|
||||
ct := extension_mime_mapping.mime_type (ext)
|
||||
if ct = Void then
|
||||
ct := {HTTP_MIME_TYPES}.application_force_download
|
||||
end
|
||||
create fres.make_with_content_type (ct, f.name)
|
||||
fres.set_status_code ({HTTP_STATUS_CODE}.ok)
|
||||
fres.set_answer_head_request_method (req.request_method.same_string ({HTTP_REQUEST_METHODS}.method_head))
|
||||
if
|
||||
attached req.meta_string_variable ("HTTP_IF_MODIFIED_SINCE") as s_if_modified_since and then
|
||||
attached file_date (f) as f_date and then (f_date >= rfc1123_http_date_format_to_date (s_if_modified_since))
|
||||
then
|
||||
process_not_modified (f_date, req, res)
|
||||
else
|
||||
create fres.make_with_content_type (ct, f.name)
|
||||
fres.set_status_code ({HTTP_STATUS_CODE}.ok)
|
||||
|
||||
res.send (fres)
|
||||
-- cache control
|
||||
create dt.make_now_utc
|
||||
fres.header.put_cache_control ("private, max-age=" + max_age.out)
|
||||
fres.header.put_utc_date (dt)
|
||||
if max_age > 0 then
|
||||
dt := dt.twin
|
||||
dt.second_add (max_age)
|
||||
end
|
||||
fres.header.put_expires_date (dt)
|
||||
|
||||
fres.set_answer_head_request_method (req.request_method.same_string ({HTTP_REQUEST_METHODS}.method_head))
|
||||
res.send (fres)
|
||||
end
|
||||
end
|
||||
|
||||
respond_not_found (uri: READABLE_STRING_8; ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
process_not_modified (a_utc_date: detachable DATE_TIME; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
h: HTTP_HEADER
|
||||
dt: DATE_TIME
|
||||
do
|
||||
create dt.make_now_utc
|
||||
create h.make
|
||||
h.put_cache_control ("private, max-age=" + max_age.out)
|
||||
h.put_utc_date (dt)
|
||||
if max_age > 0 then
|
||||
dt := dt.twin
|
||||
dt.second_add (max_age)
|
||||
end
|
||||
h.put_expires_date (dt)
|
||||
|
||||
if a_utc_date /= Void then
|
||||
h.put_last_modified (a_utc_date)
|
||||
end
|
||||
res.set_status_code ({HTTP_STATUS_CODE}.not_modified)
|
||||
res.put_header_text (h.string)
|
||||
res.flush
|
||||
end
|
||||
|
||||
process_not_found (uri: READABLE_STRING_8; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
h: HTTP_HEADER
|
||||
s: STRING_8
|
||||
do
|
||||
if attached not_found_handler as hdl then
|
||||
hdl.call ([uri, ctx, req, res])
|
||||
hdl.call ([uri, req, res])
|
||||
else
|
||||
create h.make
|
||||
h.put_content_type_text_plain
|
||||
@@ -208,13 +266,13 @@ feature -- Execution
|
||||
end
|
||||
end
|
||||
|
||||
respond_access_denied (uri: READABLE_STRING_8; ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
process_access_denied (uri: READABLE_STRING_8; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
h: HTTP_HEADER
|
||||
s: STRING_8
|
||||
do
|
||||
if attached access_denied_handler as hdl then
|
||||
hdl.call ([uri, ctx, req, res])
|
||||
hdl.call ([uri, req, res])
|
||||
else
|
||||
create h.make
|
||||
h.put_content_type_text_plain
|
||||
@@ -228,6 +286,26 @@ feature -- Execution
|
||||
end
|
||||
end
|
||||
|
||||
process_directory_index_disabled (uri: READABLE_STRING_8; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
h: HTTP_HEADER
|
||||
s: STRING_8
|
||||
do
|
||||
if attached access_denied_handler as hdl then
|
||||
hdl.call ([uri, req, res])
|
||||
else
|
||||
create h.make
|
||||
h.put_content_type_text_plain
|
||||
create s.make_empty
|
||||
s.append ("Directory index: Access denied%N")
|
||||
res.set_status_code ({HTTP_STATUS_CODE}.forbidden)
|
||||
h.put_content_length (s.count)
|
||||
res.put_header_text (h.string)
|
||||
res.put_string (s)
|
||||
res.flush
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
directory_index_file (d: DIRECTORY): detachable FILE
|
||||
@@ -343,14 +421,33 @@ feature {NONE} -- Implementation
|
||||
end
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, 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
|
||||
]"
|
||||
feature {NONE} -- implementation: date time
|
||||
|
||||
date_time_utility: HTTP_DATE_TIME_UTILITIES
|
||||
once
|
||||
create Result
|
||||
end
|
||||
|
||||
file_date (f: FILE): DATE_TIME
|
||||
do
|
||||
Result := timestamp_to_date (f.date)
|
||||
end
|
||||
|
||||
rfc1123_http_date_format_to_date (s: STRING): DATE_TIME
|
||||
-- String representation of `dt' using the RFC 1123
|
||||
local
|
||||
t: STRING
|
||||
do
|
||||
t := s
|
||||
if t.ends_with ("GMT") then
|
||||
t := t.substring (1, t.count - 4)
|
||||
end
|
||||
create Result.make_from_string (t, "ddd,[0]dd mmm yyyy [0]hh:[0]mi:[0]ss.ff2")
|
||||
end
|
||||
|
||||
timestamp_to_date (n: INTEGER): DATE_TIME
|
||||
do
|
||||
Result := date_time_utility.unix_time_stamp_to_date_time (n)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -1,20 +1,11 @@
|
||||
note
|
||||
description: "[
|
||||
Request handler object which is called by a WSF_ROUTER
|
||||
An handler should implement the method
|
||||
|
||||
execute (ctx, req, res)
|
||||
|
||||
The class is generic, this way one can use a custom WSF_HANDLER_CONTEXT if needed
|
||||
]"
|
||||
description: "Summary description for {WSF_HANDLER}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
WSF_HANDLER [C -> WSF_HANDLER_CONTEXT]
|
||||
|
||||
inherit
|
||||
ANY
|
||||
WSF_HANDLER
|
||||
|
||||
feature -- Status report
|
||||
|
||||
@@ -23,60 +14,10 @@ feature -- Status report
|
||||
do
|
||||
Result := True
|
||||
end
|
||||
|
||||
feature {WSF_ROUTER} -- Mapping change
|
||||
|
||||
feature -- Execution
|
||||
|
||||
execute (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Execute request handler
|
||||
--
|
||||
-- `ctx': contains advanced data related to request_uri
|
||||
-- in the case of URI_TEMPLATE, it add support for "path_parameter"
|
||||
-- `req': request data
|
||||
-- `res': reponse stream
|
||||
--| note `ctx' can also provide data coming from `req'
|
||||
require
|
||||
is_valid_context: is_valid_context (req)
|
||||
deferred
|
||||
ensure
|
||||
response_status_set: res.status_is_set
|
||||
end
|
||||
|
||||
feature -- Execution: report
|
||||
|
||||
url (req: WSF_REQUEST; a_base: detachable READABLE_STRING_8; args: detachable STRING; abs: BOOLEAN): STRING
|
||||
-- Associated url based on `a_base' and `args'
|
||||
-- if `abs' then return absolute url
|
||||
local
|
||||
s: detachable STRING
|
||||
l_base: STRING
|
||||
do
|
||||
if a_base /= Void then
|
||||
l_base := a_base
|
||||
else
|
||||
l_base := req.request_uri
|
||||
end
|
||||
s := args
|
||||
if s /= Void and then s.count > 0 then
|
||||
if s[1] /= '/' then
|
||||
s := l_base + "/" + s
|
||||
else
|
||||
s := l_base + s
|
||||
end
|
||||
else
|
||||
s := l_base
|
||||
end
|
||||
if abs then
|
||||
Result := req.absolute_script_url (s)
|
||||
else
|
||||
Result := req.script_url (s)
|
||||
end
|
||||
ensure
|
||||
result_attached: Result /= Void
|
||||
end
|
||||
|
||||
feature {WSF_ROUTER} -- Routes change
|
||||
|
||||
on_handler_mapped (a_resource: READABLE_STRING_8; a_rqst_methods: detachable WSF_ROUTER_METHODS)
|
||||
on_mapped (a_mapping: WSF_ROUTER_MAPPING; a_rqst_methods: detachable WSF_ROUTER_METHODS)
|
||||
-- Callback called when a router map a route to Current handler
|
||||
do
|
||||
end
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
note
|
||||
description: "[
|
||||
a WSF_ROUTE object associates a handler and the associated context at runtime
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
WSF_ROUTE [H -> WSF_HANDLER [C], C -> WSF_HANDLER_CONTEXT]
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (h: H; c: C)
|
||||
-- Instantiate Current with `h' and `c'
|
||||
do
|
||||
handler := h
|
||||
context := c
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
handler: H
|
||||
-- Handler
|
||||
|
||||
context: C
|
||||
-- Context associated to `handler' for execution
|
||||
|
||||
invariant
|
||||
handler /= Void
|
||||
context /= Void
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, 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
|
||||
@@ -1,111 +1,120 @@
|
||||
note
|
||||
description: "[
|
||||
URL dispatcher/router based on deferred mapping (to be defined in descendant)
|
||||
The associated context {WSF_HANDLER_CONTEXT} does contains information related to the matching at runtime.
|
||||
]"
|
||||
description: "Summary description for {EWF_ROUTER}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
WSF_ROUTER [H -> WSF_HANDLER [C], C -> WSF_HANDLER_CONTEXT]
|
||||
class
|
||||
WSF_ROUTER
|
||||
|
||||
inherit
|
||||
ITERABLE [TUPLE [handler: H; resource: READABLE_STRING_8; request_methods: detachable WSF_ROUTER_METHODS]]
|
||||
ITERABLE [TUPLE [mapping: WSF_ROUTER_MAPPING; request_methods: detachable WSF_ROUTER_METHODS]]
|
||||
|
||||
create
|
||||
make,
|
||||
make_with_base_url
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (n: INTEGER)
|
||||
do
|
||||
create mappings.make (n)
|
||||
initialize
|
||||
end
|
||||
|
||||
make_with_base_url (n: INTEGER; a_base_url: like base_url)
|
||||
-- Make router allocated for at least `n' maps,
|
||||
-- and use `a_base_url' as base_url
|
||||
do
|
||||
make (n)
|
||||
set_base_url (a_base_url)
|
||||
end
|
||||
|
||||
initialize
|
||||
-- Initialize router
|
||||
do
|
||||
create pre_route_execution_actions
|
||||
create mappings.make (10)
|
||||
create pre_execution_actions
|
||||
end
|
||||
|
||||
feature -- Status report
|
||||
|
||||
has_map (a_resource: READABLE_STRING_8; rqst_methods: detachable WSF_ROUTER_METHODS; a_handler: detachable H): BOOLEAN
|
||||
-- Has a map corresponding to `a_resource' and `rqst_methods' other than `a_handler'?
|
||||
do
|
||||
if attached handlers_matching_map (a_resource, rqst_methods) as lst then
|
||||
Result := a_handler = Void or else not lst.has (a_handler)
|
||||
end
|
||||
end
|
||||
|
||||
handlers_matching_map (a_resource: READABLE_STRING_8; rqst_methods: detachable WSF_ROUTER_METHODS): detachable LIST [H]
|
||||
-- Existing handlers matching map with `a_resource' and `rqst_methods'
|
||||
deferred
|
||||
end
|
||||
mappings: ARRAYED_LIST [TUPLE [mapping: WSF_ROUTER_MAPPING; request_methods: detachable WSF_ROUTER_METHODS]]
|
||||
-- Existing mappings
|
||||
|
||||
feature -- Mapping
|
||||
|
||||
map (a_resource: READABLE_STRING_8; h: H)
|
||||
-- Map handler `h' with `a_resource'
|
||||
require
|
||||
has_not_such_map: not has_map (a_resource, Void, h)
|
||||
map (a_mapping: WSF_ROUTER_MAPPING)
|
||||
-- Map `a_mapping'
|
||||
do
|
||||
map_with_request_methods (a_resource, h, Void)
|
||||
map_with_request_methods (a_mapping, Void)
|
||||
end
|
||||
|
||||
map_routing (a_resource: READABLE_STRING_8; h: H)
|
||||
-- Map handler `h' with `a_resource'
|
||||
require
|
||||
has_not_such_map: not has_map (a_resource, Void, h)
|
||||
map_with_request_methods (a_mapping: WSF_ROUTER_MAPPING; rqst_methods: detachable WSF_ROUTER_METHODS)
|
||||
-- Map `a_mapping' for request methods `rqst_methods'
|
||||
do
|
||||
map (a_resource, h)
|
||||
mappings.extend ([a_mapping, rqst_methods])
|
||||
a_mapping.handler.on_mapped (a_mapping, rqst_methods)
|
||||
end
|
||||
|
||||
map_with_request_methods (a_resource: READABLE_STRING_8; h: H; rqst_methods: detachable WSF_ROUTER_METHODS)
|
||||
-- Map handler `h' with `a_resource' and `rqst_methods'
|
||||
require
|
||||
has_not_such_map: not has_map (a_resource, rqst_methods, h)
|
||||
deferred
|
||||
end
|
||||
feature -- Access
|
||||
|
||||
feature -- Mapping agent
|
||||
is_dispatched: BOOLEAN
|
||||
-- `dispatch' set `is_dispatched' to True
|
||||
-- if handler was found and executed
|
||||
|
||||
map_agent (a_resource: READABLE_STRING_8; a_action: PROCEDURE [ANY, TUPLE [ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE]])
|
||||
-- Map `a_action' as an handler with `a_resource'
|
||||
dispatch (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
do
|
||||
map_agent_with_request_methods (a_resource, a_action, Void)
|
||||
end
|
||||
|
||||
map_agent_with_request_methods (a_resource: READABLE_STRING_8; a_action: PROCEDURE [ANY, TUPLE [ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE]];
|
||||
rqst_methods: detachable WSF_ROUTER_METHODS)
|
||||
-- Map `a_action' as an handler with `a_resource' and `rqst_methods'
|
||||
local
|
||||
rah: WSF_AGENT_HANDLER [C]
|
||||
do
|
||||
create rah.make (a_action)
|
||||
if attached {H} rah as h then
|
||||
map_with_request_methods (a_resource, h, rqst_methods)
|
||||
else
|
||||
check valid_agent_handler: False end
|
||||
if attached dispatch_and_return_handler (req, res) then
|
||||
check is_dispatched: is_dispatched end
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Mapping response agent
|
||||
|
||||
map_agent_response (a_resource: READABLE_STRING_8; a_function: FUNCTION [ANY, TUPLE [ctx: C; req: WSF_REQUEST], WSF_RESPONSE_MESSAGE])
|
||||
-- Map response as Result `a_function' as an handler with `a_resource'
|
||||
do
|
||||
map_agent_response_with_request_methods (a_resource, a_function, Void)
|
||||
end
|
||||
|
||||
map_agent_response_with_request_methods (a_resource: READABLE_STRING_8; a_function: FUNCTION [ANY, TUPLE [ctx: C; req: WSF_REQUEST], WSF_RESPONSE_MESSAGE];
|
||||
rqst_methods: detachable WSF_ROUTER_METHODS)
|
||||
-- Map response as Result `a_function' as an handler with `a_resource' and `rqst_methods'
|
||||
dispatch_and_return_handler (req: WSF_REQUEST; res: WSF_RESPONSE): detachable WSF_HANDLER
|
||||
local
|
||||
rah: WSF_AGENT_RESPONSE_HANDLER [C]
|
||||
l_req_method: READABLE_STRING_8
|
||||
m: WSF_ROUTER_MAPPING
|
||||
do
|
||||
create rah.make (a_function)
|
||||
if attached {H} rah as h then
|
||||
map_with_request_methods (a_resource, h, rqst_methods)
|
||||
else
|
||||
check valid_agent_handler: False end
|
||||
is_dispatched := False
|
||||
l_req_method := request_method (req)
|
||||
|
||||
across
|
||||
mappings as c
|
||||
until
|
||||
Result /= Void
|
||||
loop
|
||||
if attached c.item as l_info then
|
||||
if is_matching_request_methods (l_req_method, l_info.request_methods) then
|
||||
m := l_info.mapping
|
||||
if attached m.routed_handler (req, res, Current) as r then
|
||||
is_dispatched := True
|
||||
Result := r
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Hook
|
||||
|
||||
execute_before (a_mapping: WSF_ROUTER_MAPPING)
|
||||
do
|
||||
pre_execution_actions.call ([a_mapping])
|
||||
end
|
||||
|
||||
execute_after (a_mapping: WSF_ROUTER_MAPPING)
|
||||
do
|
||||
end
|
||||
|
||||
pre_execution_actions: ACTION_SEQUENCE [TUPLE [WSF_ROUTER_MAPPING]]
|
||||
-- Action triggered before a route is execute
|
||||
--| Could be used for tracing, logging
|
||||
|
||||
feature -- Base url
|
||||
|
||||
count: INTEGER
|
||||
do
|
||||
Result := mappings.count
|
||||
end
|
||||
|
||||
base_url: detachable READABLE_STRING_8
|
||||
-- Common start of any route url
|
||||
|
||||
@@ -115,6 +124,7 @@ feature -- Element change
|
||||
-- Set `base_url' to `a_base_url'
|
||||
-- make sure no map is already added (i.e: count = 0)
|
||||
require
|
||||
a_valid_base_url: (a_base_url /= Void and then a_base_url.is_empty) implies (a_base_url.starts_with ("/") and not a_base_url.ends_with ("/"))
|
||||
no_handler_set: count = 0
|
||||
do
|
||||
if a_base_url = Void or else a_base_url.is_empty then
|
||||
@@ -124,105 +134,12 @@ feature -- Element change
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Hook
|
||||
|
||||
pre_route_execution_actions: ACTION_SEQUENCE [TUPLE [like route]]
|
||||
-- Action triggered before a route is execute
|
||||
--| Could be used for tracing, logging
|
||||
|
||||
feature -- Routing
|
||||
|
||||
route (req: WSF_REQUEST): detachable WSF_ROUTE [H, C]
|
||||
-- Route matching `req'.
|
||||
do
|
||||
Result := matching_route (req)
|
||||
end
|
||||
|
||||
feature -- Execution
|
||||
|
||||
execute_route (a_route: WSF_ROUTE [H,C]; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Process route `a_route'
|
||||
require
|
||||
a_route_attached: a_route /= Void
|
||||
local
|
||||
ctx: C
|
||||
do
|
||||
pre_route_execution_actions.call ([a_route])
|
||||
ctx := a_route.context
|
||||
ctx.apply (req)
|
||||
a_route.handler.execute (ctx, req, res)
|
||||
ctx.revert (req)
|
||||
rescue
|
||||
a_route.context.revert (req)
|
||||
end
|
||||
|
||||
dispatch (req: WSF_REQUEST; res: WSF_RESPONSE): BOOLEAN
|
||||
-- Dispatch `req, res' to the associated handler
|
||||
-- And return True is handled, otherwise False
|
||||
do
|
||||
if attached route (req) as r then
|
||||
Result := True
|
||||
execute_route (r, req, res)
|
||||
end
|
||||
end
|
||||
|
||||
dispatch_and_return_handler (req: WSF_REQUEST; res: WSF_RESPONSE): detachable H
|
||||
-- Dispatch `req, res' to the associated handler
|
||||
-- And return this handler
|
||||
-- If Result is Void, this means no handler was found.
|
||||
do
|
||||
if attached route (req) as r then
|
||||
Result := r.handler
|
||||
execute_route (r, req, res)
|
||||
end
|
||||
end
|
||||
|
||||
feature {WSF_ROUTED_SERVICE_I} -- Implementation
|
||||
|
||||
default_handler_context (req: WSF_REQUEST): C
|
||||
-- Default handler context associated with `req'.
|
||||
--| It can be used to build a context if needed.
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- status report
|
||||
|
||||
count: INTEGER
|
||||
-- Count of maps handled by current
|
||||
do
|
||||
across
|
||||
Current as curs
|
||||
loop
|
||||
if attached {WSF_ROUTING_HANDLER [H, C]} curs.item.handler as rh then
|
||||
Result := Result + rh.count + 1 --| +1 for the handler itself
|
||||
else
|
||||
Result := Result + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Traversing
|
||||
|
||||
new_cursor: ITERATION_CURSOR [TUPLE [handler: H; resource: READABLE_STRING_8; request_methods: detachable WSF_ROUTER_METHODS]]
|
||||
new_cursor: ITERATION_CURSOR [TUPLE [mapping: WSF_ROUTER_MAPPING; request_methods: detachable WSF_ROUTER_METHODS]]
|
||||
-- Fresh cursor associated with current structure
|
||||
deferred
|
||||
end
|
||||
|
||||
feature {WSF_ROUTED_SERVICE_I} -- Handler
|
||||
|
||||
source_uri (req: WSF_REQUEST): READABLE_STRING_32
|
||||
-- URI to use to find handler.
|
||||
do
|
||||
Result := req.path_info
|
||||
end
|
||||
|
||||
matching_route (req: WSF_REQUEST): detachable WSF_ROUTE [H, C]
|
||||
-- Handler whose map matched with `req' with associated Context
|
||||
require
|
||||
req_valid: source_uri (req) /= Void
|
||||
deferred
|
||||
ensure
|
||||
source_uri_unchanged: source_uri (req).same_string (old source_uri (req))
|
||||
Result := mappings.new_cursor
|
||||
end
|
||||
|
||||
feature -- Request methods helper
|
||||
@@ -343,14 +260,4 @@ feature {NONE} -- Access: Implementation
|
||||
end
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, 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
|
||||
|
||||
@@ -1,31 +1,33 @@
|
||||
note
|
||||
description: "Summary description for WSF_URI_ROUTED_SERVICE."
|
||||
description: "Summary description for {WSF_ROUTER_MAPPING}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
WSF_URI_ROUTED_SERVICE
|
||||
WSF_ROUTER_MAPPING
|
||||
|
||||
inherit
|
||||
WSF_ROUTED_SERVICE_I [WSF_HANDLER [WSF_URI_HANDLER_CONTEXT], WSF_URI_HANDLER_CONTEXT]
|
||||
redefine
|
||||
router
|
||||
feature -- Access
|
||||
|
||||
handler: WSF_HANDLER
|
||||
deferred
|
||||
end
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
feature -- Status
|
||||
|
||||
create_router
|
||||
-- Create router
|
||||
--| it can be redefine to create with precise count if needed.
|
||||
routed_handler (req: WSF_REQUEST; res: WSF_RESPONSE; a_router: WSF_ROUTER): detachable WSF_HANDLER
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Helper
|
||||
|
||||
source_uri (req: WSF_REQUEST): READABLE_STRING_32
|
||||
-- URI to use to find handler.
|
||||
do
|
||||
create router.make (0)
|
||||
Result := req.path_info
|
||||
end
|
||||
feature -- Router
|
||||
|
||||
router: WSF_URI_ROUTER
|
||||
|
||||
;note
|
||||
note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
@@ -1,113 +0,0 @@
|
||||
note
|
||||
description: "[
|
||||
WSF_ROUTING_HANDLER is mainly to group a set of handler having the same base
|
||||
such as /users for
|
||||
/users/by/id/{id}
|
||||
/users/by/name/name}
|
||||
|
||||
It can be used to optimize the router, where the router checks only the base path before checking each entries
|
||||
Then for
|
||||
/a/a1
|
||||
/a/a2
|
||||
/a/a3
|
||||
/a/a4
|
||||
/b/b1
|
||||
/b/b2
|
||||
/b/b3
|
||||
2 routing handlers could be used "/a" and "/b"
|
||||
then to find the /b/b2 match, the router has to do only
|
||||
/a /b /b/b1 and /b/b2 i.e: 4 checks
|
||||
instead of /a/a1 /a/a2 /a/a3 /a/a4 /b/b1 /b/b2: i.e: 6 checks
|
||||
On router with deep arborescence this could be significant
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
WSF_ROUTING_HANDLER [H -> WSF_HANDLER [C], C -> WSF_HANDLER_CONTEXT]
|
||||
|
||||
inherit
|
||||
WSF_HANDLER [C]
|
||||
|
||||
feature -- Access
|
||||
|
||||
count: INTEGER
|
||||
-- Count of maps handled by current
|
||||
do
|
||||
Result := router.count
|
||||
end
|
||||
|
||||
base_url: detachable READABLE_STRING_8
|
||||
do
|
||||
Result := router.base_url
|
||||
end
|
||||
|
||||
feature -- Element change
|
||||
|
||||
set_base_url (a_base_url: like base_url)
|
||||
-- Set `base_url' to `a_base_url'
|
||||
-- make sure no map is already added (i.e: count = 0)
|
||||
require
|
||||
no_handler_set: count = 0
|
||||
do
|
||||
router.set_base_url (a_base_url)
|
||||
end
|
||||
|
||||
feature -- Execution
|
||||
|
||||
execute (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Execute request handler
|
||||
local
|
||||
r: detachable WSF_ROUTE [H, C]
|
||||
do
|
||||
r := router.route (req)
|
||||
if r = Void then
|
||||
res.put_header ({HTTP_STATUS_CODE}.not_found, <<[{HTTP_HEADER_NAMES}.header_content_length, "0"]>>)
|
||||
else
|
||||
router.execute_route (r, req, res)
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Routing
|
||||
|
||||
router: WSF_ROUTER [H, C]
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Mapping
|
||||
|
||||
map (a_resource: READABLE_STRING_8; h: H)
|
||||
-- Map handler `h' with `a_resource'
|
||||
do
|
||||
router.map (a_resource, h)
|
||||
end
|
||||
|
||||
map_with_request_methods (a_resource: READABLE_STRING_8; h: H;
|
||||
rqst_methods: detachable WSF_ROUTER_METHODS)
|
||||
-- Map handler `h' with `a_resource' and `rqst_methods'
|
||||
do
|
||||
router.map_with_request_methods (a_resource, h, rqst_methods)
|
||||
end
|
||||
|
||||
map_agent (a_resource: READABLE_STRING_8; a_action: PROCEDURE [ANY, TUPLE [ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE]])
|
||||
do
|
||||
router.map_agent (a_resource, a_action)
|
||||
end
|
||||
|
||||
map_agent_with_request_methods (a_resource: READABLE_STRING_8; a_action: PROCEDURE [ANY, TUPLE [ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE]];
|
||||
rqst_methods: detachable WSF_ROUTER_METHODS)
|
||||
do
|
||||
router.map_agent_with_request_methods (a_resource, a_action, rqst_methods)
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, 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
|
||||
Reference in New Issue
Block a user