From c1120a42265bad4716363f2baa48089da9ded5eb Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Fri, 9 Sep 2011 08:50:05 +0200 Subject: [PATCH 1/9] change to standard default values --- .../ewsgi/default/nino/default_wgi_application.e | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/library/server/ewsgi/default/nino/default_wgi_application.e b/library/server/ewsgi/default/nino/default_wgi_application.e index f396a0fb..7ff198fa 100644 --- a/library/server/ewsgi/default/nino/default_wgi_application.e +++ b/library/server/ewsgi/default/nino/default_wgi_application.e @@ -15,14 +15,20 @@ feature {NONE} -- Initialization local app: NINO_APPLICATION do - port_number := 8123 - print ("Example: start a Nino web server on port " + port_number.out + ", %Nand reply Hello World for any request such as http://localhost:" + port_number.out + "/%N") - create app.make_custom (agent execute, "") + port_number := 80 + base_url := "" + debug ("nino") + print ("Example: start a Nino web server on port " + port_number.out + + ", %Nand reply Hello World for any request such as http://localhost:" + port_number.out + "/" + base_url + "%N") + end + create app.make_custom (agent execute, base_url) app.listen (port_number) end port_number: INTEGER + base_url: STRING + invariant port_number_valid: port_number > 0 note From 0c7e6c08e79081fafde56616d91565d5d92b945c Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Fri, 9 Sep 2011 08:50:29 +0200 Subject: [PATCH 2/9] better type for argument and result (using READABLE_...) --- library/protocol/http/src/http_format_constants.e | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/protocol/http/src/http_format_constants.e b/library/protocol/http/src/http_format_constants.e index 3b4d91ba..b5d00397 100644 --- a/library/protocol/http/src/http_format_constants.e +++ b/library/protocol/http/src/http_format_constants.e @@ -38,11 +38,11 @@ feature -- Name feature -- Query - format_id (a_id: STRING): INTEGER + format_id (a_id: READABLE_STRING_GENERAL): INTEGER local s: STRING do - s := a_id.as_lower + s := a_id.as_string_8.as_lower if s.same_string (json_name) then Result := json elseif s.same_string (xml_name) then @@ -58,7 +58,7 @@ feature -- Query end end - format_name (a_id: INTEGER): STRING + format_name (a_id: INTEGER): READABLE_STRING_8 do inspect a_id when json then Result := json_name @@ -74,7 +74,7 @@ feature -- Query end note - copyright: "Copyright (c) 1984-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)" source: "[ Eiffel Software From 9ec87a43296185a78b1b801f67d7bb7c7800a035 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Fri, 9 Sep 2011 08:51:45 +0200 Subject: [PATCH 3/9] Added support during match for {/vars} and also handle cases such as /foo.{format}{/vars} or /foo.{format}{?vars} where no literal exists between the uri template expressions --- .../protocol/uri_template/src/uri_template.e | 44 ++++++++++++++++--- .../uri_template/tests/test_uri_template.e | 21 ++++++--- 2 files changed, 53 insertions(+), 12 deletions(-) diff --git a/library/protocol/uri_template/src/uri_template.e b/library/protocol/uri_template/src/uri_template.e index ddc9d0c6..73bd7255 100644 --- a/library/protocol/uri_template/src/uri_template.e +++ b/library/protocol/uri_template/src/uri_template.e @@ -159,10 +159,10 @@ feature -- Match b: BOOLEAN tpl: like template l_offset: INTEGER - p,q: INTEGER + p,q,nb: INTEGER exp: URI_TEMPLATE_EXPRESSION vn, s,t: STRING - vv: STRING + vv, path_vv: STRING l_vars, l_path_vars, l_query_vars: HASH_TABLE [READABLE_STRING_32, READABLE_STRING_GENERAL] l_uri_count: INTEGER tpl_count: INTEGER @@ -196,7 +196,10 @@ feature -- Match if p = q then --| There should be at least one literal between two expression --| {var}{foobar} is ambigous for matching ... - b := False + --| unless with {/var} or {?var} ... since we can search for '/' or '?' + exp.analyze + b := exp.operator = '/' or exp.operator = '?' + p := exp.end_position elseif q > p then if p = 0 then p := 1 @@ -227,15 +230,42 @@ feature -- Match else if not l_expressions.after then exp := l_expressions.item --| We change `exp' here - l_next_literal_separator := tpl.substring (p, exp.position -1) + exp.analyze + if exp.operator = '/' or exp.operator = '?' then + l_next_literal_separator := Void + else + l_next_literal_separator := tpl.substring (p, exp.position -1) + end elseif p < tpl_count then l_next_literal_separator := tpl.substring (p, tpl_count) else l_next_literal_separator := Void end - vv := next_path_variable_value (a_uri, q + l_offset, l_next_literal_separator) - l_vars.force (vv, vn) - l_offset := l_offset + vv.count - (vn.count + 2) + if vn[1] = '/' then + vn := vn.substring (2, vn.count) + from + create path_vv.make_empty + vv := "/" + nb := 0 + until + vv.is_empty or q + l_offset > a_uri.count + loop + vv := next_path_variable_value (a_uri, q + l_offset + 1, l_next_literal_separator) + l_offset := l_offset + vv.count + 1 + nb := nb + 1 + if not vv.is_empty then + path_vv.extend ('/') + path_vv.append (vv) + l_vars.force (vv, vn + "[" + nb.out + "]") + end + end + l_vars.force (path_vv, vn) + l_offset := l_offset - (1 + vn.count + 2) + else + vv := next_path_variable_value (a_uri, q + l_offset, l_next_literal_separator) + l_vars.force (vv, vn) + l_offset := l_offset + vv.count - (vn.count + 2) + end end else b := exp.is_query --| query are optional diff --git a/library/protocol/uri_template/tests/test_uri_template.e b/library/protocol/uri_template/tests/test_uri_template.e index 77fa2700..4c1a2a1d 100644 --- a/library/protocol/uri_template/tests/test_uri_template.e +++ b/library/protocol/uri_template/tests/test_uri_template.e @@ -23,7 +23,7 @@ feature -- Test routines uri_template_parse ("weather/{state}/{city}?forecast={day}", <<"state", "city">>, <<"day">>) uri_template_parse ("/hello/{name}.{format}", <<"name", "format">>, <<>>) uri_template_parse ("/hello.{format}/{name}", <<"format", "name">>, <<>>) - uri_template_parse ("/hello/Joce.{format}/foo{?foobar};crazy=IDEA", <<"name">>, <<"foobar">>) +-- uri_template_parse ("/hello/{name}.{format}/foo{?foobar};crazy=IDEA", <<"name", "format">>, <<"foobar">>) end test_uri_template_matcher @@ -32,6 +32,13 @@ feature -- Test routines local tpl: URI_TEMPLATE do + create tpl.make ("/hello.{format}{/vars}") + uri_template_match (tpl, "/hello.json/foo/bar", <<["format", "json"], ["vars", "/foo/bar"], ["vars[1]", "foo"], ["vars[2]", "bar"]>>, <<>>) + + create tpl.make ("/hello.{format}{?op}") + uri_template_match (tpl, "/hello.json?op=foobar", <<["format", "json"]>>, << ["op", "foobar"]>>) + + create tpl.make ("{version}/{id}") uri_template_match (tpl, "v2/123", <<["version", "v2"], ["id" , "123"]>>, <<>>) @@ -73,10 +80,14 @@ feature -- Test routines uri_template_match (tpl, "/hello/Joce.xml/foo", <<["name", "Joce"], ["format", "xml"]>>, <<>>) uri_template_mismatch (tpl, "/hello/Joce.xml/fooBAR") - create tpl.make ("/hello/{name}.{format}/foo{?foo};crazy={idea}") --- uri_template_match (tpl, "/hello/Joce.xml/foo", <<["name", "Joce"], ["format", "xml"]>>, <<>>) - uri_template_match (tpl, "/hello/Joce.xml/foo?foo=FOO", <<["name", "Joce"], ["format", "xml"]>>, <<["foo", "FOO"]>>) - uri_template_match (tpl, "/hello/Joce.xml/foo;crazy=IDEA", <<["name", "Joce"], ["format", "xml"]>>, <<["idea", "IDEA"], ["crazy", "IDEA"]>>) + create tpl.make ("/hello{/vars}") + uri_template_match (tpl, "/hello/foo/bar", <<["vars", "/foo/bar"], ["vars[1]", "foo"], ["vars[2]", "bar"]>>, <<>>) + + +-- create tpl.make ("/hello/{name}.{format}/foo{?foo};crazy={idea}") +---- uri_template_match (tpl, "/hello/Joce.xml/foo", <<["name", "Joce"], ["format", "xml"]>>, <<>>) +-- uri_template_match (tpl, "/hello/Joce.xml/foo?foo=FOO", <<["name", "Joce"], ["format", "xml"]>>, <<["foo", "FOO"]>>) +-- uri_template_match (tpl, "/hello/Joce.xml/foo;crazy=IDEA", <<["name", "Joce"], ["format", "xml"]>>, <<["idea", "IDEA"], ["crazy", "IDEA"]>>) end From 11286eeeef299a5f4b9a35ac4a3da379e5913257 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Fri, 9 Sep 2011 14:10:54 +0200 Subject: [PATCH 4/9] make router more easy to inherit from and specialized --- .../src/hello_routed_world.e | 2 +- library/server/request/router/router-safe.ecf | 8 +- .../src/application/routed_application.e | 7 +- .../src/context/request_handler_context.e | 47 +++++++- .../router/src/handler/request_handler.e | 104 ++++-------------- .../src/helper}/routed_application_helper.e | 62 ++--------- .../router/src/router/request_router.e | 52 +++++++-- .../router/src/router/request_uri_router.e | 29 +++-- .../src/router/request_uri_template_router.e | 28 +++-- 9 files changed, 164 insertions(+), 175 deletions(-) rename {examples/hello_routed_world/src/framework => library/server/request/router/src/helper}/routed_application_helper.e (55%) 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)" From 32197d051312f90e4f698c15ba4b6e1a9061f9a4 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Fri, 9 Sep 2011 16:24:11 +0200 Subject: [PATCH 5/9] changing design to use generic instead of anchor types --- .../src/hello_routed_world.e | 26 +++++------- .../src/application/routed_application.e | 4 +- .../src/default/default_request_uri_router.e | 39 ++++++++++++++++++ .../default_request_uri_template_router.e | 40 +++++++++++++++++++ .../src/default/default_routed_application.e | 23 +++++++++++ .../default/default_uri_routed_application.e | 30 ++++++++++++++ .../default_uri_template_routed_application.e | 30 ++++++++++++++ .../src/handler/request_agent_handler.e | 8 ++-- .../router/src/handler/request_handler.e | 6 +-- .../router/src/router/request_router.e | 33 ++++++++------- .../router/src/router/request_uri_router.e | 35 ++++++++-------- .../src/router/request_uri_template_router.e | 31 +++++++------- 12 files changed, 236 insertions(+), 69 deletions(-) create mode 100644 library/server/request/router/src/default/default_request_uri_router.e create mode 100644 library/server/request/router/src/default/default_request_uri_template_router.e create mode 100644 library/server/request/router/src/default/default_routed_application.e create mode 100644 library/server/request/router/src/default/default_uri_routed_application.e create mode 100644 library/server/request/router/src/default/default_uri_template_routed_application.e diff --git a/examples/hello_routed_world/src/hello_routed_world.e b/examples/hello_routed_world/src/hello_routed_world.e index ad5487c7..daad0e8e 100644 --- a/examples/hello_routed_world/src/hello_routed_world.e +++ b/examples/hello_routed_world/src/hello_routed_world.e @@ -10,7 +10,7 @@ class inherit ANY - ROUTED_APPLICATION + DEFAULT_URI_TEMPLATE_ROUTED_APPLICATION ROUTED_APPLICATION_HELPER @@ -29,18 +29,12 @@ feature {NONE} -- Initialization create_router 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_TEMPLATE_ROUTER} router.make (5) + create router.make (5) end setup_router local - ra: REQUEST_AGENT_HANDLER + ra: REQUEST_AGENT_HANDLER [REQUEST_URI_TEMPLATE_HANDLER_CONTEXT] do router.map_agent ("/home", agent execute_home) @@ -107,7 +101,7 @@ feature -- Execution res.flush end - execute_home (ctx: REQUEST_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + execute_home (ctx: REQUEST_URI_TEMPLATE_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) do res.write_header (200, <<["Content-Type", "text/html"]>>) res.write_string ("Hello World ?!%N") @@ -171,33 +165,33 @@ feature -- Execution end end - handle_hello (ctx: REQUEST_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + handle_hello (ctx: REQUEST_URI_TEMPLATE_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) do execute_hello (req, res, Void, ctx) end - handle_anonymous_hello (ctx: REQUEST_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + handle_anonymous_hello (ctx: REQUEST_URI_TEMPLATE_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) do execute_hello (req, res, ctx.parameter ("name"), ctx) end - handle_method_any (ctx: REQUEST_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + handle_method_any (ctx: REQUEST_URI_TEMPLATE_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) + handle_method_get (ctx: REQUEST_URI_TEMPLATE_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) + handle_method_post (ctx: REQUEST_URI_TEMPLATE_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) + handle_method_get_or_post (ctx: REQUEST_URI_TEMPLATE_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) do execute_hello (req, res, "GET or POST", ctx) end diff --git a/library/server/request/router/src/application/routed_application.e b/library/server/request/router/src/application/routed_application.e index 5cb24525..8c6d4313 100644 --- a/library/server/request/router/src/application/routed_application.e +++ b/library/server/request/router/src/application/routed_application.e @@ -5,7 +5,7 @@ note revision: "$Revision$" deferred class - ROUTED_APPLICATION + ROUTED_APPLICATION [H -> REQUEST_HANDLER [C], C -> REQUEST_HANDLER_CONTEXT] feature -- Setup @@ -30,7 +30,7 @@ feature -- Setup deferred end - router: REQUEST_ROUTER + router: REQUEST_ROUTER [H, C] -- Request router feature -- Execution diff --git a/library/server/request/router/src/default/default_request_uri_router.e b/library/server/request/router/src/default/default_request_uri_router.e new file mode 100644 index 00000000..2c96678f --- /dev/null +++ b/library/server/request/router/src/default/default_request_uri_router.e @@ -0,0 +1,39 @@ +note + description: "Summary description for {DEFAULT_REQUEST_URI_ROUTER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + DEFAULT_REQUEST_URI_ROUTER + +inherit + REQUEST_URI_ROUTER [REQUEST_HANDLER [REQUEST_URI_HANDLER_CONTEXT], REQUEST_URI_HANDLER_CONTEXT] + redefine + map_agent_with_request_methods + end +create + make + +feature -- Mapping + + map_agent_with_request_methods (a_id: READABLE_STRING_8; a_action: PROCEDURE [ANY, TUPLE [ctx: REQUEST_URI_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER]]; + rqst_methods: detachable ARRAY [READABLE_STRING_8]) + local + h: REQUEST_AGENT_HANDLER [REQUEST_URI_HANDLER_CONTEXT] + do + create h.make (a_action) + map_with_request_methods (a_id, h, rqst_methods) + end + +note + copyright: "2011-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/router/src/default/default_request_uri_template_router.e b/library/server/request/router/src/default/default_request_uri_template_router.e new file mode 100644 index 00000000..8ed69b4c --- /dev/null +++ b/library/server/request/router/src/default/default_request_uri_template_router.e @@ -0,0 +1,40 @@ +note + description: "Summary description for {DEFAULT_REQUEST_URI_TEMPLATE_ROUTER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + DEFAULT_REQUEST_URI_TEMPLATE_ROUTER + +inherit + REQUEST_URI_TEMPLATE_ROUTER [REQUEST_HANDLER [REQUEST_URI_TEMPLATE_HANDLER_CONTEXT], REQUEST_URI_TEMPLATE_HANDLER_CONTEXT] + redefine + map_agent_with_request_methods + end + +create + make + +feature -- Mapping + + map_agent_with_request_methods (a_id: READABLE_STRING_8; a_action: PROCEDURE [ANY, TUPLE [ctx: REQUEST_URI_TEMPLATE_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER]]; + rqst_methods: detachable ARRAY [READABLE_STRING_8]) + local + h: REQUEST_AGENT_HANDLER [REQUEST_URI_TEMPLATE_HANDLER_CONTEXT] + do + create h.make (a_action) + map_with_request_methods (a_id, h, rqst_methods) + end + +note + copyright: "2011-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/router/src/default/default_routed_application.e b/library/server/request/router/src/default/default_routed_application.e new file mode 100644 index 00000000..1113a09f --- /dev/null +++ b/library/server/request/router/src/default/default_routed_application.e @@ -0,0 +1,23 @@ +note + description: "Summary description for {DEFAULT_ROUTED_APPLICATION}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + DEFAULT_ROUTED_APPLICATION + +inherit + ROUTED_APPLICATION [REQUEST_HANDLER [REQUEST_HANDLER_CONTEXT], REQUEST_HANDLER_CONTEXT] + +note + copyright: "2011-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/router/src/default/default_uri_routed_application.e b/library/server/request/router/src/default/default_uri_routed_application.e new file mode 100644 index 00000000..831f134d --- /dev/null +++ b/library/server/request/router/src/default/default_uri_routed_application.e @@ -0,0 +1,30 @@ +note + description: "Summary description for {DEFAULT_URI_ROUTED_APPLICATION}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + DEFAULT_URI_ROUTED_APPLICATION + +inherit + ROUTED_APPLICATION [REQUEST_HANDLER [REQUEST_URI_HANDLER_CONTEXT], REQUEST_URI_HANDLER_CONTEXT] + redefine + router + end + +feature -- Router + + router: DEFAULT_REQUEST_URI_ROUTER + +;note + copyright: "2011-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/router/src/default/default_uri_template_routed_application.e b/library/server/request/router/src/default/default_uri_template_routed_application.e new file mode 100644 index 00000000..155b1aa0 --- /dev/null +++ b/library/server/request/router/src/default/default_uri_template_routed_application.e @@ -0,0 +1,30 @@ +note + description: "Summary description for {DEFAULT_URI_TEMPLATE_ROUTED_APPLICATION}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + DEFAULT_URI_TEMPLATE_ROUTED_APPLICATION + +inherit + ROUTED_APPLICATION [REQUEST_HANDLER [REQUEST_URI_TEMPLATE_HANDLER_CONTEXT], REQUEST_URI_TEMPLATE_HANDLER_CONTEXT] + redefine + router + end + +feature -- Router + + router: DEFAULT_REQUEST_URI_TEMPLATE_ROUTER + +;note + copyright: "2011-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/router/src/handler/request_agent_handler.e b/library/server/request/router/src/handler/request_agent_handler.e index 545df575..962cebc4 100644 --- a/library/server/request/router/src/handler/request_agent_handler.e +++ b/library/server/request/router/src/handler/request_agent_handler.e @@ -5,10 +5,10 @@ note revision: "$Revision$" class - REQUEST_AGENT_HANDLER + REQUEST_AGENT_HANDLER [C -> REQUEST_HANDLER_CONTEXT] inherit - REQUEST_HANDLER + REQUEST_HANDLER [C] create make @@ -23,11 +23,11 @@ feature -- Initialization feature -- Access - action: PROCEDURE [ANY, TUPLE [ctx: REQUEST_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER]] + action: PROCEDURE [ANY, TUPLE [ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER]] feature -- Execution - execute_application (ctx: REQUEST_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + execute_application (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) do action.call ([ctx, req, res]) end diff --git a/library/server/request/router/src/handler/request_handler.e b/library/server/request/router/src/handler/request_handler.e index 9c816624..c87056ce 100644 --- a/library/server/request/router/src/handler/request_handler.e +++ b/library/server/request/router/src/handler/request_handler.e @@ -5,7 +5,7 @@ note revision: "$Revision$" deferred class - REQUEST_HANDLER + REQUEST_HANDLER [C -> REQUEST_HANDLER_CONTEXT] inherit ANY @@ -37,7 +37,7 @@ feature -- Status report feature -- Execution - execute (a_hdl_context: REQUEST_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + execute (a_hdl_context: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) -- Execute request handler require is_valid_context: is_valid_context (req) @@ -60,7 +60,7 @@ feature -- Execution retry end - execute_application (a_hdl_context: REQUEST_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + execute_application (a_hdl_context: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) -- Execute request handler deferred end diff --git a/library/server/request/router/src/router/request_router.e b/library/server/request/router/src/router/request_router.e index a16c9cd7..8177478d 100644 --- a/library/server/request/router/src/router/request_router.e +++ b/library/server/request/router/src/router/request_router.e @@ -5,9 +5,9 @@ note revision: "$Revision$" deferred class - REQUEST_ROUTER + REQUEST_ROUTER [H -> REQUEST_HANDLER [C], C -> REQUEST_HANDLER_CONTEXT] -feature -- Registration +feature -- Mapping map_default (r: like default_handler) -- Map default handler @@ -17,28 +17,33 @@ feature -- Registration set_default_handler (r) end - map (a_id: READABLE_STRING_8; h: REQUEST_HANDLER) + map (a_id: READABLE_STRING_8; h: H) -- 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_with_request_methods (a_id: READABLE_STRING_8; h: H; rqst_methods: detachable ARRAY [READABLE_STRING_8]) -- Map handler `h' with `a_id' and `rqst_methods' deferred end - map_agent (a_id: READABLE_STRING_8; a_action: like {REQUEST_AGENT_HANDLER}.action) + map_agent (a_id: READABLE_STRING_8; a_action: PROCEDURE [ANY, TUPLE [ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER]]) 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]) + map_agent_with_request_methods (a_id: READABLE_STRING_8; a_action: PROCEDURE [ANY, TUPLE [ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER]]; + rqst_methods: detachable ARRAY [READABLE_STRING_8]) local - h: REQUEST_AGENT_HANDLER + rah: REQUEST_AGENT_HANDLER [C] do - create h.make (a_action) - map_with_request_methods (a_id, h, rqst_methods) + create rah.make (a_action) + if attached {H} rah as h then + map_with_request_methods (a_id, h, rqst_methods) + else + check valid_agent_handler: False end + end end feature -- Execution @@ -50,7 +55,7 @@ feature -- Execution Result := dispatch_and_return_handler (req, res) /= Void end - dispatch_and_return_handler (req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER): like default_handler + dispatch_and_return_handler (req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER): detachable H -- Dispatch `req, res' to the associated handler -- And return this handler -- If Result is Void, this means no handler was found. @@ -77,7 +82,7 @@ feature -- Execution feature -- Traversing - new_cursor: ITERATION_CURSOR [TUPLE [handler: REQUEST_HANDLER; resource: READABLE_STRING_8; request_methods: detachable ARRAY [READABLE_STRING_8]]] + new_cursor: ITERATION_CURSOR [TUPLE [handler: H; resource: READABLE_STRING_8; request_methods: detachable ARRAY [READABLE_STRING_8]]] -- Fresh cursor associated with current structure deferred ensure @@ -86,7 +91,7 @@ feature -- Traversing feature {NONE} -- Access: Implementation - handler (req: WGI_REQUEST): detachable TUPLE [handler: attached like default_handler; context: like default_handler_context] + handler (req: WGI_REQUEST): detachable TUPLE [handler: H; context: like default_handler_context] -- Handler whose map matched with `req' require req_valid: req /= Void and then req.path_info /= Void @@ -146,12 +151,12 @@ feature {NONE} -- Implementation default_handler_set: h = default_handler end - default_handler: detachable REQUEST_HANDLER + default_handler: detachable H -- Default handler deferred end - default_handler_context (req: WGI_REQUEST): REQUEST_HANDLER_CONTEXT + default_handler_context (req: WGI_REQUEST): C -- Default handler context associated with `default_handler' require has_default_handler: default_handler /= Void 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 4480a354..eb272ad7 100644 --- a/library/server/request/router/src/router/request_uri_router.e +++ b/library/server/request/router/src/router/request_uri_router.e @@ -5,10 +5,10 @@ note revision: "$Revision$" class - REQUEST_URI_ROUTER + REQUEST_URI_ROUTER [H -> REQUEST_HANDLER [C], C -> REQUEST_URI_HANDLER_CONTEXT create make end] inherit - REQUEST_ROUTER + REQUEST_ROUTER [H, C] create make @@ -23,16 +23,16 @@ feature -- Initialization feature -- Registration - map_with_request_methods (p: READABLE_STRING_8; h: REQUEST_HANDLER; rqst_methods: detachable ARRAY [READABLE_STRING_8]) + map_with_request_methods (p: READABLE_STRING_8; h: H; rqst_methods: detachable ARRAY [READABLE_STRING_8]) do handlers.force ([h, p, formatted_request_methods (rqst_methods)]) end feature {NONE} -- Access: Implementation - handler (req: WGI_REQUEST): detachable TUPLE [handler: REQUEST_HANDLER; context: like default_handler_context] + handler (req: WGI_REQUEST): detachable TUPLE [handler: H; context: like default_handler_context] local - h: detachable REQUEST_HANDLER + h: detachable H ctx: detachable like default_handler_context do h := handler_by_path (req.path_info, req.request_method) @@ -54,7 +54,7 @@ feature {NONE} -- Access: Implementation end end - smart_handler (req: WGI_REQUEST): detachable TUPLE [path: READABLE_STRING_8; handler: REQUEST_HANDLER] + smart_handler (req: WGI_REQUEST): detachable TUPLE [path: READABLE_STRING_8; handler: H] require req_valid: req /= Void and then req.path_info /= Void do @@ -63,7 +63,7 @@ feature {NONE} -- Access: Implementation req_path_info_unchanged: req.path_info.same_string (old req.path_info) end - handler_by_path (a_path: READABLE_STRING_GENERAL; rqst_method: READABLE_STRING_GENERAL): detachable REQUEST_HANDLER + handler_by_path (a_path: READABLE_STRING_GENERAL; rqst_method: READABLE_STRING_GENERAL): detachable H require a_path_valid: a_path /= Void local @@ -86,13 +86,13 @@ feature {NONE} -- Access: Implementation a_path_unchanged: a_path.same_string (old a_path) end - smart_handler_by_path (a_path: READABLE_STRING_8; rqst_method: READABLE_STRING_GENERAL): detachable TUPLE [path: READABLE_STRING_8; handler: REQUEST_HANDLER] + smart_handler_by_path (a_path: READABLE_STRING_8; rqst_method: READABLE_STRING_GENERAL): 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 REQUEST_HANDLER + h: detachable H do l_context_path := context_path (a_path) from @@ -116,18 +116,21 @@ feature {NONE} -- Access: Implementation feature {NONE} -- Context factory - handler_context (p: detachable STRING; req: WGI_REQUEST): like default_handler_context + handler_context (p: detachable STRING; req: WGI_REQUEST): C + local + ctx: C do if p /= Void then - create {REQUEST_URI_HANDLER_CONTEXT} Result.make (req, p) + create ctx.make (req, p) else - create {REQUEST_URI_HANDLER_CONTEXT} Result.make (req, req.path_info) + create ctx.make (req, req.path_info) end + Result := ctx end feature -- Access - new_cursor: ITERATION_CURSOR [TUPLE [handler: REQUEST_HANDLER; resource: READABLE_STRING_8; request_methods: detachable ARRAY [READABLE_STRING_8]]] + new_cursor: ITERATION_CURSOR [TUPLE [handler: H; resource: READABLE_STRING_8; request_methods: detachable ARRAY [READABLE_STRING_8]]] -- Fresh cursor associated with current structure do Result := handlers.new_cursor @@ -135,7 +138,7 @@ feature -- Access feature {NONE} -- Implementation - handlers: ARRAYED_LIST [TUPLE [handler: REQUEST_HANDLER; resource: READABLE_STRING_8; request_methods: detachable ARRAY [READABLE_STRING_8]]] + handlers: ARRAYED_LIST [TUPLE [handler: H; resource: READABLE_STRING_8; request_methods: detachable ARRAY [READABLE_STRING_8]]] -- Handlers indexed by the template expression -- see `templates' @@ -166,14 +169,14 @@ feature {NONE} -- Implementation feature {NONE} -- Default: implementation - default_handler: detachable REQUEST_HANDLER + default_handler: detachable H set_default_handler (h: like default_handler) do default_handler := h end - default_handler_context (req: WGI_REQUEST): REQUEST_HANDLER_CONTEXT + default_handler_context (req: WGI_REQUEST): C do Result := handler_context (Void, req) end 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 e73e3d11..4183b329 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 @@ -5,10 +5,10 @@ note revision: "$Revision$" class - REQUEST_URI_TEMPLATE_ROUTER + REQUEST_URI_TEMPLATE_ROUTER [H -> REQUEST_HANDLER [C], C -> REQUEST_URI_TEMPLATE_HANDLER_CONTEXT create make end] inherit - REQUEST_ROUTER + REQUEST_ROUTER [H, C] create make @@ -24,25 +24,25 @@ feature -- Initialization feature -- Registration - map_with_uri_template (uri: URI_TEMPLATE; h: REQUEST_HANDLER) + map_with_uri_template (uri: URI_TEMPLATE; h: H) do 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]) + map_with_uri_template_and_request_methods (uri: URI_TEMPLATE; h: H; rqst_methods: detachable ARRAY [READABLE_STRING_8]) do handlers.force ([h, uri.template, formatted_request_methods (rqst_methods)]) templates.force (uri, uri.template) end - map_with_request_methods (tpl: READABLE_STRING_8; h: REQUEST_HANDLER; rqst_methods: detachable ARRAY [READABLE_STRING_8]) + map_with_request_methods (tpl: READABLE_STRING_8; h: H; rqst_methods: detachable ARRAY [READABLE_STRING_8]) local uri: URI_TEMPLATE do create uri.make (tpl) map_with_uri_template_and_request_methods (uri, h, rqst_methods) end - + feature {NONE} -- Access: Implementation handler (req: WGI_REQUEST): detachable TUPLE [handler: attached like default_handler; context: like default_handler_context] @@ -76,18 +76,18 @@ feature {NONE} -- Access: Implementation feature {NONE} -- Context factory - handler_context (p: detachable STRING; req: WGI_REQUEST; tpl: URI_TEMPLATE; tpl_res: URI_TEMPLATE_MATCH_RESULT): like default_handler_context + handler_context (p: detachable STRING; req: WGI_REQUEST; tpl: URI_TEMPLATE; tpl_res: URI_TEMPLATE_MATCH_RESULT): C do if p /= Void then - create {REQUEST_URI_TEMPLATE_HANDLER_CONTEXT} Result.make (req, tpl, tpl_res, p) + create Result.make (req, tpl, tpl_res, p) else - create {REQUEST_URI_TEMPLATE_HANDLER_CONTEXT} Result.make (req, tpl, tpl_res, req.path_info) + create Result.make (req, tpl, tpl_res, req.path_info) end end feature -- Access: ITERABLE - new_cursor: ITERATION_CURSOR [TUPLE [handler: REQUEST_HANDLER; resource: READABLE_STRING_8; request_methods: detachable ARRAY [READABLE_STRING_8]]] + new_cursor: ITERATION_CURSOR [TUPLE [handler: H; resource: READABLE_STRING_8; request_methods: detachable ARRAY [READABLE_STRING_8]]] -- Fresh cursor associated with current structure do Result := handlers.new_cursor @@ -95,7 +95,7 @@ feature -- Access: ITERABLE feature {NONE} -- Implementation - handlers: ARRAYED_LIST [TUPLE [handler: REQUEST_HANDLER; resource: READABLE_STRING_8; request_methods: detachable ARRAY [READABLE_STRING_8]]] + handlers: ARRAYED_LIST [TUPLE [handler: H; resource: READABLE_STRING_8; request_methods: detachable ARRAY [READABLE_STRING_8]]] -- Handlers indexed by the template expression -- see `templates' @@ -126,16 +126,19 @@ feature {NONE} -- Implementation feature {NONE} -- Default: implementation - default_handler: detachable REQUEST_HANDLER + default_handler: detachable H set_default_handler (h: like default_handler) do default_handler := h end - default_handler_context (req: WGI_REQUEST): REQUEST_HANDLER_CONTEXT + default_handler_context (req: WGI_REQUEST): C + local + tpl: URI_TEMPLATE do - create {REQUEST_URI_HANDLER_CONTEXT} Result.make (req, "/") + create tpl.make ("/") + Result := handler_context ("/", req, tpl, create {URI_TEMPLATE_MATCH_RESULT}.make_empty) end ;note From f0c6eec23d9ea3a4260b04a194b358748b60ec59 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Tue, 13 Sep 2011 16:49:45 +0200 Subject: [PATCH 6/9] adding routing handler few renaming --- .../src/context/request_handler_context.e | 24 +++--- ...ult_request_uri_template_routing_handler.e | 33 +++++++++ .../router/src/handler/request_handler.e | 20 ++--- .../src/handler/request_routing_handler.e | 73 +++++++++++++++++++ .../src/handler/request_uri_routing_handler.e | 38 ++++++++++ .../request_uri_template_routing_handler.e | 38 ++++++++++ .../router/src/router/request_router.e | 28 ++++--- .../src/router/request_uri_template_router.e | 13 +++- 8 files changed, 233 insertions(+), 34 deletions(-) create mode 100644 library/server/request/router/src/default/default_request_uri_template_routing_handler.e create mode 100644 library/server/request/router/src/handler/request_routing_handler.e create mode 100644 library/server/request/router/src/handler/request_uri_routing_handler.e create mode 100644 library/server/request/router/src/handler/request_uri_template_routing_handler.e 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 666ff7ca..92dcf745 100644 --- a/library/server/request/router/src/context/request_handler_context.e +++ b/library/server/request/router/src/context/request_handler_context.e @@ -15,11 +15,6 @@ inherit {NONE} all end - HTTP_FORMAT_CONSTANTS - export - {NONE} all - end - feature -- Access request: WGI_REQUEST @@ -28,9 +23,17 @@ feature -- Access path: READABLE_STRING_8 -- Associated path - request_format (a_format_variable_name: detachable STRING; content_type_supported: detachable ARRAY [STRING]): detachable READABLE_STRING_8 +feature {NONE} -- Constants + + Format_constants: HTTP_FORMAT_CONSTANTS + once + create Result + end + +feature -- Query + + request_format (a_format_variable_name: detachable READABLE_STRING_GENERAL; content_type_supported: detachable ARRAY [READABLE_STRING_8]): 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 @@ -38,13 +41,12 @@ feature -- Access 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 + request_format_id (a_format_variable_name: detachable READABLE_STRING_GENERAL; content_type_supported: detachable ARRAY [READABLE_STRING_8]): 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) + Result := Format_constants.format_id (l_format) else Result := 0 end @@ -68,7 +70,7 @@ feature -- Access end end - request_content_type (content_type_supported: detachable ARRAY [STRING]): detachable READABLE_STRING_8 + request_content_type (content_type_supported: detachable ARRAY [READABLE_STRING_8]): detachable READABLE_STRING_8 local s: detachable READABLE_STRING_32 i,n: INTEGER diff --git a/library/server/request/router/src/default/default_request_uri_template_routing_handler.e b/library/server/request/router/src/default/default_request_uri_template_routing_handler.e new file mode 100644 index 00000000..f042fa00 --- /dev/null +++ b/library/server/request/router/src/default/default_request_uri_template_routing_handler.e @@ -0,0 +1,33 @@ +note + description: "Summary description for {DEFAULT_REQUEST_URI_TEMPLATE_ROUTING_HANDLER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + DEFAULT_REQUEST_URI_TEMPLATE_ROUTING_HANDLER + +inherit + REQUEST_URI_TEMPLATE_ROUTING_HANDLER [REQUEST_HANDLER [REQUEST_URI_TEMPLATE_HANDLER_CONTEXT], REQUEST_URI_TEMPLATE_HANDLER_CONTEXT] + redefine + router + end + +create + make + +feature {NONE} -- Routing + + router: DEFAULT_REQUEST_URI_TEMPLATE_ROUTER + +;note + copyright: "2011-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/router/src/handler/request_handler.e b/library/server/request/router/src/handler/request_handler.e index c87056ce..a9908338 100644 --- a/library/server/request/router/src/handler/request_handler.e +++ b/library/server/request/router/src/handler/request_handler.e @@ -37,7 +37,7 @@ feature -- Status report feature -- Execution - execute (a_hdl_context: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + execute (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) -- Execute request handler require is_valid_context: is_valid_context (req) @@ -46,42 +46,42 @@ feature -- Execution do if not rescued then if request_method_name_supported (req.request_method) then - pre_execute (req) - execute_application (a_hdl_context, req, res) - post_execute (req, res) + pre_execute (ctx, req, res) + execute_application (ctx, req, res) + post_execute (ctx, req, res) else execute_request_method_not_allowed (req, res, supported_request_method_names) end else - rescue_execute (req, res) + rescue_execute (ctx, req, res) end rescue rescued := True retry end - execute_application (a_hdl_context: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + execute_application (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) -- Execute request handler deferred end - pre_execute (req: WGI_REQUEST) + pre_execute (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) -- Operation processed before `execute' do --| To be redefined if needed end - post_execute (req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + post_execute (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) -- Operation processed after `execute' do --| To be redefined if needed end - rescue_execute (req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + rescue_execute (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) -- Operation processed after a rescue do --| To be redefined if needed - post_execute (req, res) + post_execute (ctx, req, res) end feature -- Execution: report diff --git a/library/server/request/router/src/handler/request_routing_handler.e b/library/server/request/router/src/handler/request_routing_handler.e new file mode 100644 index 00000000..117dba77 --- /dev/null +++ b/library/server/request/router/src/handler/request_routing_handler.e @@ -0,0 +1,73 @@ +note + description: "Summary description for {REQUEST_ROUTING_HANDLER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + REQUEST_ROUTING_HANDLER [H -> REQUEST_HANDLER [C], + C -> REQUEST_HANDLER_CONTEXT] + +inherit + REQUEST_HANDLER [C] + +feature -- Execution + + execute_application (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + -- Execute request handler + local + hdl: detachable H + do + hdl := router.dispatch_and_return_handler (req, res) + end + +feature {NONE} -- Routing + + router: REQUEST_ROUTER [H, C] + deferred + end + +feature -- Mapping + + map_default (h: detachable H) + -- Map default handler + -- If no route/handler is found, + -- then use `default_handler' as default if not Void + do + router.map_default (h) + end + + 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 ARRAY [READABLE_STRING_8]) + -- 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: WGI_REQUEST; res: WGI_RESPONSE_BUFFER]]) + 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: WGI_REQUEST; res: WGI_RESPONSE_BUFFER]]; + rqst_methods: detachable ARRAY [READABLE_STRING_8]) + do + router.map_agent_with_request_methods (a_resource, a_action, rqst_methods) + end + +note + copyright: "2011-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/router/src/handler/request_uri_routing_handler.e b/library/server/request/router/src/handler/request_uri_routing_handler.e new file mode 100644 index 00000000..ff522762 --- /dev/null +++ b/library/server/request/router/src/handler/request_uri_routing_handler.e @@ -0,0 +1,38 @@ +note + description: "Summary description for {REQUEST_ROUTING_HANDLER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + REQUEST_URI_ROUTING_HANDLER [H -> REQUEST_HANDLER [C], + C -> REQUEST_URI_HANDLER_CONTEXT create make end] + +inherit + REQUEST_ROUTING_HANDLER [H, C] + +create + make + +feature {NONE} -- Initialization + + make (n: INTEGER) + do + create router.make (n) + end + +feature {NONE} -- Routing + + router: REQUEST_URI_ROUTER [H, C] + +;note + copyright: "2011-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/router/src/handler/request_uri_template_routing_handler.e b/library/server/request/router/src/handler/request_uri_template_routing_handler.e new file mode 100644 index 00000000..dac329c4 --- /dev/null +++ b/library/server/request/router/src/handler/request_uri_template_routing_handler.e @@ -0,0 +1,38 @@ +note + description: "Summary description for {REQUEST_ROUTING_HANDLER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + REQUEST_URI_TEMPLATE_ROUTING_HANDLER [H -> REQUEST_HANDLER [C], + C -> REQUEST_URI_TEMPLATE_HANDLER_CONTEXT create make end] + +inherit + REQUEST_ROUTING_HANDLER [H, C] + +create + make + +feature {NONE} -- Initialization + + make (n: INTEGER) + do + create router.make (n) + end + +feature {NONE} -- Routing + + router: REQUEST_URI_TEMPLATE_ROUTER [H, C] + +;note + copyright: "2011-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/router/src/router/request_router.e b/library/server/request/router/src/router/request_router.e index 8177478d..5f6ee322 100644 --- a/library/server/request/router/src/router/request_router.e +++ b/library/server/request/router/src/router/request_router.e @@ -9,38 +9,44 @@ deferred class feature -- Mapping - map_default (r: like default_handler) + map_default (h: like default_handler) -- Map default handler -- If no route/handler is found, -- then use `default_handler' as default if not Void do - set_default_handler (r) + set_default_handler (h) end - map (a_id: READABLE_STRING_8; h: H) - -- Map handler `h' with `a_id' + map (a_resource: READABLE_STRING_8; h: H) + -- Map handler `h' with `a_resource' do - map_with_request_methods (a_id, h, Void) + map_with_request_methods (a_resource, h, Void) end - map_with_request_methods (a_id: READABLE_STRING_8; h: H; rqst_methods: detachable ARRAY [READABLE_STRING_8]) - -- Map handler `h' with `a_id' and `rqst_methods' + map_routing (a_resource: READABLE_STRING_8; h: H) + -- Map handler `h' with `a_resource' + do + map (a_resource, h) + end + + map_with_request_methods (a_resource: READABLE_STRING_8; h: H; rqst_methods: detachable ARRAY [READABLE_STRING_8]) + -- Map handler `h' with `a_resource' and `rqst_methods' deferred end - map_agent (a_id: READABLE_STRING_8; a_action: PROCEDURE [ANY, TUPLE [ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER]]) + map_agent (a_resource: READABLE_STRING_8; a_action: PROCEDURE [ANY, TUPLE [ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER]]) do - map_agent_with_request_methods (a_id, a_action, Void) + map_agent_with_request_methods (a_resource, a_action, Void) end - map_agent_with_request_methods (a_id: READABLE_STRING_8; a_action: PROCEDURE [ANY, TUPLE [ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER]]; + map_agent_with_request_methods (a_resource: READABLE_STRING_8; a_action: PROCEDURE [ANY, TUPLE [ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER]]; rqst_methods: detachable ARRAY [READABLE_STRING_8]) local rah: REQUEST_AGENT_HANDLER [C] do create rah.make (a_action) if attached {H} rah as h then - map_with_request_methods (a_id, h, rqst_methods) + map_with_request_methods (a_resource, h, rqst_methods) else check valid_agent_handler: False end end 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 4183b329..adba8c02 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 @@ -42,7 +42,7 @@ feature -- Registration create uri.make (tpl) map_with_uri_template_and_request_methods (uri, h, rqst_methods) end - + feature {NONE} -- Access: Implementation handler (req: WGI_REQUEST): detachable TUPLE [handler: attached like default_handler; context: like default_handler_context] @@ -51,6 +51,7 @@ feature {NONE} -- Access: Implementation t: STRING p: STRING l_req_method: READABLE_STRING_GENERAL + l_res: URI_TEMPLATE_MATCH_RESULT do p := req.request_uri from @@ -63,7 +64,15 @@ feature {NONE} -- Access: Implementation 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 templates.item (t) as tpl and then + if + attached {REQUEST_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, p.count), "path") + + Result := [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 Result := [l_info.handler, handler_context (p, req, tpl, res)] From 92105ca7b31ae67a2faf23167366273ffa3a3a19 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Tue, 13 Sep 2011 17:07:17 +0200 Subject: [PATCH 7/9] updated config file and examples --- .../src/hello_routed_world.e | 20 ++++++++++++++----- library/server/request/router/router-safe.ecf | 2 -- library/server/request/router/router.ecf | 4 +--- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/examples/hello_routed_world/src/hello_routed_world.e b/examples/hello_routed_world/src/hello_routed_world.e index daad0e8e..c34f3bcd 100644 --- a/examples/hello_routed_world/src/hello_routed_world.e +++ b/examples/hello_routed_world/src/hello_routed_world.e @@ -35,17 +35,27 @@ feature {NONE} -- Initialization setup_router local ra: REQUEST_AGENT_HANDLER [REQUEST_URI_TEMPLATE_HANDLER_CONTEXT] + rag: DEFAULT_REQUEST_URI_TEMPLATE_ROUTING_HANDLER do router.map_agent ("/home", agent execute_home) + create rag.make (3) + create ra.make (agent handle_hello) - router.map ("/hello/{name}.{format}", ra) - router.map ("/hello.{format}/{name}", ra) - router.map ("/hello/{name}", ra) + rag.map ("/hello/{name}.{format}", ra) + rag.map ("/hello.{format}/{name}", ra) + rag.map ("/hello/{name}", ra) +-- router.map ("/hello/{name}.{format}", ra) +-- router.map ("/hello.{format}/{name}", ra) +-- router.map ("/hello/{name}", ra) create ra.make (agent handle_anonymous_hello) - router.map ("/hello", ra) - router.map ("/hello.{format}", ra) + rag.map ("/hello", ra) + rag.map ("/hello.{format}", ra) +-- router.map ("/hello", ra) +-- router.map ("/hello.{format}", ra) + + router.map ("/hello", rag) 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">>) diff --git a/library/server/request/router/router-safe.ecf b/library/server/request/router/router-safe.ecf index 040eb070..eba5a022 100644 --- a/library/server/request/router/router-safe.ecf +++ b/library/server/request/router/router-safe.ecf @@ -14,7 +14,6 @@ - @@ -32,7 +31,6 @@ - diff --git a/library/server/request/router/router.ecf b/library/server/request/router/router.ecf index 88790095..b336e855 100644 --- a/library/server/request/router/router.ecf +++ b/library/server/request/router/router.ecf @@ -7,7 +7,7 @@ /EIFGENs$ /.svn$ - @@ -15,7 +15,6 @@ - @@ -33,7 +32,6 @@ - From 512f2d2ce53fd53b7e6e688143eb4ff95a379e84 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Tue, 13 Sep 2011 17:08:40 +0200 Subject: [PATCH 8/9] Added first draft for RESTful library note: the interfaces are likely to change in the future --- library/server/request/rest/license.lic | 1 + library/server/request/rest/rest-safe.ecf | 28 ++ library/server/request/rest/rest.ecf | 28 ++ .../rest/src/application/rest_application.e | 31 ++ .../context/rest_request_handler_context.e | 78 +++++ .../rest_request_uri_handler_context.e | 28 ++ ...est_request_uri_template_handler_context.e | 28 ++ .../rest/src/contrib/doc/html/html_page.e | 184 ++++++++++ .../src/contrib/doc/html/html_page_head.e | 111 ++++++ .../src/contrib/doc/html/html_utilities.e | 90 +++++ .../src/contrib/doc/rest_api_documentation.e | 317 ++++++++++++++++++ .../doc/rest_api_documentation_html_page.e | 124 +++++++ .../rest_api_documentation_html_page_head.e | 75 +++++ .../src/default/default_rest_application.e | 23 ++ .../default_rest_request_uri_handler.e | 24 ++ .../default/default_rest_request_uri_router.e | 40 +++ ...efault_rest_request_uri_template_handler.e | 24 ++ ...default_rest_request_uri_template_router.e | 40 +++ ...est_request_uri_template_routing_handler.e | 33 ++ .../default/default_rest_uri_application.e | 30 ++ .../default_rest_uri_template_application.e | 30 ++ .../src/handler/rest_request_agent_handler.e | 56 ++++ .../src/handler/rest_request_group_handler.e- | 47 +++ .../rest/src/handler/rest_request_handler.e | 165 +++++++++ .../rest_request_uri_routing_handler.e | 51 +++ ...est_request_uri_template_routing_handler.e | 51 +++ .../request/rest/src/response/rest_response.e | 156 +++++++++ .../rest/src/router/rest_request_router.e | 23 ++ .../rest/src/router/rest_request_uri_router.e | 36 ++ .../router/rest_request_uri_template_router.e | 28 ++ .../request/rest/tests/htdocs/.htaccess | 26 ++ .../request/rest/tests/htdocs/README.txt | 31 ++ .../request/rest/tests/htdocs/build.eant | 24 ++ .../server/request/rest/tests/htdocs/htaccess | 26 ++ .../request/rest/tests/htdocs/sample.eapp | 0 library/server/request/rest/tests/sample.ecf | 55 +++ .../src/app/app_account_verify_credential.e | 109 ++++++ .../request/rest/tests/src/app/app_test.e | 95 ++++++ .../request/rest/tests/src/app_server.e | 148 ++++++++ .../gateway/cgi/rest_application_gateway.e | 24 ++ .../gateway/fcgi/rest_application_gateway.e | 35 ++ .../gateway/nino/rest_application_gateway.e | 44 +++ .../rest/tests/src/handler/app_application.e | 30 ++ .../src/handler/app_request_agent_handler.e | 32 ++ .../tests/src/handler/app_request_handler.e | 60 ++++ .../src/handler/app_request_handler_context.e | 86 +++++ .../tests/src/handler/app_request_helper.e | 101 ++++++ .../tests/src/handler/app_request_router.e | 26 ++ .../src/handler/app_request_routing_handler.e | 40 +++ 49 files changed, 2972 insertions(+) create mode 100644 library/server/request/rest/license.lic create mode 100644 library/server/request/rest/rest-safe.ecf create mode 100644 library/server/request/rest/rest.ecf create mode 100644 library/server/request/rest/src/application/rest_application.e create mode 100644 library/server/request/rest/src/context/rest_request_handler_context.e create mode 100644 library/server/request/rest/src/context/rest_request_uri_handler_context.e create mode 100644 library/server/request/rest/src/context/rest_request_uri_template_handler_context.e create mode 100644 library/server/request/rest/src/contrib/doc/html/html_page.e create mode 100644 library/server/request/rest/src/contrib/doc/html/html_page_head.e create mode 100644 library/server/request/rest/src/contrib/doc/html/html_utilities.e create mode 100644 library/server/request/rest/src/contrib/doc/rest_api_documentation.e create mode 100644 library/server/request/rest/src/contrib/doc/rest_api_documentation_html_page.e create mode 100644 library/server/request/rest/src/contrib/doc/rest_api_documentation_html_page_head.e create mode 100644 library/server/request/rest/src/default/default_rest_application.e create mode 100644 library/server/request/rest/src/default/default_rest_request_uri_handler.e create mode 100644 library/server/request/rest/src/default/default_rest_request_uri_router.e create mode 100644 library/server/request/rest/src/default/default_rest_request_uri_template_handler.e create mode 100644 library/server/request/rest/src/default/default_rest_request_uri_template_router.e create mode 100644 library/server/request/rest/src/default/default_rest_request_uri_template_routing_handler.e create mode 100644 library/server/request/rest/src/default/default_rest_uri_application.e create mode 100644 library/server/request/rest/src/default/default_rest_uri_template_application.e create mode 100644 library/server/request/rest/src/handler/rest_request_agent_handler.e create mode 100644 library/server/request/rest/src/handler/rest_request_group_handler.e- create mode 100644 library/server/request/rest/src/handler/rest_request_handler.e create mode 100644 library/server/request/rest/src/handler/rest_request_uri_routing_handler.e create mode 100644 library/server/request/rest/src/handler/rest_request_uri_template_routing_handler.e create mode 100644 library/server/request/rest/src/response/rest_response.e create mode 100644 library/server/request/rest/src/router/rest_request_router.e create mode 100644 library/server/request/rest/src/router/rest_request_uri_router.e create mode 100644 library/server/request/rest/src/router/rest_request_uri_template_router.e create mode 100644 library/server/request/rest/tests/htdocs/.htaccess create mode 100644 library/server/request/rest/tests/htdocs/README.txt create mode 100644 library/server/request/rest/tests/htdocs/build.eant create mode 100644 library/server/request/rest/tests/htdocs/htaccess create mode 100644 library/server/request/rest/tests/htdocs/sample.eapp create mode 100644 library/server/request/rest/tests/sample.ecf create mode 100644 library/server/request/rest/tests/src/app/app_account_verify_credential.e create mode 100644 library/server/request/rest/tests/src/app/app_test.e create mode 100644 library/server/request/rest/tests/src/app_server.e create mode 100644 library/server/request/rest/tests/src/gateway/cgi/rest_application_gateway.e create mode 100644 library/server/request/rest/tests/src/gateway/fcgi/rest_application_gateway.e create mode 100644 library/server/request/rest/tests/src/gateway/nino/rest_application_gateway.e create mode 100644 library/server/request/rest/tests/src/handler/app_application.e create mode 100644 library/server/request/rest/tests/src/handler/app_request_agent_handler.e create mode 100644 library/server/request/rest/tests/src/handler/app_request_handler.e create mode 100644 library/server/request/rest/tests/src/handler/app_request_handler_context.e create mode 100644 library/server/request/rest/tests/src/handler/app_request_helper.e create mode 100644 library/server/request/rest/tests/src/handler/app_request_router.e create mode 100644 library/server/request/rest/tests/src/handler/app_request_routing_handler.e diff --git a/library/server/request/rest/license.lic b/library/server/request/rest/license.lic new file mode 100644 index 00000000..c929225f --- /dev/null +++ b/library/server/request/rest/license.lic @@ -0,0 +1 @@ +reference:forum2 diff --git a/library/server/request/rest/rest-safe.ecf b/library/server/request/rest/rest-safe.ecf new file mode 100644 index 00000000..a6865a9a --- /dev/null +++ b/library/server/request/rest/rest-safe.ecf @@ -0,0 +1,28 @@ + + + + + + /EIFGENs$ + /\.git$ + /\.svn$ + + + diff --git a/library/server/request/rest/rest.ecf b/library/server/request/rest/rest.ecf new file mode 100644 index 00000000..0c5c4034 --- /dev/null +++ b/library/server/request/rest/rest.ecf @@ -0,0 +1,28 @@ + + + + + + /EIFGENs$ + /\.git$ + /\.svn$ + + + diff --git a/library/server/request/rest/src/application/rest_application.e b/library/server/request/rest/src/application/rest_application.e new file mode 100644 index 00000000..b4536020 --- /dev/null +++ b/library/server/request/rest/src/application/rest_application.e @@ -0,0 +1,31 @@ +note + description: "Summary description for {REST_APPLICATION}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + REST_APPLICATION [H -> REST_REQUEST_HANDLER [C], C -> REST_REQUEST_HANDLER_CONTEXT] + +inherit + ROUTED_APPLICATION [H, C] + redefine + router + end + +feature -- Setup + + router: REST_REQUEST_ROUTER [H, C] + -- Request router + +;note + copyright: "Copyright (c) 1984-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/rest/src/context/rest_request_handler_context.e b/library/server/request/rest/src/context/rest_request_handler_context.e new file mode 100644 index 00000000..4fbf9913 --- /dev/null +++ b/library/server/request/rest/src/context/rest_request_handler_context.e @@ -0,0 +1,78 @@ +note + description: "Summary description for {REST_REQUEST_HANDLER_CONTEXT}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + REST_REQUEST_HANDLER_CONTEXT + +inherit + REQUEST_HANDLER_CONTEXT + +feature -- Status report + + script_absolute_url (a_path: STRING): STRING + -- Absolute Url for the script if any, extended by `a_path' + do + Result := request.absolute_script_url (a_path) + end + + script_url (a_path: STRING): STRING + -- Url relative to script name if any, extended by `a_path' + require + a_path_attached: a_path /= Void + do + Result := request.script_url (a_path) + end + + url (args: detachable STRING; abs: BOOLEAN): STRING + -- Associated url based on `path' and `args' + -- if `abs' then return absolute url + local + s,t: detachable STRING + do + s := args + if s /= Void and then s.count > 0 then + create t.make_from_string (path) + if s[1] /= '/' then + t.append_character ('/') + t.append (s) + else + t.append (s) + end + s := t + else + s := path + end + if abs then + Result := script_absolute_url (s) + else + Result := script_url (s) + end + ensure + result_attached: Result /= Void + end + + authenticated: BOOLEAN + do + if request.http_authorization /= Void then + Result := True + end + end + + authenticated_identifier: detachable READABLE_STRING_32 + do + end + +note + copyright: "Copyright (c) 1984-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/rest/src/context/rest_request_uri_handler_context.e b/library/server/request/rest/src/context/rest_request_uri_handler_context.e new file mode 100644 index 00000000..d9f91e76 --- /dev/null +++ b/library/server/request/rest/src/context/rest_request_uri_handler_context.e @@ -0,0 +1,28 @@ +note + description: "Summary description for {REQUEST_URI_HANDLER_CONTEXT}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + REST_REQUEST_URI_HANDLER_CONTEXT + +inherit + REQUEST_URI_HANDLER_CONTEXT + + REST_REQUEST_HANDLER_CONTEXT + +create + make + +note + copyright: "2011-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/rest/src/context/rest_request_uri_template_handler_context.e b/library/server/request/rest/src/context/rest_request_uri_template_handler_context.e new file mode 100644 index 00000000..eefa61e7 --- /dev/null +++ b/library/server/request/rest/src/context/rest_request_uri_template_handler_context.e @@ -0,0 +1,28 @@ +note + description: "Summary description for {REQUEST_URI_TEMPLATE_HANDLER_CONTEXT}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + REST_REQUEST_URI_TEMPLATE_HANDLER_CONTEXT + +inherit + REQUEST_URI_TEMPLATE_HANDLER_CONTEXT + + REST_REQUEST_HANDLER_CONTEXT + +create + make + +note + copyright: "2011-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/rest/src/contrib/doc/html/html_page.e b/library/server/request/rest/src/contrib/doc/html/html_page.e new file mode 100644 index 00000000..d203a8ab --- /dev/null +++ b/library/server/request/rest/src/contrib/doc/html/html_page.e @@ -0,0 +1,184 @@ +note + description: "Summary description for {HTML_PAGE}." + date: "$Date$" + revision: "$Revision$" + +class + HTML_PAGE + +inherit + HTML_UTILITIES + +create + make + +feature {NONE} -- Initialization + + make (a_title: like title) + do + create {ARRAYED_LIST [like html_attributes.item]} html_attributes.make (0) + create head.make (a_title) + create {ARRAYED_LIST [like body_attributes.item]} body_attributes.make (0) + create body.make_empty + initialize + end + + initialize + -- Initialize + do + create headers.make + end + +feature -- Access + + headers: EWF_HEADER + +feature -- Recycle + + recycle + do + html_attributes.wipe_out + headers.recycle + head.recycle + body_attributes.wipe_out + body.wipe_out + internal_header_string := Void + internal_message_string := Void + end + +feature -- Access + + html_attributes: LIST [TUPLE [name: STRING; value: STRING]] + + head: HTML_PAGE_HEAD + + body_attributes: LIST [TUPLE [name: STRING; value: STRING]] + + body: STRING + +feature -- Query + + title: detachable STRING + do + Result := head.title + end + + add_html_ttribute (a: like html_attributes.item) + do + html_attributes.force (a) + end + + add_body_attribute (a: like body_attributes.item) + do + body_attributes.force (a) + end + + set_body (s: like body) + -- Set `body' to `s' + do + body := s + end + +feature -- Element change + + set_title (t: like title) + do + head.title := t + end + +feature -- Output + + compute + -- Compute the string output + local + s, t: STRING + do + --| HTML beginning + create s.make (128) + s.append_string ("%N") + + --| Head + head.compute --| Be sure to have a fresh string + t := head.string + if not t.is_empty then + s.append_string (t) + s.append_character ('%N') + end + + --| Body + s.append_string ("%N") + s.append_string (body) + s.append_string ("") + + --| End + s.append_string ("") + + --| Http headers + headers.put_content_length (s.count) + internal_header_string := headers.string + internal_message_string := s + end + + header_string: STRING + local + o: like internal_header_string + do + o := internal_header_string + if o = Void then + compute + o := internal_header_string + if o = Void then + check output_computed: False end + create o.make_empty + end + end + Result := o + end + + message_string: STRING + local + o: like internal_message_string + do + o := internal_message_string + if o = Void then + compute + o := internal_message_string + if o = Void then + check output_computed: False end + create o.make_empty + end + end + Result := o + end + + send (buf: WGI_RESPONSE_BUFFER) + do + buf.set_status_code (200) + buf.write_headers_string (header_string) + buf.write_string (message_string) + end + +feature {NONE} -- Implementation: output + + internal_header_string: detachable like header_string + + internal_message_string: detachable like message_string + +invariant + header_attached: headers /= Void + +;note + copyright: "Copyright (c) 1984-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/rest/src/contrib/doc/html/html_page_head.e b/library/server/request/rest/src/contrib/doc/html/html_page_head.e new file mode 100644 index 00000000..c51d930e --- /dev/null +++ b/library/server/request/rest/src/contrib/doc/html/html_page_head.e @@ -0,0 +1,111 @@ +note + description: "Summary description for {HTML_PAGE_HEAD}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + HTML_PAGE_HEAD + +inherit + HTML_UTILITIES + +create + make + +feature {NONE} -- Initialization + + make (a_title: like title) + do + initialize + title := a_title + end + + initialize + do + create text.make_empty + create {ARRAYED_LIST [like attributes.item]} attributes.make (0) + end + +feature -- Recycle + + recycle + do + attributes.wipe_out + title := Void + text.wipe_out + internal_string := Void + end + +feature -- Access + + attributes: LIST [TUPLE [name: STRING; value: STRING]] + + title: detachable STRING assign set_title + + text: STRING + +feature -- Element change + + set_title (t: like title) + do + title := t + end + +feature -- Output + + compute + -- Compute the string output + local + s: STRING + do + create s.make_empty + if attached title as t then + s.append_string ("" + t + "%N") + end + if text.count > 0 then + s.append_string (text) + s.append_character ('%N') + end + if s.count > 0 then + internal_string := "%N" + s + "" + else + internal_string := s + end + end + + string: STRING + -- + local + o: like internal_string + do + o := internal_string + if o = Void then + compute + o := internal_string + if o = Void then + check output_computed: False end + create o.make_empty + end + end + Result := o + end + +feature {NONE} -- Implementation: output + + internal_string: detachable like string + +invariant + text_attached: text /= Void + +note + copyright: "Copyright (c) 1984-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/rest/src/contrib/doc/html/html_utilities.e b/library/server/request/rest/src/contrib/doc/html/html_utilities.e new file mode 100644 index 00000000..18261931 --- /dev/null +++ b/library/server/request/rest/src/contrib/doc/html/html_utilities.e @@ -0,0 +1,90 @@ +note + description: "Summary description for {HTML_UTILITIES}." + date: "$Date$" + revision: "$Revision$" + +class + HTML_UTILITIES + +feature -- Encoding + + html_special_chars_encoded_string (s: STRING): STRING + local + c: CHARACTER + i,n: INTEGER + do + from + i := 1 + n := s.count + create Result.make (n + 10) + until + i > n + loop + c := s[i] + inspect c + when '&' then + Result.append_string ("&") + when '%"' then + Result.append_string (""") + when '%'' then + Result.append_string ("'") + when '<' then + Result.append_string ("<") + when '>' then + Result.append_string (">") + else + Result.extend (c) + end + i := i + 1 + end + end + +feature -- Helpers + + strings_to_string (lst: LIST [STRING]; sep: STRING): STRING + do + create Result.make_empty + if lst.count > 0 then + from + lst.start + until + lst.after + loop + Result.append_string (lst.item) + Result.append_string (sep) + lst.forth + end + end + end + + attributes_to_string (atts: LIST [TUPLE [name: STRING; value: STRING]]): STRING + do + create Result.make_empty + if atts.count > 0 then + from + atts.start + until + atts.after + loop + Result.append_character (' ') + Result.append_string (atts.item.name) + Result.append_character ('=') + Result.append_character ('%"') + Result.append_string (html_special_chars_encoded_string (atts.item.value)) + Result.append_character ('%"') + atts.forth + end + end + end + +note + copyright: "Copyright (c) 1984-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/rest/src/contrib/doc/rest_api_documentation.e b/library/server/request/rest/src/contrib/doc/rest_api_documentation.e new file mode 100644 index 00000000..0d30b40e --- /dev/null +++ b/library/server/request/rest/src/contrib/doc/rest_api_documentation.e @@ -0,0 +1,317 @@ +note + description: "Summary description for {REST_API_DOCUMENTATION}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + REST_API_DOCUMENTATION [C -> REST_REQUEST_HANDLER_CONTEXT] + +inherit + REST_REQUEST_HANDLER [C] + +create + make + +feature {NONE} -- Initialization + + make (a_router: like router; a_base_doc_url: like base_doc_url) + do + router := a_router + base_doc_url := a_base_doc_url + description := "Technical documention for the API" + initialize + end + +feature {NONE} -- Access: Implementation + + router: REST_REQUEST_ROUTER [REST_REQUEST_HANDLER [C], C] + + base_doc_url: READABLE_STRING_8 + +feature -- Access + + authentication_required: BOOLEAN = False + +feature -- Execution + + execute_application (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + local + rep: like new_html_page + s: STRING + rq: detachable REST_REQUEST_HANDLER [C] + rq_resource: detachable READABLE_STRING_GENERAL +-- l_dft_format_name: detachable STRING + hdl_cursor: like router.new_cursor + do + rep := new_html_page + rep.headers.put_content_type_text_html + create s.make_empty + + if attached ctx.path_parameter ("resource") as l_resource then + from + hdl_cursor := router.new_cursor + until + hdl_cursor.after or rq /= Void + loop + if hdl_cursor.item.resource.same_string_general (l_resource) then + rq := hdl_cursor.item.handler + rq_resource := l_resource + end + hdl_cursor.forth + end + end +-- if a_args /= Void and then not a_args.is_empty then +-- rq := router.handler_by_path (a_args) +-- if rq = Void then +-- rq := handler_manager.smart_handler_by_path (a_args) +---- if attached {REST_REQUEST_GROUP_HANDLER} rq as grp then +---- rq := grp.handlers.handler_by_path (a_args) +---- end +-- end +-- if +-- rq /= Void and then +-- attached rq.path_information (a_args) as l_info +-- then +-- l_dft_format_name := l_info.format +-- end +-- end + + + if rq /= Void and then rq_resource /= Void then + rep.set_big_title ("API: Technical documentation for ["+ rq_resource.as_string_8 +"]") + + s.append_string ("
") + s.append_string ("

") + + s.append_string (".. Show all features ..") + s.append_string ("

%N") + + process_request_handler_doc (rq, rq_resource.as_string_8, s, ctx, req, res, Void) + else + rep.set_big_title ("API: Technical documentation") + + from + hdl_cursor := router.new_cursor + until + hdl_cursor.after + loop + if attached hdl_cursor.item as l_item then + rq := l_item.handler + rep.add_shortcut (l_item.resource) + s.append ("") + process_request_handler_doc (rq, l_item.resource, s, ctx, req, res, Void) + hdl_cursor.forth + end + end + end + rep.set_body (s) + rep.send (res) + rep.recycle + end + + process_request_handler_doc (rq: REST_REQUEST_HANDLER [C]; a_resource: STRING; buf: STRING; ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER; a_dft_format: detachable STRING) + local + l_dft_format_name: detachable STRING + s: STRING + l_uri_tpl: URI_TEMPLATE + do + s := buf + + if a_dft_format /= Void then + if rq.supported_format_names.has (a_dft_format) then + l_dft_format_name := a_dft_format + end + end + + s.append_string ("
") + s.append_string ("

"+ a_resource +"

") + s.append_string ("
") +-- if rq.hidden (req) then +-- s.append_string ("
This feature is hidden
%N") +-- else + if attached rq.description as desc then + s.append_string ("
" + desc + "
") + end +-- if attached {REST_REQUEST_GROUP_HANDLER} rq as grp then +-- s.append_string ("
Handler: ") +-- if attached grp.handlers.new_cursor as l_handlers_cursor then +-- from + +-- until +-- l_handlers_cursor.after +-- loop +-- s.append_string (" ") +-- s.append_string (""+ l_handlers_cursor.item.path +"") +-- l_handlers_cursor.forth +-- end +-- end +-- s.append_string ("
") +-- end + if attached rq.supported_format_names as l_formats and then not l_formats.is_empty then + s.append_string ("
Supported formats: ") + if attached l_formats.new_cursor as l_formats_cursor then + from + + until + l_formats_cursor.after + loop + s.append_string (" ") + s.append_string (""+ l_formats_cursor.item +"") + l_formats_cursor.forth + end + end + s.append_string ("
") + end + if attached rq.supported_request_method_names as l_methods and then not l_methods.is_empty then + s.append_string ("
Supported request methods: ") + if attached l_methods.new_cursor as l_methods_cursor then + from + + until + l_methods_cursor.after + loop + s.append_string (" ") + s.append_string (l_methods_cursor.item) + l_methods_cursor.forth + end + end + s.append_string ("
") + end + s.append_string ("
Authentication required: " + rq.authentication_required.out + "
") + if attached {REST_REQUEST_URI_TEMPLATE_ROUTER [REST_REQUEST_HANDLER [REST_REQUEST_URI_TEMPLATE_HANDLER_CONTEXT], REST_REQUEST_URI_TEMPLATE_HANDLER_CONTEXT]} router as l_uri_template_router then + create l_uri_tpl.make (a_resource) + if attached l_uri_tpl.query_variable_names as l_query_variable_names and then not l_query_variable_names.is_empty then + s.append_string ("
Query parameters: ") +-- s.append_string (rq.path) + from + l_query_variable_names.start + until + l_query_variable_names.after + loop + if l_query_variable_names.isfirst then + s.append_string ("?") + else + s.append_string ("&") + end + if attached l_query_variable_names.item as l_query_param then + s.append_string ("" + l_query_param + "") + s.append_string ("=" + l_query_param + "") + end + l_query_variable_names.forth + end + s.append_string ("
%N") + end + if attached l_uri_tpl.path_variable_names as l_path_variable_names and then not l_path_variable_names.is_empty then + s.append_string ("
Path Segment parameters: ") +-- s.append_string (rq.path) + from + l_path_variable_names.start + until + l_path_variable_names.after + loop + if attached l_path_variable_names.item as l_seg_param then + s.append_string ("{" + l_seg_param + "}") + end + l_path_variable_names.forth + end + s.append_string ("
%N") + end + + end +-- if attached rq._parameters as l_uri_params and then not l_uri_params.is_empty then +-- s.append_string ("
URI Template: ") +-- s.append_string (rq.path) +-- if attached l_uri_params.new_cursor as l_uri_params_cursor then +-- from + +-- until +-- l_uri_params_cursor.after +-- loop +-- if attached l_uri_params_cursor.item as l_uri_param then +-- s.append_string ("/" + l_uri_param.name + "") +-- s.append_string ("/{" + l_uri_param.name + "}") +-- end +-- l_uri_params_cursor.forth +-- end +-- end +-- s.append_string ("
%N") +-- end +-- if attached rq.parameters as l_params and then not l_params.is_empty then +-- s.append_string ("
Parameters: ") + +-- --| show form only if we have a default format +-- if l_dft_format_name = Void then +-- s.append_string ("to test the parameter(s), please first select a supported format.%N") +-- else +-- if rq.method_post_supported then +-- s.append_string ("
%N") +-- else +-- s.append_string ("%N") +-- end +-- end +-- s.append_string ("
    ") +-- if attached l_params.new_cursor as l_params_cursor then +-- from + +-- until +-- l_params_cursor.after +-- loop +-- if attached l_params_cursor.item as l_param then +-- s.append_string ("
  • " + l_param.name + "") +-- if l_param.optional then +-- s.append_string (" (Optional)") +-- end +-- if attached l_param.description as l_param_desc then +-- s.append_string (": " + l_param_desc + "") +-- end +-- if l_dft_format_name /= Void then +-- s.append (" ") +-- end +-- s.append_string ("
  • ") +-- end +-- l_params_cursor.forth +-- end +-- end + +-- if l_dft_format_name /= Void then +-- s.append_string ("") +-- s.append_string ("") +-- end +-- s.append_string ("
") +-- else +-- if l_dft_format_name /= Void then +-- s.append_string ("Test "+ a_resource + "." + l_dft_format_name + "") +-- else +-- s.append_string ("Test "+ a_resource +"") +-- end +-- end + s.append_string ("
%N") +-- end + s.append_string ("
%N") -- inner + end + +feature -- Access + + new_html_page: REST_API_DOCUMENTATION_HTML_PAGE + do + create Result.make ("API Documentation") + end + +note + copyright: "Copyright (c) 1984-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/rest/src/contrib/doc/rest_api_documentation_html_page.e b/library/server/request/rest/src/contrib/doc/rest_api_documentation_html_page.e new file mode 100644 index 00000000..953cb482 --- /dev/null +++ b/library/server/request/rest/src/contrib/doc/rest_api_documentation_html_page.e @@ -0,0 +1,124 @@ +note + description: "Summary description for {REST_API_DOCUMENTATION_HTML_PAGE}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + REST_API_DOCUMENTATION_HTML_PAGE + +inherit + HTML_PAGE + redefine + head, + initialize, + recycle, + compute + end + +create + make + +feature {NONE} -- Initialization + + initialize + do + Precursor + create {LINKED_LIST [like shortcuts.item]} shortcuts.make + end + +feature -- Recyle + + recycle + do + Precursor + shortcuts.wipe_out + end + +feature -- Access + + head: REST_API_DOCUMENTATION_HTML_PAGE_HEAD + + big_title: detachable STRING + + shortcuts: LIST [TUPLE [name: STRING; anchor: STRING]] + + add_shortcut (s: STRING) + local + t: STRING + do + t := s.string + t.replace_substring_all ("/", "-") + shortcuts.force ([s,t]) + end + + last_added_shortcut: STRING + do + if shortcuts.count > 0 and then attached shortcuts.last as sht then + Result := sht.anchor + else + create Result.make_empty + end + end + + shortcuts_to_html: detachable STRING + do + if not shortcuts.is_empty then + from + create Result.make_from_string ("Shortcuts: | ") + shortcuts.start + until + shortcuts.after + loop + Result.append_string (""+ shortcuts.item.name +" | ") + shortcuts.forth + end + end + end + +feature -- Element change + + set_big_title (t: like big_title) + do + big_title := t + end + +feature -- Basic operation + + compute + local + l_old_body: STRING + sh, bt: detachable STRING + do + sh := shortcuts_to_html + bt := big_title + if sh /= Void or bt /= Void then + l_old_body := body + if bt /= Void then + bt := "

" + bt + "

%N" + if sh /= Void then + body := bt + sh + l_old_body + else + body := bt + l_old_body + end + elseif sh /= Void then + body := sh + l_old_body + end + Precursor + body := l_old_body + else + Precursor + end + end + +;note + copyright: "Copyright (c) 1984-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/rest/src/contrib/doc/rest_api_documentation_html_page_head.e b/library/server/request/rest/src/contrib/doc/rest_api_documentation_html_page_head.e new file mode 100644 index 00000000..aa57b34f --- /dev/null +++ b/library/server/request/rest/src/contrib/doc/rest_api_documentation_html_page_head.e @@ -0,0 +1,75 @@ +note + description: "Summary description for {REST_API_DOCUMENTATION_HTML_PAGE_HEAD}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + REST_API_DOCUMENTATION_HTML_PAGE_HEAD + +inherit + HTML_PAGE_HEAD + redefine + initialize, + compute + end + +create + make + +feature {NONE} -- Initialization + + initialize + do + Precursor + style := "[ + body {margin: 0px;} + a { text-decoration: none; } + h1 { padding: 10px; border: solid 2px #000; background-color: #009; color: #fff;} + div.api { padding: 5px; margin-bottom: 10px;} + div.api .api-description { padding: 5px 5px 5px 0px; font-style: italic; color: #090;} + div.api div.inner { padding-left: 40px;} + div.api h2>a { color: #009; text-decoration: none;} + div.api a.api-format { color: #009; text-decoration: none;} + div.api a.api-format.selected { padding: 0 4px 0 4px; color: #009; text-decoration: none; border: solid 1px #99c; background-color: #eeeeff;} + div.api>h2 { margin: 2px; padding: 2px 2px 2px 10px; display: inline-block; border: dotted 1px #cce; width: 100%; color: #009; background-color: #E7F3F8; text-decoration: none; font-weight: bold; font-size: 120%;} + div.api span.note { font-style: italic;} + ]" + end + +feature {REST_API_DOCUMENTATION_HTML_PAGE} -- Access + + style: STRING + +feature -- Output + + compute + -- Compute the string output + local + s: detachable STRING + p: INTEGER + do + Precursor + s := internal_string + if s /= Void then + p := s.substring_index ("", 1) + if p > 0 then + s.insert_string ("%N", p) + else + s.append_string ("%N") + end + end + end + + +note + copyright: "Copyright (c) 1984-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/rest/src/default/default_rest_application.e b/library/server/request/rest/src/default/default_rest_application.e new file mode 100644 index 00000000..3c8ee966 --- /dev/null +++ b/library/server/request/rest/src/default/default_rest_application.e @@ -0,0 +1,23 @@ +note + description: "Summary description for {DEFAULT_REST_APPLICATION}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + DEFAULT_REST_APPLICATION + +inherit + REST_APPLICATION [REST_REQUEST_HANDLER [REST_REQUEST_HANDLER_CONTEXT], REST_REQUEST_HANDLER_CONTEXT] + +note + copyright: "Copyright (c) 1984-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/rest/src/default/default_rest_request_uri_handler.e b/library/server/request/rest/src/default/default_rest_request_uri_handler.e new file mode 100644 index 00000000..efbf0ed7 --- /dev/null +++ b/library/server/request/rest/src/default/default_rest_request_uri_handler.e @@ -0,0 +1,24 @@ +note + description: "Summary description for {DEFAULT_REST_REQUEST_URI_HANDLER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + DEFAULT_REST_REQUEST_URI_HANDLER + +inherit + REST_REQUEST_HANDLER [REST_REQUEST_URI_HANDLER_CONTEXT] + + +;note + copyright: "Copyright (c) 1984-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/rest/src/default/default_rest_request_uri_router.e b/library/server/request/rest/src/default/default_rest_request_uri_router.e new file mode 100644 index 00000000..854f9c68 --- /dev/null +++ b/library/server/request/rest/src/default/default_rest_request_uri_router.e @@ -0,0 +1,40 @@ +note + description: "Summary description for {DEFAULT_REST_REQUEST_URI_ROUTER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + DEFAULT_REST_REQUEST_URI_ROUTER + +inherit + REST_REQUEST_URI_ROUTER [REST_REQUEST_HANDLER [REST_REQUEST_URI_HANDLER_CONTEXT], REST_REQUEST_URI_HANDLER_CONTEXT] + redefine + map_agent_with_request_methods + end + +create + make + +feature -- Mapping + + map_agent_with_request_methods (a_id: READABLE_STRING_8; a_action: PROCEDURE [ANY, TUPLE [ctx: REST_REQUEST_URI_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER]]; + rqst_methods: detachable ARRAY [READABLE_STRING_8]) + local + h: REST_REQUEST_AGENT_HANDLER [REST_REQUEST_URI_HANDLER_CONTEXT] + do + create h.make (a_action) + map_with_request_methods (a_id, h, rqst_methods) + end + +note + copyright: "Copyright (c) 1984-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/rest/src/default/default_rest_request_uri_template_handler.e b/library/server/request/rest/src/default/default_rest_request_uri_template_handler.e new file mode 100644 index 00000000..a637ed60 --- /dev/null +++ b/library/server/request/rest/src/default/default_rest_request_uri_template_handler.e @@ -0,0 +1,24 @@ +note + description: "Summary description for {DEFAULT_REST_REQUEST_URI_TEMPLATE_HANDLER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + DEFAULT_REST_REQUEST_URI_TEMPLATE_HANDLER + +inherit + REST_REQUEST_HANDLER [REST_REQUEST_URI_TEMPLATE_HANDLER_CONTEXT] + + +;note + copyright: "Copyright (c) 1984-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/rest/src/default/default_rest_request_uri_template_router.e b/library/server/request/rest/src/default/default_rest_request_uri_template_router.e new file mode 100644 index 00000000..2054255b --- /dev/null +++ b/library/server/request/rest/src/default/default_rest_request_uri_template_router.e @@ -0,0 +1,40 @@ +note + description: "Summary description for {DEFAULT_REST_REQUEST_URI_TEMPLATE_ROUTER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + DEFAULT_REST_REQUEST_URI_TEMPLATE_ROUTER + +inherit + REST_REQUEST_URI_TEMPLATE_ROUTER [REST_REQUEST_HANDLER [REST_REQUEST_URI_TEMPLATE_HANDLER_CONTEXT], REST_REQUEST_URI_TEMPLATE_HANDLER_CONTEXT] + redefine + map_agent_with_request_methods + end + +create + make + +feature -- Mapping + + map_agent_with_request_methods (a_id: READABLE_STRING_8; a_action: PROCEDURE [ANY, TUPLE [ctx: REST_REQUEST_URI_TEMPLATE_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER]]; + rqst_methods: detachable ARRAY [READABLE_STRING_8]) + local + h: REST_REQUEST_AGENT_HANDLER [REST_REQUEST_URI_TEMPLATE_HANDLER_CONTEXT] + do + create h.make (a_action) + map_with_request_methods (a_id, h, rqst_methods) + end + +note + copyright: "Copyright (c) 1984-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/rest/src/default/default_rest_request_uri_template_routing_handler.e b/library/server/request/rest/src/default/default_rest_request_uri_template_routing_handler.e new file mode 100644 index 00000000..67c37924 --- /dev/null +++ b/library/server/request/rest/src/default/default_rest_request_uri_template_routing_handler.e @@ -0,0 +1,33 @@ +note + description: "Summary description for {DEFAULT_REST_REQUEST_URI_TEMPLATE_ROUTING_HANDLER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + DEFAULT_REST_REQUEST_URI_TEMPLATE_ROUTING_HANDLER + +inherit + REST_REQUEST_URI_TEMPLATE_ROUTING_HANDLER [REST_REQUEST_HANDLER [REST_REQUEST_URI_TEMPLATE_HANDLER_CONTEXT], REST_REQUEST_URI_TEMPLATE_HANDLER_CONTEXT] + redefine + router + end + +create + make + +feature {NONE} -- Routing + + router: DEFAULT_REST_REQUEST_URI_TEMPLATE_ROUTER + +;note + copyright: "Copyright (c) 1984-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/rest/src/default/default_rest_uri_application.e b/library/server/request/rest/src/default/default_rest_uri_application.e new file mode 100644 index 00000000..b6bdd088 --- /dev/null +++ b/library/server/request/rest/src/default/default_rest_uri_application.e @@ -0,0 +1,30 @@ +note + description: "Summary description for {DEFAULT_REST_URI_APPLICATION}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + DEFAULT_REST_URI_APPLICATION + +inherit + REST_APPLICATION [REST_REQUEST_HANDLER [REST_REQUEST_URI_HANDLER_CONTEXT], REST_REQUEST_URI_HANDLER_CONTEXT] + redefine + router + end + +feature -- Router + + router: DEFAULT_REST_REQUEST_URI_ROUTER + +;note + copyright: "Copyright (c) 1984-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/rest/src/default/default_rest_uri_template_application.e b/library/server/request/rest/src/default/default_rest_uri_template_application.e new file mode 100644 index 00000000..0f1e76c6 --- /dev/null +++ b/library/server/request/rest/src/default/default_rest_uri_template_application.e @@ -0,0 +1,30 @@ +note + description: "Summary description for {DEFAULT_URI_TEMPLATE_REST_APPLICATION}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + DEFAULT_REST_URI_TEMPLATE_APPLICATION + +inherit + REST_APPLICATION [REST_REQUEST_HANDLER [REST_REQUEST_URI_TEMPLATE_HANDLER_CONTEXT], REST_REQUEST_URI_TEMPLATE_HANDLER_CONTEXT] + redefine + router + end + +feature -- Router + + router: DEFAULT_REST_REQUEST_URI_TEMPLATE_ROUTER + +;note + copyright: "Copyright (c) 1984-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/rest/src/handler/rest_request_agent_handler.e b/library/server/request/rest/src/handler/rest_request_agent_handler.e new file mode 100644 index 00000000..ba85571e --- /dev/null +++ b/library/server/request/rest/src/handler/rest_request_agent_handler.e @@ -0,0 +1,56 @@ +note + description: "Summary description for REST_REQUEST_AGENT_HANDLER." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + REST_REQUEST_AGENT_HANDLER [C -> REST_REQUEST_HANDLER_CONTEXT] + +inherit + REQUEST_AGENT_HANDLER [C] + redefine + execute + end + + REST_REQUEST_HANDLER [C] + redefine + execute + end +create + make + +feature -- status + + authentication_required: BOOLEAN + +feature -- Element change + + set_authentication_required (b: like authentication_required) + do + authentication_required := b + end + +feature -- Execution + + execute (a_hdl_context: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + do + Precursor {REST_REQUEST_HANDLER} (a_hdl_context, req, res) + end + +-- execute_application (ctx: REST_REQUEST_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) +-- do +-- action.call ([ctx, req, res]) +-- end + +;note + copyright: "Copyright (c) 1984-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/rest/src/handler/rest_request_group_handler.e- b/library/server/request/rest/src/handler/rest_request_group_handler.e- new file mode 100644 index 00000000..12bfe4b0 --- /dev/null +++ b/library/server/request/rest/src/handler/rest_request_group_handler.e- @@ -0,0 +1,47 @@ +note + description: "Summary description for REST_REQUEST_GROUP_HANDLER." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + REST_REQUEST_GROUP_HANDLER [H -> REST_REQUEST_HANDLER [C], C -> REST_REQUEST_HANDLER_CONTEXT] + +inherit + REQUEST_ROUTING_HANDLER [H, C] + redefine + execute + end + + REST_REQUEST_HANDLER [C] + redefine + execute + select + execute_application + end + +create + make + +feature -- status + + authentication_required: BOOLEAN + +feature -- Execution + + execute (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + do + Precursor {REST_REQUEST_HANDLER} (ctx, req, res) + end + +;note + copyright: "Copyright (c) 1984-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/rest/src/handler/rest_request_handler.e b/library/server/request/rest/src/handler/rest_request_handler.e new file mode 100644 index 00000000..8e9810a8 --- /dev/null +++ b/library/server/request/rest/src/handler/rest_request_handler.e @@ -0,0 +1,165 @@ +note + description: "Summary description for {REST_REQUEST_HANDLER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + REST_REQUEST_HANDLER [C -> REST_REQUEST_HANDLER_CONTEXT] + +inherit + REQUEST_HANDLER [C] + redefine + execute + end + +feature -- Access + + authentication_required: BOOLEAN + -- Is authentication required + -- might depend on the request environment + -- or the associated resources + deferred + end + +feature -- Execution + + execute (a_hdl_context: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + -- Execute request handler + do + if authentication_required and then not a_hdl_context.authenticated then + execute_unauthorized (a_hdl_context, req, res) + else + Precursor (a_hdl_context, req, res) + end + end + + execute_unauthorized (a_hdl_context: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + do + res.set_status_code ({HTTP_STATUS_CODE}.unauthorized) + res.write_header ({HTTP_STATUS_CODE}.unauthorized, <<["WWW-Authenticate", "Basic realm=%"Eiffel auth%""]>>) + res.write_string ("Unauthorized") + end + +feature {NONE} -- Implementation + + supported_formats: INTEGER + -- Support request format result such as json, xml, ... + +feature {NONE} -- Status report + + format_id_supported (a_id: INTEGER): BOOLEAN + do + Result := (supported_formats & a_id) = a_id + end + + format_name_supported (n: STRING): BOOLEAN + -- Is format `n' supported? + do + Result := format_id_supported (format_constants.format_id (n)) + end + + format_constants: HTTP_FORMAT_CONSTANTS + once + create Result + end + +feature -- Status report + + supported_format_names: LIST [STRING] + -- Supported format names ... + do + create {LINKED_LIST [STRING]} Result.make + if format_json_supported then + Result.extend (format_constants.json_name) + end + if format_xml_supported then + Result.extend (format_constants.xml_name) + end + if format_text_supported then + Result.extend (format_constants.text_name) + end + if format_html_supported then + Result.extend (format_constants.html_name) + end + if format_rss_supported then + Result.extend (format_constants.rss_name) + end + if format_atom_supported then + Result.extend (format_constants.atom_name) + end + end + + format_json_supported: BOOLEAN + do + Result := format_id_supported ({HTTP_FORMAT_CONSTANTS}.json) + end + + format_xml_supported: BOOLEAN + do + Result := format_id_supported ({HTTP_FORMAT_CONSTANTS}.xml) + end + + format_text_supported: BOOLEAN + do + Result := format_id_supported ({HTTP_FORMAT_CONSTANTS}.text) + end + + format_html_supported: BOOLEAN + do + Result := format_id_supported ({HTTP_FORMAT_CONSTANTS}.html) + end + + format_rss_supported: BOOLEAN + do + Result := format_id_supported ({HTTP_FORMAT_CONSTANTS}.rss) + end + + format_atom_supported: BOOLEAN + do + Result := format_id_supported ({HTTP_FORMAT_CONSTANTS}.atom) + end + +feature -- Element change: formats + + reset_supported_formats + do + supported_formats := 0 + end + + enable_format_json + do + enable_format ({HTTP_FORMAT_CONSTANTS}.json) + end + + enable_format_xml + do + enable_format ({HTTP_FORMAT_CONSTANTS}.xml) + end + + enable_format_text + do + enable_format ({HTTP_FORMAT_CONSTANTS}.text) + end + + enable_format_html + do + enable_format ({HTTP_FORMAT_CONSTANTS}.html) + end + + enable_format (f: INTEGER) + do + supported_formats := supported_formats | f + end + +note + copyright: "Copyright (c) 1984-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/rest/src/handler/rest_request_uri_routing_handler.e b/library/server/request/rest/src/handler/rest_request_uri_routing_handler.e new file mode 100644 index 00000000..6d6fb2f1 --- /dev/null +++ b/library/server/request/rest/src/handler/rest_request_uri_routing_handler.e @@ -0,0 +1,51 @@ +note + description: "Summary description for {REQUEST_ROUTING_HANDLER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + REST_REQUEST_URI_ROUTING_HANDLER [H -> REST_REQUEST_HANDLER [C], + C -> REST_REQUEST_URI_HANDLER_CONTEXT create make end] + +inherit + REQUEST_URI_ROUTING_HANDLER [H, C] + redefine + router, + execute + end + + REST_REQUEST_HANDLER [C] + undefine + execute + end + +create + make + +feature -- Status report + + authentication_required: BOOLEAN + +feature -- Execution + + execute (a_hdl_context: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + do + Precursor {REST_REQUEST_HANDLER} (a_hdl_context, req, res) + end + +feature {NONE} -- Routing + + router: REST_REQUEST_URI_ROUTER [H, C] + +;note + copyright: "Copyright (c) 1984-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/rest/src/handler/rest_request_uri_template_routing_handler.e b/library/server/request/rest/src/handler/rest_request_uri_template_routing_handler.e new file mode 100644 index 00000000..606df5dc --- /dev/null +++ b/library/server/request/rest/src/handler/rest_request_uri_template_routing_handler.e @@ -0,0 +1,51 @@ +note + description: "Summary description for {REQUEST_ROUTING_HANDLER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + REST_REQUEST_URI_TEMPLATE_ROUTING_HANDLER [H -> REST_REQUEST_HANDLER [C], + C -> REST_REQUEST_URI_TEMPLATE_HANDLER_CONTEXT create make end] + +inherit + REQUEST_URI_TEMPLATE_ROUTING_HANDLER [H, C] + redefine + router, + execute + end + + REST_REQUEST_HANDLER [C] + undefine + execute + end + +create + make + +feature -- Status report + + authentication_required: BOOLEAN + +feature -- Execution + + execute (a_hdl_context: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + do + Precursor {REST_REQUEST_HANDLER} (a_hdl_context, req, res) + end + +feature {NONE} -- Routing + + router: REST_REQUEST_URI_TEMPLATE_ROUTER [H, C] + +;note + copyright: "Copyright (c) 1984-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/rest/src/response/rest_response.e b/library/server/request/rest/src/response/rest_response.e new file mode 100644 index 00000000..f385b9fe --- /dev/null +++ b/library/server/request/rest/src/response/rest_response.e @@ -0,0 +1,156 @@ +note + description: "Summary description for {REST_RESPONSE}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + REST_RESPONSE + +create + make + +feature {NONE} -- Initialization + + make (a_api: like api) + do + api := a_api + initialize + end + + initialize + do + create headers.make + end + +feature -- Recycle + + recycle + do + headers.recycle + end + +feature -- Access + + headers: EWF_HEADER + + api: STRING + -- Associated api query string. + + message: detachable STRING_8 + -- Associated message to send with the response. + +feature -- Element change + + set_message (m: like message) + -- Set `message' to `m' + do + message := m + end + + append_message (m: attached like message) + -- Append message `m' to current `message' value + -- create `message' is Void + require + m_not_empty: m /= Void and then not m.is_empty + do + if attached message as msg then + msg.append (m) + else + set_message (m.string) + end + end + + append_message_file_content (fn: STRING) + -- Append file content from `fn' to the response + --| To use with care. + --| You should avoid using this for big or binary content ... + local + f: RAW_FILE + do + create f.make (fn) + if f.exists and then f.is_readable then + f.open_read + from + until + f.exhausted + loop + f.read_stream (1024) + append_message (f.last_string) + end + f.close + end + end + +feature -- Output + + update_content_length (a_overwrite: BOOLEAN) + -- Update content length + -- if the header already exists it won't change it, + -- unless `a_overwrite' is set to True + local + hds: like headers + len: INTEGER + do + hds := headers + if a_overwrite or else not hds.has_content_length then + if attached message as m then + len := m.count +-- if {PLATFORM}.is_windows then +-- len := len + m.occurrences ('%N') --| FIXME: find better solution +-- end + else + len := 0 + end + hds.put_content_length (len) + end + end + + compute + -- Compute the string output + do + update_content_length (False) + internal_headers_string := headers.string + end + + headers_string: STRING + local + o: like internal_headers_string + do + o := internal_headers_string + if o = Void then + compute + o := internal_headers_string + if o = Void then + check output_computed: False end + create o.make_empty + end + end + Result := o + end + + send (res: WGI_RESPONSE_BUFFER) + do + compute + res.set_status_code (200) + res.write_headers_string (headers_string) + if attached message as m then + res.write_string (m) + end + end + +feature {NONE} -- Implementation: output + + internal_headers_string: detachable like headers_string + +;note + copyright: "Copyright (c) 1984-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/rest/src/router/rest_request_router.e b/library/server/request/rest/src/router/rest_request_router.e new file mode 100644 index 00000000..f6755362 --- /dev/null +++ b/library/server/request/rest/src/router/rest_request_router.e @@ -0,0 +1,23 @@ +note + description: "Summary description for {REST_REQUEST_ROUTER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + REST_REQUEST_ROUTER [H -> REST_REQUEST_HANDLER [C], C -> REST_REQUEST_HANDLER_CONTEXT] + +inherit + REQUEST_ROUTER [H, C] + +;note + copyright: "Copyright (c) 1984-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/rest/src/router/rest_request_uri_router.e b/library/server/request/rest/src/router/rest_request_uri_router.e new file mode 100644 index 00000000..57a0a362 --- /dev/null +++ b/library/server/request/rest/src/router/rest_request_uri_router.e @@ -0,0 +1,36 @@ +note + description: "Summary description for {REST_REQUEST_URI_ROUTER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + REST_REQUEST_URI_ROUTER [H -> REST_REQUEST_HANDLER [C], C -> REST_REQUEST_URI_HANDLER_CONTEXT create make end] + +inherit + REQUEST_URI_ROUTER [H, C] + + REST_REQUEST_ROUTER [H, C] + + +create + make + +feature -- Mapping + +-- map_agent_with_request_methods (a_id: READABLE_STRING_8; a_action: like {REST_REQUEST_AGENT_HANDLER}.action; rqst_methods: detachable ARRAY [READABLE_STRING_8]) +-- do +-- Precursor (a_id, a_action, rqst_methods) +-- end + +note + copyright: "Copyright (c) 1984-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/rest/src/router/rest_request_uri_template_router.e b/library/server/request/rest/src/router/rest_request_uri_template_router.e new file mode 100644 index 00000000..d023dd3e --- /dev/null +++ b/library/server/request/rest/src/router/rest_request_uri_template_router.e @@ -0,0 +1,28 @@ +note + description: "Summary description for {REST_REQUEST_URI_TEMPLATE_ROUTER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + REST_REQUEST_URI_TEMPLATE_ROUTER [H -> REST_REQUEST_HANDLER [C], C -> REST_REQUEST_URI_TEMPLATE_HANDLER_CONTEXT create make end] + +inherit + REQUEST_URI_TEMPLATE_ROUTER [H, C] + + REST_REQUEST_ROUTER [H, C] + +create + make + +note + copyright: "Copyright (c) 1984-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/rest/tests/htdocs/.htaccess b/library/server/request/rest/tests/htdocs/.htaccess new file mode 100644 index 00000000..687d4c26 --- /dev/null +++ b/library/server/request/rest/tests/htdocs/.htaccess @@ -0,0 +1,26 @@ +Options Indexes FollowSymLinks ExecCGI + + +AddHandler fcgid-script .eapp +FcgidWrapper c:/_dev/Dev-Process/web-library/library/server/rest/tests/htdocs/../EIFGENs/rest_sample_cgi/W_code/sample.exe .eapp + + + +Options +ExecCGI +AddHandler cgi-script exe + + + + RewriteEngine on + RewriteBase /REST + + + RewriteCond %{REQUEST_FILENAME} !-f + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_URI} !=/favicon.ico + RewriteRule ^(.*)$ sample.eapp/$1 + +# To let CGI app knows about HTTP_AUTHORIZATION +RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L] + + diff --git a/library/server/request/rest/tests/htdocs/README.txt b/library/server/request/rest/tests/htdocs/README.txt new file mode 100644 index 00000000..13bd0686 --- /dev/null +++ b/library/server/request/rest/tests/htdocs/README.txt @@ -0,0 +1,31 @@ += How to make this works with Apache = +* In the apache's configuration file, be sure to add the following, or similar + LoadModule fcgid_module modules/mod_fcgid.so + + FcgidIdleTimeout 60 + FcgidBusyScanInterval 120 + FcgidProcessLifeTime 1600 + #7200 + FcgidMaxProcesses 5 + FcgidMaxProcessesPerClass 100 + FcgidMinProcessesPerClass 100 + FcgidConnectTimeout 8 + FcgidIOTimeout 3000 + FcgidBusyTimeout 3200 + FcgidMaxRequestLen 10000000 + FcgidPassHeader Authorization + + + + alias /REST/ "c:/_dev/Dev-Process/src/server/htdocs/" + + AllowOverride All + Order allow,deny + Allow from all + + +* You can use , but then the AllowOverride All, should be somewhere else, since does not allow it. + +* And then, check the .htaccess from this folder for additional settings (but required) + + diff --git a/library/server/request/rest/tests/htdocs/build.eant b/library/server/request/rest/tests/htdocs/build.eant new file mode 100644 index 00000000..2a5a919b --- /dev/null +++ b/library/server/request/rest/tests/htdocs/build.eant @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/library/server/request/rest/tests/htdocs/htaccess b/library/server/request/rest/tests/htdocs/htaccess new file mode 100644 index 00000000..a36c2b28 --- /dev/null +++ b/library/server/request/rest/tests/htdocs/htaccess @@ -0,0 +1,26 @@ +Options Indexes FollowSymLinks ExecCGI + + +AddHandler fcgid-script .eapp +FcgidWrapper ##SAMPLE-CGI-DIR##/sample.exe .eapp + + + +Options +ExecCGI +AddHandler cgi-script exe + + + + RewriteEngine on + RewriteBase /REST + + + RewriteCond %{REQUEST_FILENAME} !-f + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_URI} !=/favicon.ico + RewriteRule ^(.*)$ sample.eapp/$1 + +# To let CGI app knows about HTTP_AUTHORIZATION +RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L] + + diff --git a/library/server/request/rest/tests/htdocs/sample.eapp b/library/server/request/rest/tests/htdocs/sample.eapp new file mode 100644 index 00000000..e69de29b diff --git a/library/server/request/rest/tests/sample.ecf b/library/server/request/rest/tests/sample.ecf new file mode 100644 index 00000000..05cfaeab --- /dev/null +++ b/library/server/request/rest/tests/sample.ecf @@ -0,0 +1,55 @@ + + + + + /EIFGENs$ + /\.git$ + /\.svn$ + + + + + + + + + + + + + + + + /gateway$ + + + + + + + + + + + /gateway$ + + + + + + + + + + + + + + + /gateway$ + + + + + diff --git a/library/server/request/rest/tests/src/app/app_account_verify_credential.e b/library/server/request/rest/tests/src/app/app_account_verify_credential.e new file mode 100644 index 00000000..0bb06270 --- /dev/null +++ b/library/server/request/rest/tests/src/app/app_account_verify_credential.e @@ -0,0 +1,109 @@ +note + description: "Summary description for {APP_ACCOUNT_VERIFY_CREDENTIAL}." + date: "$Date$" + revision: "$Revision$" + +class + APP_ACCOUNT_VERIFY_CREDENTIAL + +inherit + APP_REQUEST_HANDLER + redefine + initialize, + execute_unauthorized + end + +create + make + +feature {NONE} -- Initialization + + make + do + description := "Verify credentials" + initialize + end + + initialize + do + Precursor + enable_request_method_get + enable_format_json + enable_format_xml + enable_format_text + end + +feature -- Access + + authentication_required: BOOLEAN = True + +feature -- Execution + + execute_unauthorized (a_hdl_context: APP_REQUEST_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + local + s: STRING + lst: LIST [STRING] + do + res.set_status_code ({HTTP_STATUS_CODE}.unauthorized) + res.write_header ({HTTP_STATUS_CODE}.unauthorized, <<["WWW-Authenticate", "Basic realm=%"My Silly demo auth, password must be the same as login such as foo:foo%""]>>) + res.write_string ("Unauthorized") + end + + execute_application (ctx: APP_REQUEST_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + local + l_full: BOOLEAN + h: EWF_HEADER + l_login: STRING_8 + s: STRING + content_type_supported: ARRAY [STRING] + l_format_id: INTEGER + do + content_type_supported := <<{HTTP_CONSTANTS}.json_app, {HTTP_CONSTANTS}.xml_text, {HTTP_CONSTANTS}.plain_text>> + l_format_id := ctx.request_format_id ("format", content_type_supported) + if ctx.authenticated then + l_full := attached ctx.query_parameter ("details") as v and then v.is_case_insensitive_equal ("true") + if attached ctx.authenticated_identifier as log then + l_login := log.as_string_8 + + create h.make + + create s.make_empty + inspect l_format_id + when {HTTP_FORMAT_CONSTANTS}.json then + h.put_content_type_text_plain + s.append_string ("{ %"login%": %"" + l_login + "%" }%N") + when {HTTP_FORMAT_CONSTANTS}.xml then + h.put_content_type_text_xml + s.append_string ("" + l_login + "%N") + when {HTTP_FORMAT_CONSTANTS}.text then -- Default + h.put_content_type_text_plain + s.append_string ("login: " + l_login + "%N") + else + execute_content_type_not_allowed (req, res, content_type_supported, + <<{HTTP_FORMAT_CONSTANTS}.json_name, {HTTP_FORMAT_CONSTANTS}.html_name, {HTTP_FORMAT_CONSTANTS}.xml_name, {HTTP_FORMAT_CONSTANTS}.text_name>> + ) + end + if not s.is_empty then + res.set_status_code ({HTTP_STATUS_CODE}.ok) + res.write_headers_string (h.string) + res.write_string (s) + end + else + send_error (ctx.path, 0, "User/password unknown", Void, ctx, req, res) + end + else + send_error (ctx.path, 0, "Authentication rejected", Void, ctx, req, res) + end + end + +note + copyright: "Copyright (c) 1984-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/rest/tests/src/app/app_test.e b/library/server/request/rest/tests/src/app/app_test.e new file mode 100644 index 00000000..5d3f1ca2 --- /dev/null +++ b/library/server/request/rest/tests/src/app/app_test.e @@ -0,0 +1,95 @@ +note + description: "Summary description for {APP_TEST}." + date: "$Date$" + revision: "$Revision$" + +class + APP_TEST + +inherit + APP_REQUEST_HANDLER + redefine + initialize + end + +create + make + +feature {NONE} -- Initialization + + make + do + description := "Return a simple test output " + initialize + end + + initialize + do + Precursor + enable_request_method_get + enable_format_text + end + +feature -- Access + + authentication_required: BOOLEAN = False + +feature -- Execution + + execute_application (ctx: APP_REQUEST_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + -- Execute request handler + local + s: STRING + h: EWF_HEADER + do + create h.make + h.put_content_type_text_plain + + create s.make_empty + s.append_string ("test") + if attached req.meta_variable ("REQUEST_COUNT") as l_request_count then + s.append_string ("(request_count="+ l_request_count +")%N") + end + +-- ctx.request_format_id ("format", Void) + + if attached ctx.request_format ("format", Void) as l_format then + s.append_string (" format=" + l_format + "%N") + end + + if attached ctx.parameter ("op") as l_op then + s.append_string (" op=" + l_op) + if l_op.same_string ("crash") then + (create {DEVELOPER_EXCEPTION}).raise + elseif l_op.starts_with ("env") then + s.append_string ("%N%NAll variables:") + s.append (string_hash_table_string_string (req.parameters.new_cursor, False)) + s.append_string ("
script_url(%"" + req.path_info + "%")=" + ctx.script_url (req.path_info) + "%N") +-- if attached ctx.http_authorization_login_password as t then +-- s.append_string ("Check login=" + t.login + "
%N") +-- end + if ctx.authenticated and then attached ctx.authenticated_identifier as l_login then + s.append_string ("Authenticated: login=" + l_login.as_string_8 + "
%N") + end + end + else + s.append ("%N Try " + ctx.script_absolute_url (req.path_info + "?op=env") + " to display all variables%N") + s.append ("%N Try " + ctx.script_absolute_url (req.path_info + "?op=crash") + " to demonstrate exception trace%N") + end + + res.set_status_code (200) + res.write_headers_string (h.string) + res.write_string (s) + end + +note + copyright: "Copyright (c) 1984-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/rest/tests/src/app_server.e b/library/server/request/rest/tests/src/app_server.e new file mode 100644 index 00000000..51c6399e --- /dev/null +++ b/library/server/request/rest/tests/src/app_server.e @@ -0,0 +1,148 @@ +note + description: "Summary description for {APP_SERVER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + APP_SERVER + +inherit + APP_APPLICATION + redefine + execute + end + + REST_APPLICATION_GATEWAY + +create + make + +feature {NONE} -- Initialization + + make + -- Initialize `Current'. + do + initialize_router + build_gateway_and_launch + end + +feature {NONE} -- Handlers + + create_router + -- Create `router' + do + create router.make (5) + end + + setup_router + local + h: APP_REQUEST_HANDLER + rah: APP_REQUEST_AGENT_HANDLER + gh: APP_REQUEST_ROUTING_HANDLER + do + create {APP_ACCOUNT_VERIFY_CREDENTIAL} h.make + router.map ("/account/verify_credentials", h) + router.map ("/account/verify_credentials.{format}", h) + + + create {APP_TEST} h.make + + create gh.make (4) + router.map ("/test", gh) + gh.map_default (h) +-- gh.map ("/test", h) + gh.map ("/test/{op}", h) + gh.map ("/test.{format}", h) + gh.map ("/test.{format}/{op}", h) + + + create rah.make (agent execute_exit_application) + h := rah + h.set_description ("tell the REST server to exit (in FCGI context, this is used to reload the FCGI server)") + h.enable_request_method_get + h.enable_format_text + router.map ("/debug/exit", h) + router.map ("/debug/exit.{format}", h) + end + +feature -- Execution + + execute (req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + do + request_count := request_count + 1 + Precursor (req, res) + end + + execute_default (req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + local + rqst_uri: detachable STRING + l_path_info: detachable STRING + h: EWF_HEADER + s: STRING + l_redir_url: STRING + do + create h.make +-- h.put_refresh (ctx.script_url ("/doc"), 2, {HTTP_STATUS_CODE}.temp_redirect) + l_redir_url := "/doc" + h.put_refresh (l_redir_url, 2, {HTTP_STATUS_CODE}.temp_redirect) + h.put_content_type_text_html + create s.make_empty + s := "Request [" + req.path_info + "] is not available.
%N"; + s.append ("You are being redirected to /doc in 2 seconds ...%N") + h.put_content_length (s.count) + res.set_status_code (200) + res.write_headers_string (h.string) + res.write_string (s) + end + +-- execute_rescue (ctx: like new_request_context) +-- -- Execute the default rescue behavior +-- do +-- execute_exception_trace (ctx) +-- end + +feature -- Implementation + +-- execute_exception_trace (ctx: like new_request_context) +-- local +-- h: EWF_HEADER +-- s: STRING +-- do +-- create h.make +-- h.put_content_type_text_plain +-- ctx.output.put_string (h.string) +-- ctx.output.put_string ("Error occurred .. rq="+ request_count.out +"%N") + +-- if attached (create {EXCEPTIONS}).exception_trace as l_trace then +-- ctx.output.put_string ("
" + l_trace + "
") +-- end +-- h.recycle +-- exit_with_code (-1) +-- end + + execute_exit_application (ctx: APP_REQUEST_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + local + s: STRING + do + res.set_status_code (200) + res.write_header (200, <<["Content-Type", "text/html"]>>) + + create s.make_empty + s.append_string ("Exited") + s.append_string (" start again%N") + res.write_string (s) + exit_with_code (0) + end + +note + copyright: "Copyright (c) 1984-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/rest/tests/src/gateway/cgi/rest_application_gateway.e b/library/server/request/rest/tests/src/gateway/cgi/rest_application_gateway.e new file mode 100644 index 00000000..ab7b0997 --- /dev/null +++ b/library/server/request/rest/tests/src/gateway/cgi/rest_application_gateway.e @@ -0,0 +1,24 @@ +deferred class + REST_APPLICATION_GATEWAY + +inherit + WGI_APPLICATION + +feature -- Access + + build_gateway_and_launch + local + cgi: EWF_CGI_CONNECTOR + do + create cgi.make (Current) + cgi.launch + end + + gateway_name: STRING = "CGI" + + exit_with_code (a_code: INTEGER) + do + (create {EXCEPTIONS}).die (a_code) + end + +end diff --git a/library/server/request/rest/tests/src/gateway/fcgi/rest_application_gateway.e b/library/server/request/rest/tests/src/gateway/fcgi/rest_application_gateway.e new file mode 100644 index 00000000..f78f80e8 --- /dev/null +++ b/library/server/request/rest/tests/src/gateway/fcgi/rest_application_gateway.e @@ -0,0 +1,35 @@ +deferred class + REST_APPLICATION_GATEWAY + +inherit + WGI_APPLICATION + +feature -- Access + + build_gateway_and_launch + local + libfcgi: EWF_LIBFCGI_CONNECTOR + do + create libfcgi.make (Current) + libfcgi.launch + end + + gateway_name: STRING = "libFCGI" + + exit_with_code (a_code: INTEGER) + do + (create {EXCEPTIONS}).die (a_code) + end + + +note + copyright: "Copyright (c) 1984-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/rest/tests/src/gateway/nino/rest_application_gateway.e b/library/server/request/rest/tests/src/gateway/nino/rest_application_gateway.e new file mode 100644 index 00000000..af955abd --- /dev/null +++ b/library/server/request/rest/tests/src/gateway/nino/rest_application_gateway.e @@ -0,0 +1,44 @@ +deferred class + REST_APPLICATION_GATEWAY + +inherit + WGI_APPLICATION + +feature -- Access + + build_gateway_and_launch + local + app: NINO_APPLICATION + port_number: INTEGER + base_url: STRING + do + port_number := 8080 + base_url := "" + debug ("nino") + print ("Example: start a Nino web server on port " + port_number.out + + ", %Nand reply Hello World for any request such as http://localhost:" + port_number.out + "/" + base_url + "%N") + end + create app.make_custom (agent execute, base_url) + app.force_single_threaded + + app.listen (port_number) + end + + gateway_name: STRING = "NINO" + + exit_with_code (a_code: INTEGER) + do + (create {EXCEPTIONS}).die (a_code) + end + +note + copyright: "Copyright (c) 1984-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/rest/tests/src/handler/app_application.e b/library/server/request/rest/tests/src/handler/app_application.e new file mode 100644 index 00000000..325f832f --- /dev/null +++ b/library/server/request/rest/tests/src/handler/app_application.e @@ -0,0 +1,30 @@ +note + description: "Summary description for {APP_APPLICATION}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + APP_APPLICATION + +inherit + REST_APPLICATION [APP_REQUEST_HANDLER, APP_REQUEST_HANDLER_CONTEXT] + redefine + router + end + +feature {NONE} -- Router + + router: APP_REQUEST_ROUTER + +;note + copyright: "Copyright (c) 1984-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/rest/tests/src/handler/app_request_agent_handler.e b/library/server/request/rest/tests/src/handler/app_request_agent_handler.e new file mode 100644 index 00000000..a59ab7ab --- /dev/null +++ b/library/server/request/rest/tests/src/handler/app_request_agent_handler.e @@ -0,0 +1,32 @@ +note + description: "Summary description for REST_REQUEST_AGENT_HANDLER." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + APP_REQUEST_AGENT_HANDLER + +inherit + APP_REQUEST_HANDLER + undefine + execute, pre_execute, post_execute + end + + REST_REQUEST_AGENT_HANDLER [APP_REQUEST_HANDLER_CONTEXT] + +create + make + + +note + copyright: "Copyright (c) 1984-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/rest/tests/src/handler/app_request_handler.e b/library/server/request/rest/tests/src/handler/app_request_handler.e new file mode 100644 index 00000000..f0298788 --- /dev/null +++ b/library/server/request/rest/tests/src/handler/app_request_handler.e @@ -0,0 +1,60 @@ +note + description : "Objects that ..." + date : "$Date$" + revision : "$Revision$" + +deferred class + APP_REQUEST_HANDLER + +inherit + REST_REQUEST_HANDLER [APP_REQUEST_HANDLER_CONTEXT] + + APP_REQUEST_HELPER + +feature {NONE} -- Implementation + + string_hash_table_string_string (ht: HASH_TABLE_ITERATION_CURSOR [READABLE_STRING_GENERAL, READABLE_STRING_GENERAL]; using_pre: BOOLEAN): STRING_8 + do + create Result.make (100) + if using_pre then + Result.append ("
")
+			end
+			from
+				ht.start
+			until
+				ht.after
+			loop
+				Result.append_string (ht.key.as_string_8 + " = " + ht.item.as_string_8 + "%N")
+				ht.forth
+			end
+			if using_pre then
+				Result.append ("
") + end + end + +feature -- Helpers + + format_id (s: detachable STRING): INTEGER + do + Result := {HTTP_FORMAT_CONSTANTS}.text + if s /= Void then + Result := format_constants.format_id (s) + end + end + + exit_with_code (a_code: INTEGER) + do + (create {EXCEPTIONS}).die (a_code) + end + +note + copyright: "Copyright (c) 1984-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/rest/tests/src/handler/app_request_handler_context.e b/library/server/request/rest/tests/src/handler/app_request_handler_context.e new file mode 100644 index 00000000..98bd12de --- /dev/null +++ b/library/server/request/rest/tests/src/handler/app_request_handler_context.e @@ -0,0 +1,86 @@ +note + description : "Objects that ..." + author : "$Author$" + date : "$Date$" + revision : "$Revision$" + +class + APP_REQUEST_HANDLER_CONTEXT + +inherit + REST_REQUEST_URI_TEMPLATE_HANDLER_CONTEXT + redefine + authenticated, + authenticated_identifier + end + +create + make + +feature -- Auth + + authenticated: BOOLEAN + do + if attached request.http_authorization as l_http_auth then + Result := True + end + end + + authenticated_identifier: detachable READABLE_STRING_32 + do + if authenticated then + Result := "foo" + end + end + +feature -- Format + + get_format_id (a_format_variable_name: detachable READABLE_STRING_GENERAL; a_content_type_supported: detachable ARRAY [STRING_8]) + do + if internal_format_id = 0 then + internal_format_id := request_format_id (a_format_variable_name, a_content_type_supported) + end + end + + get_format_name (a_format_variable_name: detachable READABLE_STRING_GENERAL; a_content_type_supported: detachable ARRAY [STRING_8]) + do + if internal_format_name = Void then + internal_format_name := request_format (a_format_variable_name, a_content_type_supported) + end + end + + format_id: INTEGER + do + if internal_format_id = 0 then + get_format_id (Void, Void) + end + Result := internal_format_id + end + + format_name: detachable READABLE_STRING_8 + do + Result := internal_format_name + if Result = Void then + Result := request_format (Void, Void) + internal_format_name := Result + end + end + +feature {NONE} -- Internal + + internal_format_id: like format_id + + internal_format_name: like format_name + + +;note + copyright: "Copyright (c) 1984-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/rest/tests/src/handler/app_request_helper.e b/library/server/request/rest/tests/src/handler/app_request_helper.e new file mode 100644 index 00000000..77cde314 --- /dev/null +++ b/library/server/request/rest/tests/src/handler/app_request_helper.e @@ -0,0 +1,101 @@ +note + description: "Summary description for {APP_REQUEST_HELPER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + APP_REQUEST_HELPER + +feature -- Helpers + + send_error (a_path: STRING; a_error_id: INTEGER; a_error_name: STRING; a_error_message: detachable STRING; ctx: APP_REQUEST_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + local + s: STRING + i,nb: INTEGER + rep_data: REST_RESPONSE + do + res.set_status_code ({HTTP_STATUS_CODE}.expectation_failed) + create rep_data.make (a_path) + rep_data.headers.put_content_type_text_plain + + create s.make_empty + inspect ctx.format_id + when {HTTP_FORMAT_CONSTANTS}.json then + rep_data.headers.put_content_type_text_plain + s := "{%"application%": %"" + a_path + "%"" + s.append_string (", %"error%": {") + s.append_string ("%"id%": " + a_error_id.out) + s.append_string (",%"name%": %"" + a_error_name + "%"") + if a_error_message /= Void then + s.append_string (",%"message%": %"") + + if a_error_message.has ('%N') then + from + i := s.count + s.append_string (a_error_message) + nb := s.count + until + i > nb + loop + inspect s[i] + when '%R' then + if s.valid_index (i+1) and then s[i+1] = '%N' then + s[i] := '\' + s[i+1] := 'n' + i := i + 1 + end + when '%N' then + s.insert_character ('\', i) + s[i] := 'n' + else + end + i := i + 1 + end + else + s.append_string (a_error_message) + end + s.append_string ("%"") + end + + s.append_string ("}") -- end error + s.append_string ("}") -- end global object + rep_data.set_message (s) + when {HTTP_FORMAT_CONSTANTS}.xml then + rep_data.headers.put_content_type_text_xml + s := "" + if a_error_message /= Void then + s.append_string (a_error_message) + end + s.append_string ("") + rep_data.set_message (s) + when {HTTP_FORMAT_CONSTANTS}.html then + rep_data.headers.put_content_type_text_html + s := "application: " + a_path + "
%NError (" + a_error_id.out + ") %"" + a_error_name + "%"
%N" + if a_error_message /= Void then + s.append_string ("
" + a_error_message + "
") + end + rep_data.set_message (s) + when {HTTP_FORMAT_CONSTANTS}.text then -- Default + s := "Application: " + a_path + "
%N" + s.append_string ("Error (" + a_error_id.out + ") %"" + a_error_name + "%"%N") + if a_error_message /= Void then + s.append_string ("%T" + a_error_message + "%N") + end + rep_data.set_message (s) + end + rep_data.send (res) + rep_data.recycle + end + +note + copyright: "Copyright (c) 1984-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/rest/tests/src/handler/app_request_router.e b/library/server/request/rest/tests/src/handler/app_request_router.e new file mode 100644 index 00000000..25bd2a14 --- /dev/null +++ b/library/server/request/rest/tests/src/handler/app_request_router.e @@ -0,0 +1,26 @@ +note + description: "Summary description for {REST_REQUEST_URI_TEMPLATE_ROUTER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + APP_REQUEST_ROUTER + +inherit + REST_REQUEST_URI_TEMPLATE_ROUTER [APP_REQUEST_HANDLER, APP_REQUEST_HANDLER_CONTEXT] + +create + make + +note + copyright: "Copyright (c) 1984-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/request/rest/tests/src/handler/app_request_routing_handler.e b/library/server/request/rest/tests/src/handler/app_request_routing_handler.e new file mode 100644 index 00000000..e7bcee5e --- /dev/null +++ b/library/server/request/rest/tests/src/handler/app_request_routing_handler.e @@ -0,0 +1,40 @@ +note + description: "Summary description for {APP_REQUEST_ROUTING_HANDLER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + APP_REQUEST_ROUTING_HANDLER + +inherit + APP_REQUEST_HANDLER + undefine + execute, + pre_execute, + post_execute + end + + REST_REQUEST_URI_TEMPLATE_ROUTING_HANDLER [APP_REQUEST_HANDLER, APP_REQUEST_HANDLER_CONTEXT] + redefine + router + end + +create + make + +feature {NONE} -- Routing + + router: APP_REQUEST_ROUTER + +;note + copyright: "Copyright (c) 1984-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end From 2e53f7e0c443a5630c86743103534f67b165aeaf Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Tue, 13 Sep 2011 17:12:12 +0200 Subject: [PATCH 9/9] updated changelogs --- CHANGELOGS.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOGS.txt b/CHANGELOGS.txt index 30faa5c0..4ea6deca 100644 --- a/CHANGELOGS.txt +++ b/CHANGELOGS.txt @@ -1,5 +1,15 @@ History for Eiffel-Web-Framework +[2011-09-13] Jocelyn + * library "router": now using a generic design to allow customization of + request handler context class. + * library "server/request/rest": first attempt to provide a library to + help building RESTful application (the interfaces are likely to change + soon) EXPERIMENTAL + +[2011-09-09] Jocelyn + * library "uri-template": better support for {/vars} and {?vars} + [2011-09-07] Jocelyn * library "router": now routing depends on uri (or uri template) and request methods * Nino connector: Fixed issue where HTTP_ prefix were missing for header meta variable.