added hello_routed_world example

few changes on new `router' library (still in-progress)
This commit is contained in:
Jocelyn Fiat
2011-07-29 15:13:08 +02:00
parent 1b49445077
commit 801caa4e69
9 changed files with 558 additions and 20 deletions

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-8-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-8-0 http://www.eiffel.com/developers/xml/configuration-1-8-0.xsd" name="hello_routed_world" uuid="7C9887BD-4AE4-47F2-A0AA-4BBB6736D433">
<target name="hello_routed_world">
<root class="HELLO_ROUTED_WORLD" feature="make"/>
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/\.git$</exclude>
<exclude>/\.svn$</exclude>
</file_rule>
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="provisional">
</option>
<setting name="concurrency" value="thread"/>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="default_nino" location="..\..\library\server\ewsgi\default\ewsgi_nino-safe.ecf" readonly="false"/>
<library name="connector_nino" location="..\..\library\server\ewsgi\connectors\nino\nino-safe.ecf" readonly="false"/>
<library name="ewsgi_spec" location="..\..\library\server\ewsgi\ewsgi_specification-safe.ecf" readonly="false"/>
<library name="ewsgi" location="..\..\library\server\ewsgi\ewsgi-safe.ecf" readonly="false"/>
<library name="router" location="..\..\library\server\request\router\router-safe.ecf" readonly="false"/>
<library name="uri_template" location="..\..\library\protocol\uri_template\uri_template-safe.ecf" readonly="false"/>
<library name="encoder" location="..\..\library\text\encoder\encoder-safe.ecf" readonly="false"/>
<library name="http" location="..\..\library\protocol\http\http-safe.ecf" readonly="false"/>
<cluster name="src" location="src\" recursive="true"/>
</target>
</system>

View File

@@ -0,0 +1,10 @@
${NOTE_KEYWORD}
copyright: "2011-${YEAR}, 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
]"

View File

@@ -0,0 +1,145 @@
note
description: "Summary description for {ROUTED_APPLICATION_HELPER}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
ROUTED_APPLICATION_HELPER
inherit
ANY
HTTP_FORMAT_CONSTANTS
export
{NONE} all
end
feature -- Helper
execute_content_type_not_allowed (req: EWSGI_REQUEST; res: EWSGI_RESPONSE_STREAM; a_content_types: detachable ARRAY [STRING]; a_uri_formats: detachable ARRAY [STRING])
local
s, uri_s: detachable STRING
i, n: INTEGER
h: GW_HEADER
do
create h.make
h.put_status ({HTTP_STATUS_CODE}.unsupported_media_type)
h.put_content_type_text_plain
if a_content_types /= Void then
create s.make (10)
from
i := a_content_types.lower
n := a_content_types.upper
until
i > n
loop
s.append_string (a_content_types[i])
if i < n then
s.append_character (',')
s.append_character (' ')
end
i := i + 1
end
h.put_header_key_value ("Accept", s)
end
if a_uri_formats /= Void then
create uri_s.make (10)
from
i := a_uri_formats.lower
n := a_uri_formats.upper
until
i > n
loop
uri_s.append_string (a_uri_formats[i])
if i < n then
uri_s.append_character (',')
uri_s.append_character (' ')
end
i := i + 1
end
end
if s /= Void then
res.write_string ("Unsupported request content-type, Accept: " + s + "%N")
end
if uri_s /= Void then
res.write_string ("Unsupported request format from the URI: " + uri_s + "%N")
end
end
execute_method_not_allowed (req: EWSGI_REQUEST; res: EWSGI_RESPONSE_STREAM; a_methods: ARRAY [STRING])
local
s: STRING
i, n: INTEGER
do
create s.make (10)
from
i := a_methods.lower
n := a_methods.upper
until
i > n
loop
s.append_string (a_methods[i])
if i < n then
s.append_character (',')
s.append_character (' ')
end
i := i + 1
end
res.write_header ({HTTP_STATUS_CODE}.method_not_allowed, <<
["Content-Type", {HTTP_CONSTANTS}.plain_text],
["Allow", s]
>>)
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, l_content_type: 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 STRING): 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)"
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

View File

@@ -0,0 +1,183 @@
note
description : "Objects that ..."
author : "$Author$"
date : "$Date$"
revision : "$Revision$"
class
HELLO_ROUTED_WORLD
inherit
ANY
ROUTED_APPLICATION
ROUTED_APPLICATION_HELPER
DEFAULT_EWSGI_APPLICATION
create
make
feature {NONE} -- Initialization
make
do
initialize_router
make_and_launch
end
create_router
do
-- create {REQUEST_URI_ROUTER} router.make (5)
create {REQUEST_URI_TEMPLATE_ROUTER} router.make (5)
end
setup_router
local
ra: REQUEST_AGENT_HANDLER
do
router.map_agent ("/home", agent execute_home)
create ra.make (agent handle_hello)
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)
end
feature -- Execution
execute_default (req: EWSGI_REQUEST; res: EWSGI_RESPONSE_STREAM)
local
h: GW_HEADER
l_url: STRING
e: EXECUTION_ENVIRONMENT
n: INTEGER
i: INTEGER
do
create h.make
l_url := req.script_url ("/home")
n := 3
h.put_refresh (l_url, 5, 200)
res.set_status_code (200)
res.write_string (h.string)
from
create e
until
n = 0
loop
if n > 1 then
res.write_string ("Redirected to " + l_url + " in " + n.out + " seconds :%N")
else
res.write_string ("Redirected to " + l_url + " in 1 second :%N")
end
res.flush
from
i := 1
until
i = 1001
loop
res.write_string (".")
if i \\ 100 = 0 then
res.write_string ("%N")
end
res.flush
e.sleep (1_000_000)
i := i + 1
end
res.write_string ("%N")
n := n - 1
end
res.write_string ("You are now being redirected...%N")
res.flush
end
execute_home (ctx: REQUEST_HANDLER_CONTEXT; req: EWSGI_REQUEST; res: EWSGI_RESPONSE_STREAM)
do
res.write_header (200, <<["Content-Type", "text/html"]>>)
res.write_string ("<html><body>Hello World ?!%N")
res.write_string ("<h3>Please try the following links</h3><ul>%N")
res.write_string ("<li><a href=%""+ req.script_url ("/") + "%">default</a></li>%N")
res.write_string ("<li><a href=%""+ req.script_url ("/hello") + "%">/hello</a></li>%N")
res.write_string ("<li><a href=%""+ req.script_url ("/hello.html/Joce") + "%">/hello.html/Joce</a></li>%N")
res.write_string ("<li><a href=%""+ req.script_url ("/hello.json/Joce") + "%">/hello.json/Joce</a></li>%N")
res.write_string ("<li><a href=%""+ req.script_url ("/hello/Joce.html") + "%">/hello/Joce.html</a></li>%N")
res.write_string ("<li><a href=%""+ req.script_url ("/hello/Joce.xml") + "%">/hello/Joce.xml</a></li>%N")
res.write_string ("<li><a href=%""+ req.script_url ("/hello/Joce") + "%">/hello/Joce</a></li>%N")
res.write_string ("</ul>%N")
if attached req.environment_variable ("REQUEST_COUNT") as rqc then
res.write_string ("request #"+ rqc + "%N")
end
res.write_string ("</body></html>%N")
end
execute_hello (req: EWSGI_REQUEST; res: EWSGI_RESPONSE_STREAM; a_name: detachable STRING_32; ctx: REQUEST_HANDLER_CONTEXT)
local
l_response_content_type: detachable STRING
msg: STRING
h: GW_HEADER
content_type_supported: ARRAY [STRING]
do
if a_name /= Void then
msg := "Hello %"" + a_name + "%" !%N"
else
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)
when {HTTP_FORMAT_CONSTANTS}.json then
l_response_content_type := {HTTP_CONSTANTS}.json_app
msg := "{%N%"application%": %"/hello%",%N %"message%": %"" + msg + "%" %N}"
when {HTTP_FORMAT_CONSTANTS}.html then
l_response_content_type := {HTTP_CONSTANTS}.html_text
when {HTTP_FORMAT_CONSTANTS}.xml then
l_response_content_type := {HTTP_CONSTANTS}.xml_text
msg := "<response><application>/hello</application><message>" + msg + "</message></response>%N"
when {HTTP_FORMAT_CONSTANTS}.text then
l_response_content_type := {HTTP_CONSTANTS}.plain_text
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 l_response_content_type /= Void then
create h.make
h.put_status (200)
h.put_content_type (l_response_content_type)
h.put_content_length (msg.count)
res.set_status_code (200)
res.write_string (h.string)
-- res.write_header (200, <<
-- ["Content-Type", l_response_content_type],
-- ["Content-Length", msg.count.out
-- >>)
res.write_string (msg)
end
end
handle_hello (ctx: REQUEST_HANDLER_CONTEXT; req: EWSGI_REQUEST; res: EWSGI_RESPONSE_STREAM)
do
execute_hello (req, res, Void, ctx)
end
handle_anonymous_hello (ctx: REQUEST_HANDLER_CONTEXT; req: EWSGI_REQUEST; res: EWSGI_RESPONSE_STREAM)
do
execute_hello (req, res, ctx.parameter ("name"), ctx)
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

View File

@@ -11,6 +11,7 @@
<assertions precondition="true"/>
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="base_extension" location="$ISE_LIBRARY\library\base_extension\base_extension-safe.ecf"/>
<library name="ewsgi_spec" location="..\..\ewsgi\ewsgi_specification-safe.ecf" readonly="false"/>
<library name="http" location="..\..\..\protocol\http\http-safe.ecf"/>
<library name="uri_template" location="..\..\..\protocol\uri_template\uri_template-safe.ecf" readonly="false"/>

View File

@@ -7,14 +7,15 @@
<exclude>/EIFGENs$</exclude>
<exclude>/.svn$</exclude>
</file_rule>
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all">
<option warning="true" full_class_checking="true">
<assertions precondition="true"/>
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="ewsgi_spec" location="..\..\ewsgi\ewsgi_specification-safe.ecf" readonly="false"/>
<library name="http" location="..\..\..\protocol\http\http-safe.ecf"/>
<library name="uri_template" location="..\..\..\protocol\uri_template\uri_template-safe.ecf" readonly="false"/>
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
<library name="base_extension" location="$ISE_LIBRARY\library\base_extension\base_extension.ecf"/>
<library name="ewsgi_spec" location="..\..\ewsgi\ewsgi_specification.ecf" readonly="false"/>
<library name="http" location="..\..\..\protocol\http\http.ecf"/>
<library name="uri_template" location="..\..\..\protocol\uri_template\uri_template.ecf" readonly="false"/>
<library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/>
<cluster name="src" location="src\" recursive="true"/>
</target>
</system>

View File

@@ -0,0 +1,61 @@
note
description: "Summary description for {ROUTED_APPLICATION}."
author: ""
date: "$Date$"
revision: "$Revision$"
deferred class
ROUTED_APPLICATION
feature -- Setup
initialize_router
-- Initialize `router'
do
create_router
setup_router
end
create_router
-- Create `router'
deferred
ensure
router_created: router /= Void
end
setup_router
-- Setup `router'
require
router_created: router /= Void
deferred
end
router: REQUEST_ROUTER
-- Request router
feature -- Execution
execute (req: EWSGI_REQUEST; res: EWSGI_RESPONSE_STREAM)
do
if attached router.dispatch (req, res) as r then
--| done
else
execute_default (req, res)
end
end
execute_default (req: EWSGI_REQUEST; res: EWSGI_RESPONSE_STREAM)
deferred
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

View File

@@ -7,6 +7,14 @@ note
deferred class
REQUEST_HANDLER_CONTEXT
inherit
ANY
REQUEST_FORMAT_UTILITY
export
{NONE} all
end
feature -- Access
request: EWSGI_REQUEST
@@ -15,23 +23,39 @@ feature -- Access
path: STRING
-- ???
request_format: detachable STRING
-- Request format based on `Content-Type'.
request_content_type (content_type_supported: detachable ARRAY [STRING]): detachable STRING
local
s: detachable STRING
i,n: INTEGER
do
s := request.environment.content_type
if s = Void then
elseif s.same_string ({HTTP_CONSTANTS}.json_text) then
Result := {HTTP_FORMAT_CONSTANTS}.json_name
elseif s.same_string ({HTTP_CONSTANTS}.json_app) then
Result := {HTTP_FORMAT_CONSTANTS}.json_name
elseif s.same_string ({HTTP_CONSTANTS}.xml_text) then
Result := {HTTP_FORMAT_CONSTANTS}.xml_name
elseif s.same_string ({HTTP_CONSTANTS}.html_text) then
Result := {HTTP_FORMAT_CONSTANTS}.html_name
elseif s.same_string ({HTTP_CONSTANTS}.plain_text) then
Result := {HTTP_FORMAT_CONSTANTS}.text_name
Result := request.environment.content_type
if Result = Void then
s := request.environment.http_accept
if s /= Void then
if attached accepted_content_types (request) as l_accept_lst then
from
l_accept_lst.start
until
l_accept_lst.after or Result /= Void
loop
s := l_accept_lst.item
if content_type_supported /= Void then
from
i := content_type_supported.lower
n := content_type_supported.upper
until
i > n or Result /= Void
loop
if content_type_supported[i].same_string (s) then
Result := s
end
i := i + 1
end
end
l_accept_lst.forth
end
end
end
end
end

View File

@@ -0,0 +1,89 @@
note
description: "Summary description for {REQUEST_FORMAT_UTILITY}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
REQUEST_FORMAT_UTILITY
feature -- Access
accepted_content_types (req: EWSGI_REQUEST): detachable ARRAYED_LIST [STRING]
local
l_accept: detachable STRING
s,q: STRING
p: INTEGER
lst: LIST [STRING]
qs: QUICK_SORTER [STRING]
do
l_accept := req.environment.http_accept
--TEST l_accept := "text/html,application/xhtml+xml;q=0.6,application/xml;q=0.2,text/plain;q=0.5,*/*;q=0.8"
if l_accept /= Void then
lst := l_accept.split (',')
create Result.make (lst.count)
from
lst.start
until
lst.after
loop
s := lst.item
p := s.substring_index (";q=", 1)
if p > 0 then
q := s.substring (p + 3, s.count)
s := s.substring (1, p - 1)
else
q := "1.0"
end
Result.force (q + ":" + s)
lst.forth
end
create qs.make (create {COMPARABLE_COMPARATOR [STRING]})
qs.reverse_sort (Result)
from
Result.start
until
Result.after
loop
s := Result.item
p := s.index_of (':', 1)
if p > 0 then
s.remove_head (p)
else
check should_have_colon: False end
end
Result.forth
end
end
end
feature {NONE} -- Implementation
string_in_array (arr: ARRAY [STRING]; s: STRING): BOOLEAN
local
i,n: INTEGER
do
from
i := arr.lower
n := arr.upper
until
i > n or Result
loop
Result := s.same_string (arr[i])
i := i + 1
end
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