diff --git a/examples/hello_routed_world/src/hello_routed_world.e b/examples/hello_routed_world/src/hello_routed_world.e
index a178b03a..ad5487c7 100644
--- a/examples/hello_routed_world/src/hello_routed_world.e
+++ b/examples/hello_routed_world/src/hello_routed_world.e
@@ -140,7 +140,7 @@ feature -- Execution
msg := "Hello anonymous visitor !%N"
end
content_type_supported := <<{HTTP_CONSTANTS}.json_app, {HTTP_CONSTANTS}.html_text, {HTTP_CONSTANTS}.xml_text, {HTTP_CONSTANTS}.plain_text>>
- inspect request_format_id (ctx, "format", content_type_supported)
+ inspect ctx.request_format_id ("format", content_type_supported)
when {HTTP_FORMAT_CONSTANTS}.json then
l_response_content_type := {HTTP_CONSTANTS}.json_app
msg := "{%N%"application%": %"/hello%",%N %"message%": %"" + msg + "%" %N}"
diff --git a/library/server/request/router/router-safe.ecf b/library/server/request/router/router-safe.ecf
index f655ffe4..040eb070 100644
--- a/library/server/request/router/router-safe.ecf
+++ b/library/server/request/router/router-safe.ecf
@@ -7,15 +7,15 @@
/EIFGENs$
/.svn$
-
-
+
@@ -32,8 +32,8 @@
-
+
-
+
diff --git a/library/server/request/router/src/application/routed_application.e b/library/server/request/router/src/application/routed_application.e
index c22e6080..5cb24525 100644
--- a/library/server/request/router/src/application/routed_application.e
+++ b/library/server/request/router/src/application/routed_application.e
@@ -36,10 +36,11 @@ feature -- Setup
feature -- Execution
execute (req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
+ local
+ l_handled: BOOLEAN
do
- if attached router.dispatch (req, res) as r then
- --| done
- else
+ l_handled := router.dispatch (req, res)
+ if not l_handled then
execute_default (req, res)
end
end
diff --git a/library/server/request/router/src/context/request_handler_context.e b/library/server/request/router/src/context/request_handler_context.e
index 9fa5f0bc..666ff7ca 100644
--- a/library/server/request/router/src/context/request_handler_context.e
+++ b/library/server/request/router/src/context/request_handler_context.e
@@ -15,14 +15,59 @@ inherit
{NONE} all
end
+ HTTP_FORMAT_CONSTANTS
+ export
+ {NONE} all
+ end
+
feature -- Access
request: WGI_REQUEST
-- Associated request
- path: READABLE_STRING_GENERAL
+ path: READABLE_STRING_8
-- Associated path
+ request_format (a_format_variable_name: detachable STRING; content_type_supported: detachable ARRAY [STRING]): detachable READABLE_STRING_8
+ -- Format id for the request based on {HTTP_FORMAT_CONSTANTS}
+ local
+ do
+ if a_format_variable_name /= Void and then attached parameter (a_format_variable_name) as ctx_format then
+ Result := ctx_format.as_string_8
+ else
+ Result := content_type_to_request_format (request_content_type (content_type_supported))
+ end
+ end
+
+
+ request_format_id (a_format_variable_name: detachable STRING; content_type_supported: detachable ARRAY [STRING]): INTEGER
+ -- Format id for the request based on {HTTP_FORMAT_CONSTANTS}
+ do
+ if attached request_format (a_format_variable_name, content_type_supported) as l_format then
+ Result := format_id (l_format)
+ else
+ Result := 0
+ end
+ end
+
+ content_type_to_request_format (a_content_type: detachable READABLE_STRING_8): detachable READABLE_STRING_8
+ -- `a_content_type' converted into a request format name
+ do
+ if a_content_type /= Void then
+ if a_content_type.same_string ({HTTP_CONSTANTS}.json_text) then
+ Result := {HTTP_FORMAT_CONSTANTS}.json_name
+ elseif a_content_type.same_string ({HTTP_CONSTANTS}.json_app) then
+ Result := {HTTP_FORMAT_CONSTANTS}.json_name
+ elseif a_content_type.same_string ({HTTP_CONSTANTS}.xml_text) then
+ Result := {HTTP_FORMAT_CONSTANTS}.xml_name
+ elseif a_content_type.same_string ({HTTP_CONSTANTS}.html_text) then
+ Result := {HTTP_FORMAT_CONSTANTS}.html_name
+ elseif a_content_type.same_string ({HTTP_CONSTANTS}.plain_text) then
+ Result := {HTTP_FORMAT_CONSTANTS}.text_name
+ end
+ end
+ end
+
request_content_type (content_type_supported: detachable ARRAY [STRING]): detachable READABLE_STRING_8
local
s: detachable READABLE_STRING_32
diff --git a/library/server/request/router/src/handler/request_handler.e b/library/server/request/router/src/handler/request_handler.e
index 7c4cd294..9c816624 100644
--- a/library/server/request/router/src/handler/request_handler.e
+++ b/library/server/request/router/src/handler/request_handler.e
@@ -7,6 +7,14 @@ note
deferred class
REQUEST_HANDLER
+inherit
+ ANY
+
+ ROUTED_APPLICATION_HELPER
+ export
+ {NONE} all
+ end
+
feature {NONE} -- Initialization
initialize
@@ -42,7 +50,7 @@ feature -- Execution
execute_application (a_hdl_context, req, res)
post_execute (req, res)
else
- execute_method_not_allowed (a_hdl_context, req, res)
+ execute_request_method_not_allowed (req, res, supported_request_method_names)
end
else
rescue_execute (req, res)
@@ -52,29 +60,6 @@ feature -- Execution
retry
end
- execute_method_not_allowed (a_hdl_context: REQUEST_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
- local
- s: STRING
- lst: LIST [STRING]
- do
- res.set_status_code ({HTTP_STATUS_CODE}.method_not_allowed)
- create s.make (25)
- from
- lst := supported_request_method_names
- lst.start
- until
- lst.after
- loop
- s.append_string (lst.item)
- if not lst.islast then
- s.append_character (',')
- s.append_character (' ')
- end
- lst.forth
- end
- res.write_header ({HTTP_STATUS_CODE}.method_not_allowed, <<["Allow", s]>>)
- end
-
execute_application (a_hdl_context: REQUEST_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
-- Execute request handler
deferred
@@ -101,76 +86,27 @@ feature -- Execution
feature -- Execution: report
--- execution_information (req: WGI_REQUEST): detachable REQUEST_HANDLER_CONTEXT
--- -- Execution information related to the request
--- do
--- if attached path_information (req, req.environment.path_info) as info then
--- create Result.make (req.environment.path_info)
--- end
--- end
-
--- path_information (req: WGI_REQUEST; a_rq_path: STRING): detachable TUPLE [format: detachable STRING; arguments: detachable STRING]
--- -- Information related to `a_path'
--- local
--- l_rq_path: STRING
--- i,p,n: INTEGER
--- l_format, l_args: detachable STRING
--- do
--- l_rq_path := a_rq_path
--- if l_rq_path.count > 0 and then l_rq_path[1] /= '/' then
--- l_rq_path := "/" + l_rq_path
--- end
--- n := l_rq_path.count
--- i := req.environment.path_info.count + 1
-
--- if format_located_before_parameters then
--- --| path = app-path{.format}/parameters
-
--- if l_rq_path.valid_index (i) and then l_rq_path[i] = '.' then
--- p := l_rq_path.index_of ('/', i + 1)
--- if p = 0 then
--- p := n + 1
--- else
--- l_args := l_rq_path.substring (p + 1, n)
--- end
--- l_format := l_rq_path.substring (i + 1, p - 1)
--- elseif n > i then
--- check l_rq_path[i] = '/' end
--- l_args := l_rq_path.substring (i + 1, n)
--- end
--- elseif format_located_after_parameters then
--- --| path = app-path/parameters{.format}
-
--- p := l_rq_path.last_index_of ('.', n)
--- if p > i then
--- l_format := l_rq_path.substring (p + 1, n)
--- l_args := l_rq_path.substring (i + 1, p - 1)
--- elseif n > i then
--- check l_rq_path[i] = '/' end
--- l_format := Void
--- l_args := l_rq_path.substring (i + 1, n)
--- end
--- end
--- if l_format /= Void or l_args /= Void then
--- Result := [l_format, l_args]
--- end
--- end
-
- url (req: WGI_REQUEST; args: detachable STRING; abs: BOOLEAN): STRING
- -- Associated url based on `path' and `args'
+ url (req: WGI_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 := req.request_uri + "/" + s
+ s := l_base + "/" + s
else
- s := req.request_uri + s
+ s := l_base + s
end
else
- s := req.request_uri
+ s := l_base
end
if abs then
Result := req.absolute_script_url (s)
diff --git a/examples/hello_routed_world/src/framework/routed_application_helper.e b/library/server/request/router/src/helper/routed_application_helper.e
similarity index 55%
rename from examples/hello_routed_world/src/framework/routed_application_helper.e
rename to library/server/request/router/src/helper/routed_application_helper.e
index 92349a8b..0cce19bf 100644
--- a/examples/hello_routed_world/src/framework/routed_application_helper.e
+++ b/library/server/request/router/src/helper/routed_application_helper.e
@@ -10,11 +10,6 @@ class
inherit
ANY
- HTTP_FORMAT_CONSTANTS
- export
- {NONE} all
- end
-
feature -- Helper
execute_content_type_not_allowed (req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER; a_content_types: detachable ARRAY [STRING]; a_uri_formats: detachable ARRAY [STRING])
@@ -70,26 +65,22 @@ feature -- Helper
end
end
- execute_method_not_allowed (req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER; a_methods: ARRAY [STRING])
+ execute_request_method_not_allowed (req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER; a_methods: ITERABLE [STRING])
local
s: STRING
- i, n: INTEGER
do
- create s.make (10)
- from
- i := a_methods.lower
- n := a_methods.upper
- until
- i > n
+ res.set_status_code ({HTTP_STATUS_CODE}.method_not_allowed)
+ create s.make (25)
+ across
+ a_methods as c
loop
- s.append_string (a_methods[i])
- if i < n then
+ if not s.is_empty then
s.append_character (',')
s.append_character (' ')
end
- i := i + 1
+ s.append_string (c.item)
end
-
+ res.set_status_code ({HTTP_STATUS_CODE}.method_not_allowed)
res.write_header ({HTTP_STATUS_CODE}.method_not_allowed, <<
["Content-Type", {HTTP_CONSTANTS}.plain_text],
["Allow", s]
@@ -97,43 +88,6 @@ feature -- Helper
res.write_string ("Unsupported request method, Allow: " + s + "%N")
end
-feature -- Context helper
-
- request_format_id (ctx: REQUEST_HANDLER_CONTEXT; a_format_variable_name: detachable STRING; content_type_supported: detachable ARRAY [STRING]): INTEGER
- -- Format id for the request based on {HTTP_FORMAT_CONSTANTS}
- local
- l_format: detachable STRING_8
- do
- if a_format_variable_name /= Void and then attached ctx.parameter (a_format_variable_name) as ctx_format then
- l_format := ctx_format.as_string_8
- else
- l_format := content_type_to_request_format (ctx.request_content_type (content_type_supported))
- end
- if l_format /= Void then
- Result := format_id (l_format)
- else
- Result := 0
- end
- end
-
- content_type_to_request_format (a_content_type: detachable READABLE_STRING_8): detachable STRING
- -- `a_content_type' converted into a request format name
- do
- if a_content_type /= Void then
- if a_content_type.same_string ({HTTP_CONSTANTS}.json_text) then
- Result := {HTTP_FORMAT_CONSTANTS}.json_name
- elseif a_content_type.same_string ({HTTP_CONSTANTS}.json_app) then
- Result := {HTTP_FORMAT_CONSTANTS}.json_name
- elseif a_content_type.same_string ({HTTP_CONSTANTS}.xml_text) then
- Result := {HTTP_FORMAT_CONSTANTS}.xml_name
- elseif a_content_type.same_string ({HTTP_CONSTANTS}.html_text) then
- Result := {HTTP_FORMAT_CONSTANTS}.html_name
- elseif a_content_type.same_string ({HTTP_CONSTANTS}.plain_text) then
- Result := {HTTP_FORMAT_CONSTANTS}.text_name
- end
- end
- end
-
note
copyright: "2011-2011, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
diff --git a/library/server/request/router/src/router/request_router.e b/library/server/request/router/src/router/request_router.e
index b5f0e414..a16c9cd7 100644
--- a/library/server/request/router/src/router/request_router.e
+++ b/library/server/request/router/src/router/request_router.e
@@ -7,9 +7,6 @@ note
deferred class
REQUEST_ROUTER
-inherit
- ITERABLE [TUPLE [handler: REQUEST_HANDLER; resource: READABLE_STRING_8; request_methods: detachable ARRAY [READABLE_STRING_8]]]
-
feature -- Registration
map_default (r: like default_handler)
@@ -17,7 +14,7 @@ feature -- Registration
-- If no route/handler is found,
-- then use `default_handler' as default if not Void
do
- default_handler := r
+ set_default_handler (r)
end
map (a_id: READABLE_STRING_8; h: REQUEST_HANDLER)
@@ -46,13 +43,20 @@ feature -- Registration
feature -- Execution
- dispatch (req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER): detachable REQUEST_HANDLER
+ dispatch (req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER): BOOLEAN
+ -- Dispatch `req, res' to the associated handler
+ -- And return True is handled, otherwise False
+ do
+ Result := dispatch_and_return_handler (req, res) /= Void
+ end
+
+ dispatch_and_return_handler (req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER): like default_handler
-- Dispatch `req, res' to the associated handler
-- And return this handler
-- If Result is Void, this means no handler was found.
local
d: like handler
- ctx: detachable REQUEST_HANDLER_CONTEXT
+ ctx: detachable like default_handler_context
do
d := handler (req)
if d /= Void then
@@ -60,21 +64,29 @@ feature -- Execution
ctx := d.context
else
Result := default_handler
- end
- if Result /= Void then
- if ctx = Void then
- check is_default_handler: Result = default_handler end
- create {REQUEST_URI_HANDLER_CONTEXT} ctx.make (req, "/")
+ if Result /= Void then
+ ctx := default_handler_context (req)
end
+ end
+ if Result /= Void and ctx /= Void then
Result.execute (ctx, req, res)
end
ensure
result_void_implie_no_default: Result = Void implies default_handler = Void
end
+feature -- Traversing
+
+ new_cursor: ITERATION_CURSOR [TUPLE [handler: REQUEST_HANDLER; resource: READABLE_STRING_8; request_methods: detachable ARRAY [READABLE_STRING_8]]]
+ -- Fresh cursor associated with current structure
+ deferred
+ ensure
+ result_attached: Result /= Void
+ end
+
feature {NONE} -- Access: Implementation
- handler (req: WGI_REQUEST): detachable TUPLE [handler: REQUEST_HANDLER; context: REQUEST_HANDLER_CONTEXT]
+ handler (req: WGI_REQUEST): detachable TUPLE [handler: attached like default_handler; context: like default_handler_context]
-- Handler whose map matched with `req'
require
req_valid: req /= Void and then req.path_info /= Void
@@ -127,8 +139,24 @@ feature {NONE} -- Access: Implementation
feature {NONE} -- Implementation
+ set_default_handler (h: like default_handler)
+ -- Set `default_handler' to `h'
+ deferred
+ ensure
+ default_handler_set: h = default_handler
+ end
+
default_handler: detachable REQUEST_HANDLER
-- Default handler
+ deferred
+ end
+
+ default_handler_context (req: WGI_REQUEST): REQUEST_HANDLER_CONTEXT
+ -- Default handler context associated with `default_handler'
+ require
+ has_default_handler: default_handler /= Void
+ deferred
+ end
;note
copyright: "2011-2011, Eiffel Software and others"
diff --git a/library/server/request/router/src/router/request_uri_router.e b/library/server/request/router/src/router/request_uri_router.e
index 303a1c3c..4480a354 100644
--- a/library/server/request/router/src/router/request_uri_router.e
+++ b/library/server/request/router/src/router/request_uri_router.e
@@ -30,10 +30,10 @@ feature -- Registration
feature {NONE} -- Access: Implementation
- handler (req: WGI_REQUEST): detachable TUPLE [handler: REQUEST_HANDLER; context: REQUEST_HANDLER_CONTEXT]
+ handler (req: WGI_REQUEST): detachable TUPLE [handler: REQUEST_HANDLER; context: like default_handler_context]
local
h: detachable REQUEST_HANDLER
- ctx: detachable REQUEST_HANDLER_CONTEXT
+ ctx: detachable like default_handler_context
do
h := handler_by_path (req.path_info, req.request_method)
if h = Void then
@@ -82,7 +82,6 @@ feature {NONE} -- Access: Implementation
end
l_handlers.forth
end
--- Result := handlers.item (context_path (a_path))
ensure
a_path_unchanged: a_path.same_string (old a_path)
end
@@ -115,14 +114,14 @@ feature {NONE} -- Access: Implementation
a_path_unchanged: a_path.same_string (old a_path)
end
-feature -- Context factory
+feature {NONE} -- Context factory
- handler_context (p: detachable STRING; req: WGI_REQUEST): REQUEST_URI_HANDLER_CONTEXT
+ handler_context (p: detachable STRING; req: WGI_REQUEST): like default_handler_context
do
if p /= Void then
- create Result.make (req, p)
+ create {REQUEST_URI_HANDLER_CONTEXT} Result.make (req, p)
else
- create Result.make (req, req.path_info)
+ create {REQUEST_URI_HANDLER_CONTEXT} Result.make (req, req.path_info)
end
end
@@ -165,7 +164,21 @@ feature {NONE} -- Implementation
result_not_empty: not Result.is_empty
end
-;note
+feature {NONE} -- Default: implementation
+
+ default_handler: detachable REQUEST_HANDLER
+
+ set_default_handler (h: like default_handler)
+ do
+ default_handler := h
+ end
+
+ default_handler_context (req: WGI_REQUEST): REQUEST_HANDLER_CONTEXT
+ do
+ Result := handler_context (Void, req)
+ end
+
+note
copyright: "2011-2011, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
diff --git a/library/server/request/router/src/router/request_uri_template_router.e b/library/server/request/router/src/router/request_uri_template_router.e
index d4554320..e73e3d11 100644
--- a/library/server/request/router/src/router/request_uri_template_router.e
+++ b/library/server/request/router/src/router/request_uri_template_router.e
@@ -45,9 +45,8 @@ feature -- Registration
feature {NONE} -- Access: Implementation
- handler (req: WGI_REQUEST): detachable TUPLE [handler: REQUEST_HANDLER; context: REQUEST_HANDLER_CONTEXT]
+ handler (req: WGI_REQUEST): detachable TUPLE [handler: attached like default_handler; context: like default_handler_context]
local
- ctx: detachable REQUEST_URI_TEMPLATE_HANDLER_CONTEXT
l_handlers: like handlers
t: STRING
p: STRING
@@ -67,8 +66,7 @@ feature {NONE} -- Access: Implementation
if attached templates.item (t) as tpl and then
attached tpl.match (p) as res
then
- ctx := handler_context (p, req, tpl, res)
- Result := [l_info.handler, ctx]
+ Result := [l_info.handler, handler_context (p, req, tpl, res)]
end
end
end
@@ -76,14 +74,14 @@ feature {NONE} -- Access: Implementation
end
end
-feature -- Context factory
+feature {NONE} -- Context factory
- handler_context (p: detachable STRING; req: WGI_REQUEST; tpl: URI_TEMPLATE; tpl_res: URI_TEMPLATE_MATCH_RESULT): REQUEST_URI_TEMPLATE_HANDLER_CONTEXT
+ handler_context (p: detachable STRING; req: WGI_REQUEST; tpl: URI_TEMPLATE; tpl_res: URI_TEMPLATE_MATCH_RESULT): like default_handler_context
do
if p /= Void then
- create Result.make (req, tpl, tpl_res, p)
+ create {REQUEST_URI_TEMPLATE_HANDLER_CONTEXT} Result.make (req, tpl, tpl_res, p)
else
- create Result.make (req, tpl, tpl_res, req.path_info)
+ create {REQUEST_URI_TEMPLATE_HANDLER_CONTEXT} Result.make (req, tpl, tpl_res, req.path_info)
end
end
@@ -126,6 +124,20 @@ feature {NONE} -- Implementation
result_not_empty: not Result.is_empty
end
+feature {NONE} -- Default: implementation
+
+ default_handler: detachable REQUEST_HANDLER
+
+ set_default_handler (h: like default_handler)
+ do
+ default_handler := h
+ end
+
+ default_handler_context (req: WGI_REQUEST): REQUEST_HANDLER_CONTEXT
+ do
+ create {REQUEST_URI_HANDLER_CONTEXT} Result.make (req, "/")
+ end
+
;note
copyright: "2011-2011, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"