Added request methods criteria for the router component.
Now one can decide
map_agent_with_request_methods ("/foo/bar/{bar_id}", agent handle_foo_bar, <<"GET">>)
(and similar for non agent way)
This might be useful in pure RESTful environment.
This commit is contained in:
@@ -29,6 +29,11 @@ feature {NONE} -- Initialization
|
|||||||
|
|
||||||
create_router
|
create_router
|
||||||
do
|
do
|
||||||
|
debug
|
||||||
|
create {REQUEST_URI_ROUTER} router.make (5)
|
||||||
|
create {REQUEST_URI_TEMPLATE_ROUTER} router.make (5)
|
||||||
|
end
|
||||||
|
|
||||||
-- create {REQUEST_URI_ROUTER} router.make (5)
|
-- create {REQUEST_URI_ROUTER} router.make (5)
|
||||||
create {REQUEST_URI_TEMPLATE_ROUTER} router.make (5)
|
create {REQUEST_URI_TEMPLATE_ROUTER} router.make (5)
|
||||||
end
|
end
|
||||||
@@ -47,6 +52,12 @@ feature {NONE} -- Initialization
|
|||||||
create ra.make (agent handle_anonymous_hello)
|
create ra.make (agent handle_anonymous_hello)
|
||||||
router.map ("/hello", ra)
|
router.map ("/hello", ra)
|
||||||
router.map ("/hello.{format}", ra)
|
router.map ("/hello.{format}", ra)
|
||||||
|
|
||||||
|
router.map_agent_with_request_methods ("/method/any", agent handle_method_any, Void)
|
||||||
|
router.map_agent_with_request_methods ("/method/guess", agent handle_method_get_or_post, <<"GET", "POST">>)
|
||||||
|
router.map_agent_with_request_methods ("/method/custom", agent handle_method_get, <<"GET">>)
|
||||||
|
router.map_agent_with_request_methods ("/method/custom", agent handle_method_post, <<"POST">>)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
feature -- Execution
|
feature -- Execution
|
||||||
@@ -170,6 +181,29 @@ feature -- Execution
|
|||||||
execute_hello (req, res, ctx.parameter ("name"), ctx)
|
execute_hello (req, res, ctx.parameter ("name"), ctx)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
handle_method_any (ctx: REQUEST_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
|
||||||
|
do
|
||||||
|
execute_hello (req, res, req.request_method, ctx)
|
||||||
|
end
|
||||||
|
|
||||||
|
handle_method_get (ctx: REQUEST_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
|
||||||
|
do
|
||||||
|
execute_hello (req, res, "GET", ctx)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
handle_method_post (ctx: REQUEST_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
|
||||||
|
do
|
||||||
|
execute_hello (req, res, "POST", ctx)
|
||||||
|
end
|
||||||
|
|
||||||
|
handle_method_get_or_post (ctx: REQUEST_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
|
||||||
|
do
|
||||||
|
execute_hello (req, res, "GET or POST", ctx)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2011, Eiffel Software and others"
|
copyright: "2011-2011, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ feature -- Access
|
|||||||
request: WGI_REQUEST
|
request: WGI_REQUEST
|
||||||
-- Associated request
|
-- Associated request
|
||||||
|
|
||||||
path: STRING
|
path: READABLE_STRING_GENERAL
|
||||||
-- ???
|
-- Associated path
|
||||||
|
|
||||||
request_content_type (content_type_supported: detachable ARRAY [STRING]): detachable READABLE_STRING_8
|
request_content_type (content_type_supported: detachable ARRAY [STRING]): detachable READABLE_STRING_8
|
||||||
local
|
local
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ note
|
|||||||
deferred class
|
deferred class
|
||||||
REQUEST_ROUTER
|
REQUEST_ROUTER
|
||||||
|
|
||||||
|
inherit
|
||||||
|
ITERABLE [TUPLE [handler: REQUEST_HANDLER; id: READABLE_STRING_8; request_methods: detachable ARRAY [READABLE_STRING_8]]]
|
||||||
|
|
||||||
feature -- Registration
|
feature -- Registration
|
||||||
|
|
||||||
map_default (r: like default_handler)
|
map_default (r: like default_handler)
|
||||||
@@ -17,17 +20,28 @@ feature -- Registration
|
|||||||
default_handler := r
|
default_handler := r
|
||||||
end
|
end
|
||||||
|
|
||||||
map (a_id: STRING; h: REQUEST_HANDLER)
|
map (a_id: READABLE_STRING_8; h: REQUEST_HANDLER)
|
||||||
-- Map handler `h' with `a_id'
|
-- Map handler `h' with `a_id'
|
||||||
|
do
|
||||||
|
map_with_request_methods (a_id, h, Void)
|
||||||
|
end
|
||||||
|
|
||||||
|
map_with_request_methods (a_id: READABLE_STRING_8; h: REQUEST_HANDLER; rqst_methods: detachable ARRAY [READABLE_STRING_8])
|
||||||
|
-- Map handler `h' with `a_id' and `rqst_methods'
|
||||||
deferred
|
deferred
|
||||||
end
|
end
|
||||||
|
|
||||||
map_agent (a_id: STRING; a_action: like {REQUEST_AGENT_HANDLER}.action)
|
map_agent (a_id: READABLE_STRING_8; a_action: like {REQUEST_AGENT_HANDLER}.action)
|
||||||
|
do
|
||||||
|
map_agent_with_request_methods (a_id, a_action, Void)
|
||||||
|
end
|
||||||
|
|
||||||
|
map_agent_with_request_methods (a_id: READABLE_STRING_8; a_action: like {REQUEST_AGENT_HANDLER}.action; rqst_methods: detachable ARRAY [READABLE_STRING_8])
|
||||||
local
|
local
|
||||||
h: REQUEST_AGENT_HANDLER
|
h: REQUEST_AGENT_HANDLER
|
||||||
do
|
do
|
||||||
create h.make (a_action)
|
create h.make (a_action)
|
||||||
map (a_id, h)
|
map_with_request_methods (a_id, h, rqst_methods)
|
||||||
end
|
end
|
||||||
|
|
||||||
feature -- Execution
|
feature -- Execution
|
||||||
@@ -69,6 +83,48 @@ feature {NONE} -- Access: Implementation
|
|||||||
req_path_info_unchanged: req.path_info.same_string (old req.path_info)
|
req_path_info_unchanged: req.path_info.same_string (old req.path_info)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
is_matching_request_methods (a_request_method: READABLE_STRING_GENERAL; rqst_methods: like formatted_request_methods): BOOLEAN
|
||||||
|
-- `a_request_method' is matching `rqst_methods' contents
|
||||||
|
local
|
||||||
|
i,n: INTEGER
|
||||||
|
m: READABLE_STRING_GENERAL
|
||||||
|
do
|
||||||
|
if rqst_methods /= Void and then not rqst_methods.is_empty then
|
||||||
|
m := a_request_method
|
||||||
|
from
|
||||||
|
i := rqst_methods.lower
|
||||||
|
n := rqst_methods.upper
|
||||||
|
until
|
||||||
|
i > n or Result
|
||||||
|
loop
|
||||||
|
Result := m.same_string (rqst_methods[i])
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Result := True
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
formatted_request_methods (rqst_methods: like formatted_request_methods): detachable ARRAY [READABLE_STRING_8]
|
||||||
|
-- Formatted request methods values
|
||||||
|
local
|
||||||
|
i,l,u: INTEGER
|
||||||
|
do
|
||||||
|
if rqst_methods /= Void and then not rqst_methods.is_empty then
|
||||||
|
l := rqst_methods.lower
|
||||||
|
u := rqst_methods.upper
|
||||||
|
create Result.make_filled (rqst_methods[l], l, u)
|
||||||
|
from
|
||||||
|
i := l + 1
|
||||||
|
until
|
||||||
|
i > u
|
||||||
|
loop
|
||||||
|
Result[i] := rqst_methods[i].as_string_8.as_upper
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
feature {NONE} -- Implementation
|
feature {NONE} -- Implementation
|
||||||
|
|
||||||
default_handler: detachable REQUEST_HANDLER
|
default_handler: detachable REQUEST_HANDLER
|
||||||
|
|||||||
@@ -10,11 +10,6 @@ class
|
|||||||
inherit
|
inherit
|
||||||
REQUEST_ROUTER
|
REQUEST_ROUTER
|
||||||
|
|
||||||
ITERABLE [REQUEST_HANDLER]
|
|
||||||
redefine
|
|
||||||
new_cursor
|
|
||||||
end
|
|
||||||
|
|
||||||
create
|
create
|
||||||
make
|
make
|
||||||
|
|
||||||
@@ -28,9 +23,9 @@ feature -- Initialization
|
|||||||
|
|
||||||
feature -- Registration
|
feature -- Registration
|
||||||
|
|
||||||
map (p: STRING; h: REQUEST_HANDLER)
|
map_with_request_methods (p: READABLE_STRING_8; h: REQUEST_HANDLER; rqst_methods: detachable ARRAY [READABLE_STRING_8])
|
||||||
do
|
do
|
||||||
handlers.force (h, p)
|
handlers.force ([h, p, formatted_request_methods (rqst_methods)])
|
||||||
end
|
end
|
||||||
|
|
||||||
feature {NONE} -- Access: Implementation
|
feature {NONE} -- Access: Implementation
|
||||||
@@ -40,9 +35,9 @@ feature {NONE} -- Access: Implementation
|
|||||||
h: detachable REQUEST_HANDLER
|
h: detachable REQUEST_HANDLER
|
||||||
ctx: detachable REQUEST_HANDLER_CONTEXT
|
ctx: detachable REQUEST_HANDLER_CONTEXT
|
||||||
do
|
do
|
||||||
h := handler_by_path (req.path_info)
|
h := handler_by_path (req.path_info, req.request_method)
|
||||||
if h = Void then
|
if h = Void then
|
||||||
if attached smart_handler_by_path (req.path_info) as info then
|
if attached smart_handler_by_path (req.path_info, req.request_method) as info then
|
||||||
h := info.handler
|
h := info.handler
|
||||||
ctx := handler_context (info.path, req)
|
ctx := handler_context (info.path, req)
|
||||||
end
|
end
|
||||||
@@ -59,30 +54,45 @@ feature {NONE} -- Access: Implementation
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
smart_handler (req: WGI_REQUEST): detachable TUPLE [path: STRING; handler: REQUEST_HANDLER]
|
smart_handler (req: WGI_REQUEST): detachable TUPLE [path: READABLE_STRING_8; handler: REQUEST_HANDLER]
|
||||||
require
|
require
|
||||||
req_valid: req /= Void and then req.path_info /= Void
|
req_valid: req /= Void and then req.path_info /= Void
|
||||||
do
|
do
|
||||||
Result := smart_handler_by_path (req.path_info)
|
Result := smart_handler_by_path (req.path_info, req.request_method)
|
||||||
ensure
|
ensure
|
||||||
req_path_info_unchanged: req.path_info.same_string (old req.path_info)
|
req_path_info_unchanged: req.path_info.same_string (old req.path_info)
|
||||||
end
|
end
|
||||||
|
|
||||||
handler_by_path (a_path: STRING): detachable REQUEST_HANDLER
|
handler_by_path (a_path: READABLE_STRING_GENERAL; rqst_method: READABLE_STRING_GENERAL): detachable REQUEST_HANDLER
|
||||||
require
|
require
|
||||||
a_path_valid: a_path /= Void
|
a_path_valid: a_path /= Void
|
||||||
|
local
|
||||||
|
l_handlers: like handlers
|
||||||
|
l_item: like handlers.item
|
||||||
do
|
do
|
||||||
Result := handlers.item (context_path (a_path))
|
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.uri) then
|
||||||
|
Result := l_item.handler
|
||||||
|
end
|
||||||
|
l_handlers.forth
|
||||||
|
end
|
||||||
|
-- Result := handlers.item (context_path (a_path))
|
||||||
ensure
|
ensure
|
||||||
a_path_unchanged: a_path.same_string (old a_path)
|
a_path_unchanged: a_path.same_string (old a_path)
|
||||||
end
|
end
|
||||||
|
|
||||||
smart_handler_by_path (a_path: STRING): detachable TUPLE [path: STRING; handler: REQUEST_HANDLER]
|
smart_handler_by_path (a_path: READABLE_STRING_8; rqst_method: READABLE_STRING_GENERAL): detachable TUPLE [path: READABLE_STRING_8; handler: REQUEST_HANDLER]
|
||||||
require
|
require
|
||||||
a_path_valid: a_path /= Void
|
a_path_valid: a_path /= Void
|
||||||
local
|
local
|
||||||
p: INTEGER
|
p: INTEGER
|
||||||
l_context_path, l_path: STRING
|
l_context_path, l_path: READABLE_STRING_8
|
||||||
h: detachable REQUEST_HANDLER
|
h: detachable REQUEST_HANDLER
|
||||||
do
|
do
|
||||||
l_context_path := context_path (a_path)
|
l_context_path := context_path (a_path)
|
||||||
@@ -92,7 +102,7 @@ feature {NONE} -- Access: Implementation
|
|||||||
p <= 1 or Result /= Void
|
p <= 1 or Result /= Void
|
||||||
loop
|
loop
|
||||||
l_path := l_context_path.substring (1, p - 1)
|
l_path := l_context_path.substring (1, p - 1)
|
||||||
h := handler_by_path (l_path)
|
h := handler_by_path (l_path, rqst_method)
|
||||||
if h /= Void then
|
if h /= Void then
|
||||||
Result := [l_path, h]
|
Result := [l_path, h]
|
||||||
else
|
else
|
||||||
@@ -118,34 +128,33 @@ feature -- Context factory
|
|||||||
|
|
||||||
feature -- Access
|
feature -- Access
|
||||||
|
|
||||||
new_cursor: HASH_TABLE_ITERATION_CURSOR [REQUEST_HANDLER, STRING]
|
new_cursor: ITERATION_CURSOR [TUPLE [handler: REQUEST_HANDLER; id: READABLE_STRING_8; request_methods: detachable ARRAY [READABLE_STRING_8]]]
|
||||||
-- Fresh cursor associated with current structure
|
-- Fresh cursor associated with current structure
|
||||||
do
|
do
|
||||||
Result := handlers.new_cursor
|
Result := handlers.new_cursor
|
||||||
end
|
end
|
||||||
|
|
||||||
item (a_path: STRING): detachable REQUEST_HANDLER
|
|
||||||
do
|
|
||||||
Result := handler_by_path (a_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
feature {NONE} -- Implementation
|
feature {NONE} -- Implementation
|
||||||
|
|
||||||
handlers: HASH_TABLE [REQUEST_HANDLER, STRING]
|
handlers: ARRAYED_LIST [TUPLE [handler: REQUEST_HANDLER; uri: READABLE_STRING_8; request_methods: detachable ARRAY [READABLE_STRING_8]]]
|
||||||
-- Handlers
|
-- Handlers indexed by the template expression
|
||||||
|
-- see `templates'
|
||||||
|
|
||||||
context_path (a_path: STRING): STRING
|
context_path (a_path: READABLE_STRING_8): READABLE_STRING_8
|
||||||
-- Prepared path from context which match requirement
|
-- Prepared path from context which match requirement
|
||||||
-- i.e: not empty, starting with '/'
|
-- i.e: not empty, starting with '/'
|
||||||
local
|
local
|
||||||
p: INTEGER
|
p: INTEGER
|
||||||
|
s: STRING_8
|
||||||
do
|
do
|
||||||
Result := a_path
|
Result := a_path
|
||||||
if Result.is_empty then
|
if Result.is_empty then
|
||||||
Result := "/"
|
Result := "/"
|
||||||
else
|
else
|
||||||
if Result[1] /= '/' then
|
if Result[1] /= '/' then
|
||||||
Result := "/" + Result
|
create s.make_from_string (Result)
|
||||||
|
s.prepend_character ('/')
|
||||||
|
Result := s
|
||||||
end
|
end
|
||||||
p := Result.index_of ('.', 1)
|
p := Result.index_of ('.', 1)
|
||||||
if p > 0 then
|
if p > 0 then
|
||||||
|
|||||||
@@ -10,11 +10,6 @@ class
|
|||||||
inherit
|
inherit
|
||||||
REQUEST_ROUTER
|
REQUEST_ROUTER
|
||||||
|
|
||||||
ITERABLE [REQUEST_HANDLER]
|
|
||||||
redefine
|
|
||||||
new_cursor
|
|
||||||
end
|
|
||||||
|
|
||||||
create
|
create
|
||||||
make
|
make
|
||||||
|
|
||||||
@@ -31,16 +26,21 @@ feature -- Registration
|
|||||||
|
|
||||||
map_with_uri_template (uri: URI_TEMPLATE; h: REQUEST_HANDLER)
|
map_with_uri_template (uri: URI_TEMPLATE; h: REQUEST_HANDLER)
|
||||||
do
|
do
|
||||||
handlers.force (h, uri.template)
|
map_with_uri_template_and_request_methods (uri, h, Void)
|
||||||
|
end
|
||||||
|
|
||||||
|
map_with_uri_template_and_request_methods (uri: URI_TEMPLATE; h: REQUEST_HANDLER; rqst_methods: detachable ARRAY [READABLE_STRING_8])
|
||||||
|
do
|
||||||
|
handlers.force ([h, uri.template, formatted_request_methods (rqst_methods)])
|
||||||
templates.force (uri, uri.template)
|
templates.force (uri, uri.template)
|
||||||
end
|
end
|
||||||
|
|
||||||
map (tpl: STRING; h: REQUEST_HANDLER)
|
map_with_request_methods (tpl: READABLE_STRING_8; h: REQUEST_HANDLER; rqst_methods: detachable ARRAY [READABLE_STRING_8])
|
||||||
local
|
local
|
||||||
uri: URI_TEMPLATE
|
uri: URI_TEMPLATE
|
||||||
do
|
do
|
||||||
create uri.make (tpl)
|
create uri.make (tpl)
|
||||||
map_with_uri_template (uri, h)
|
map_with_uri_template_and_request_methods (uri, h, rqst_methods)
|
||||||
end
|
end
|
||||||
|
|
||||||
feature {NONE} -- Access: Implementation
|
feature {NONE} -- Access: Implementation
|
||||||
@@ -51,20 +51,26 @@ feature {NONE} -- Access: Implementation
|
|||||||
l_handlers: like handlers
|
l_handlers: like handlers
|
||||||
t: STRING
|
t: STRING
|
||||||
p: STRING
|
p: STRING
|
||||||
|
l_req_method: READABLE_STRING_GENERAL
|
||||||
do
|
do
|
||||||
p := req.request_uri
|
p := req.request_uri
|
||||||
from
|
from
|
||||||
|
l_req_method := req.request_method
|
||||||
l_handlers := handlers
|
l_handlers := handlers
|
||||||
l_handlers.start
|
l_handlers.start
|
||||||
until
|
until
|
||||||
l_handlers.after or Result /= Void
|
l_handlers.after or Result /= Void
|
||||||
loop
|
loop
|
||||||
t := l_handlers.key_for_iteration
|
if attached l_handlers.item as l_info then
|
||||||
if attached templates.item (t) as tpl and then
|
if is_matching_request_methods (l_req_method, l_info.request_methods) then
|
||||||
attached tpl.match (p) as res
|
t := l_info.template
|
||||||
then
|
if attached templates.item (t) as tpl and then
|
||||||
ctx := handler_context (p, req, tpl, res)
|
attached tpl.match (p) as res
|
||||||
Result := [l_handlers.item_for_iteration, ctx]
|
then
|
||||||
|
ctx := handler_context (p, req, tpl, res)
|
||||||
|
Result := [l_info.handler, ctx]
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
l_handlers.forth
|
l_handlers.forth
|
||||||
end
|
end
|
||||||
@@ -81,26 +87,21 @@ feature -- Context factory
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
feature -- Access
|
feature -- Access: ITERABLE
|
||||||
|
|
||||||
new_cursor: HASH_TABLE_ITERATION_CURSOR [REQUEST_HANDLER, STRING]
|
new_cursor: ITERATION_CURSOR [TUPLE [handler: REQUEST_HANDLER; template: READABLE_STRING_8; request_methods: detachable ARRAY [READABLE_STRING_8]]]
|
||||||
-- Fresh cursor associated with current structure
|
-- Fresh cursor associated with current structure
|
||||||
do
|
do
|
||||||
Result := handlers.new_cursor
|
Result := handlers.new_cursor
|
||||||
end
|
end
|
||||||
|
|
||||||
item (a_path: STRING): detachable REQUEST_HANDLER
|
|
||||||
do
|
|
||||||
Result := handlers.item (a_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
feature {NONE} -- Implementation
|
feature {NONE} -- Implementation
|
||||||
|
|
||||||
handlers: HASH_TABLE [REQUEST_HANDLER, STRING]
|
handlers: ARRAYED_LIST [TUPLE [handler: REQUEST_HANDLER; template: READABLE_STRING_8; request_methods: detachable ARRAY [READABLE_STRING_8]]]
|
||||||
-- Handlers indexed by the template expression
|
-- Handlers indexed by the template expression
|
||||||
-- see `templates'
|
-- see `templates'
|
||||||
|
|
||||||
templates: HASH_TABLE [URI_TEMPLATE, STRING]
|
templates: HASH_TABLE [URI_TEMPLATE, READABLE_STRING_8]
|
||||||
-- URI Template indexed by the template expression
|
-- URI Template indexed by the template expression
|
||||||
|
|
||||||
context_path (a_path: STRING): STRING
|
context_path (a_path: STRING): STRING
|
||||||
|
|||||||
Reference in New Issue
Block a user