Compare commits
17 Commits
Review_EWS
...
code_revie
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ec6cc5f2b8 | ||
|
|
40018d36eb | ||
|
|
8e18329063 | ||
|
|
c372494713 | ||
|
|
10f4a99ee1 | ||
|
|
e9085c614c | ||
|
|
f7d3f519a7 | ||
|
|
4eb22d0272 | ||
|
|
bbcc9ef44b | ||
|
|
801caa4e69 | ||
|
|
1b49445077 | ||
|
|
f005d8bb06 | ||
|
|
a278537f7b | ||
|
|
78b5b6f5fe | ||
|
|
a215c1e4d2 | ||
|
|
fe3726677b | ||
|
|
94d4909644 |
2
doc/wiki
2
doc/wiki
Submodule doc/wiki updated: c7f4f45f5e...a2a1f89299
24
examples/hello_routed_world/hello-safe.ecf
Normal file
24
examples/hello_routed_world/hello-safe.ecf
Normal 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">
|
||||
<assertions precondition="true" postcondition="true" invariant="true" supplier_precondition="true"/>
|
||||
</option>
|
||||
<setting name="concurrency" value="thread"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="connector_nino" location="..\..\library\server\ewsgi\connectors\nino\nino-safe.ecf" readonly="false"/>
|
||||
<library name="default_nino" location="..\..\library\server\ewsgi\default\ewsgi_nino-safe.ecf" readonly="false"/>
|
||||
<library name="encoder" location="..\..\library\text\encoder\encoder-safe.ecf" readonly="false"/>
|
||||
<library name="ewsgi" location="..\..\library\server\ewsgi\ewsgi-safe.ecf" readonly="false"/>
|
||||
<library name="http" location="..\..\library\protocol\http\http-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"/>
|
||||
<cluster name="src" location="src\" recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
10
examples/hello_routed_world/license.lic
Normal file
10
examples/hello_routed_world/license.lic
Normal 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
|
||||
]"
|
||||
@@ -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_BUFFER; 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_BUFFER; 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: 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
|
||||
183
examples/hello_routed_world/src/hello_routed_world.e
Normal file
183
examples/hello_routed_world/src/hello_routed_world.e
Normal 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_BUFFER)
|
||||
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_headers_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_BUFFER)
|
||||
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_BUFFER; 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_BUFFER)
|
||||
do
|
||||
execute_hello (req, res, Void, ctx)
|
||||
end
|
||||
|
||||
handle_anonymous_hello (ctx: REQUEST_HANDLER_CONTEXT; req: EWSGI_REQUEST; res: EWSGI_RESPONSE_BUFFER)
|
||||
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
|
||||
@@ -8,6 +8,11 @@ note
|
||||
class
|
||||
ERROR_HANDLER
|
||||
|
||||
inherit
|
||||
ANY
|
||||
|
||||
DEBUG_OUTPUT
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
@@ -35,6 +40,18 @@ feature -- Status
|
||||
errors: LIST [ERROR]
|
||||
-- Errors container
|
||||
|
||||
feature -- Status report
|
||||
|
||||
debug_output: STRING
|
||||
-- String that should be displayed in debugger to represent `Current'.
|
||||
do
|
||||
if has_error then
|
||||
Result := count.out + " errors"
|
||||
else
|
||||
Result := "no error"
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Basic operation
|
||||
|
||||
add_error (a_error: ERROR)
|
||||
@@ -52,6 +69,12 @@ feature -- Basic operation
|
||||
add_error (e)
|
||||
end
|
||||
|
||||
append (a_err_handler: ERROR_HANDLER)
|
||||
-- Append errors from `a_err_handler'
|
||||
do
|
||||
errors.append (a_err_handler.errors)
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
as_single_error: detachable ERROR
|
||||
@@ -61,6 +84,20 @@ feature -- Access
|
||||
elseif count > 0 then
|
||||
Result := errors.first
|
||||
end
|
||||
ensure
|
||||
has_error_implies_result_attached: has_error implies Result /= Void
|
||||
end
|
||||
|
||||
as_string_representation: STRING
|
||||
require
|
||||
has_error
|
||||
do
|
||||
if attached as_single_error as e then
|
||||
Result := e.string_representation
|
||||
else
|
||||
check has_error: False end
|
||||
Result := "Error occured"
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Element changes
|
||||
|
||||
@@ -153,6 +153,8 @@ feature -- Builder
|
||||
feature -- Match
|
||||
|
||||
match (a_uri: STRING): detachable URI_TEMPLATE_MATCH_RESULT
|
||||
require
|
||||
is_valid: is_valid
|
||||
local
|
||||
b: BOOLEAN
|
||||
tpl: like template
|
||||
@@ -163,6 +165,8 @@ feature -- Match
|
||||
vv: STRING
|
||||
l_vars, l_path_vars, l_query_vars: HASH_TABLE [STRING, STRING]
|
||||
l_uri_count: INTEGER
|
||||
tpl_count: INTEGER
|
||||
l_next_literal_separator: detachable STRING
|
||||
do
|
||||
--| Extract expansion parts "\\{([^\\}]*)\\}"
|
||||
analyze
|
||||
@@ -173,8 +177,10 @@ feature -- Match
|
||||
b := True
|
||||
l_uri_count := a_uri.count
|
||||
tpl := template
|
||||
tpl_count := tpl.count
|
||||
if l_expressions.is_empty then
|
||||
b := a_uri.substring (1, tpl.count).same_string (tpl)
|
||||
-- b := a_uri.substring (1, tpl_count).same_string (tpl)
|
||||
b := a_uri.same_string (tpl)
|
||||
else
|
||||
from
|
||||
l_expressions.start
|
||||
@@ -200,6 +206,8 @@ feature -- Match
|
||||
b := s.same_string (t)
|
||||
p := exp.end_position
|
||||
end
|
||||
l_expressions.forth --| we forth `l_expressions' so be careful
|
||||
|
||||
--| Check related variable
|
||||
if b and then not vn.is_empty then
|
||||
if exp.is_query then
|
||||
@@ -211,10 +219,21 @@ feature -- Match
|
||||
inspect vn[1]
|
||||
when '?' then
|
||||
import_form_style_parameters_into (a_uri.substring (q + l_offset + 1, l_uri_count), l_vars)
|
||||
p := tpl_count + 1
|
||||
l_offset := l_offset + (l_uri_count - (q + l_offset + 1))
|
||||
when ';' then
|
||||
import_path_style_parameters_into (a_uri.substring (q + l_offset, l_uri_count), l_vars)
|
||||
p := tpl_count + 1
|
||||
else
|
||||
vv := next_path_variable_value (a_uri, q + l_offset)
|
||||
if not l_expressions.after then
|
||||
exp := l_expressions.item --| We change `exp' here
|
||||
l_next_literal_separator := tpl.substring (p, exp.position -1)
|
||||
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)
|
||||
end
|
||||
@@ -222,7 +241,17 @@ feature -- Match
|
||||
b := exp.is_query --| query are optional
|
||||
end
|
||||
end
|
||||
l_expressions.forth
|
||||
if b and l_expressions.after then
|
||||
if
|
||||
(p < tpl_count) or
|
||||
(p + l_offset < l_uri_count)
|
||||
then
|
||||
--| Remaining literal part
|
||||
t := tpl.substring (p, tpl_count)
|
||||
s := a_uri.substring (p + l_offset, l_uri_count)
|
||||
b := s.same_string (t)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if b then
|
||||
@@ -231,8 +260,36 @@ feature -- Match
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Basic operation
|
||||
|
||||
parse
|
||||
-- Parse template
|
||||
do
|
||||
reset
|
||||
analyze
|
||||
end
|
||||
|
||||
feature -- Status report
|
||||
|
||||
is_valid: BOOLEAN
|
||||
-- Is Current URI template valid?
|
||||
do
|
||||
analyze
|
||||
Result := not has_syntax_error
|
||||
end
|
||||
|
||||
feature {NONE} -- Internal Access
|
||||
|
||||
reset
|
||||
do
|
||||
expressions := Void
|
||||
has_syntax_error := False
|
||||
end
|
||||
|
||||
has_syntax_error: BOOLEAN
|
||||
-- Has syntax error
|
||||
--| Make sense only if `analyze' was processed before
|
||||
|
||||
expressions: detachable LIST [URI_TEMPLATE_EXPRESSION]
|
||||
-- Expansion parts
|
||||
|
||||
@@ -248,6 +305,7 @@ feature {NONE} -- Implementation
|
||||
in_query: BOOLEAN
|
||||
x: STRING
|
||||
exp: URI_TEMPLATE_EXPRESSION
|
||||
l_has_query_expression: BOOLEAN
|
||||
do
|
||||
l_expressions := expressions
|
||||
if l_expressions = Void then
|
||||
@@ -258,6 +316,7 @@ feature {NONE} -- Implementation
|
||||
from
|
||||
i := 1
|
||||
n := tpl.count
|
||||
l_has_query_expression := False
|
||||
create x.make_empty
|
||||
until
|
||||
i > n
|
||||
@@ -269,6 +328,10 @@ feature {NONE} -- Implementation
|
||||
l_expressions.force (exp)
|
||||
x.wipe_out
|
||||
in_x := False
|
||||
if l_has_query_expression and then i < n then
|
||||
--| Remaining text after {?exp}
|
||||
has_syntax_error := True
|
||||
end
|
||||
else
|
||||
x.extend (c)
|
||||
end
|
||||
@@ -278,8 +341,11 @@ feature {NONE} -- Implementation
|
||||
check x_is_empty: x.is_empty end
|
||||
p := i
|
||||
in_x := True
|
||||
if not l_has_query_expression then
|
||||
l_has_query_expression := tpl.valid_index (i+1) and then tpl[i+1] = '?'
|
||||
end
|
||||
if not in_query then
|
||||
in_query := tpl.valid_index (i+1) and then tpl[i+1] = '?'
|
||||
in_query := l_has_query_expression
|
||||
end
|
||||
when '?' then
|
||||
in_query := True
|
||||
@@ -344,23 +410,39 @@ feature {NONE} -- Implementation
|
||||
end
|
||||
end
|
||||
|
||||
next_path_variable_value (a_uri: STRING; a_index: INTEGER): STRING
|
||||
next_path_variable_value (a_uri: STRING; a_index: INTEGER; a_end_token: detachable STRING): STRING
|
||||
require
|
||||
valid_index: a_index <= a_uri.count
|
||||
local
|
||||
c: CHARACTER
|
||||
i,n,p: INTEGER
|
||||
l_end_token_first_char: CHARACTER
|
||||
l_end_token_count: INTEGER
|
||||
do
|
||||
from
|
||||
if a_end_token /= Void and then not a_end_token.is_empty then
|
||||
l_end_token_first_char := a_end_token.item (1)
|
||||
l_end_token_count := a_end_token.count
|
||||
end
|
||||
i := a_index
|
||||
n := a_uri.count
|
||||
until
|
||||
i > n
|
||||
loop
|
||||
inspect a_uri[i]
|
||||
c := a_uri[i]
|
||||
inspect c
|
||||
when '/', '?' then
|
||||
i := n
|
||||
else
|
||||
p := i
|
||||
if
|
||||
a_end_token /= Void and then
|
||||
c = l_end_token_first_char and then
|
||||
a_uri.substring (i, i + l_end_token_count - 1).same_string (a_end_token)
|
||||
then
|
||||
i := n
|
||||
else
|
||||
p := i
|
||||
end
|
||||
end
|
||||
i := i + 1
|
||||
end
|
||||
|
||||
@@ -11,7 +11,8 @@ inherit
|
||||
ANY
|
||||
|
||||
DEBUG_OUTPUT
|
||||
|
||||
export {NONE} all end
|
||||
|
||||
URI_TEMPLATE_CONSTANTS
|
||||
export {NONE} all end
|
||||
|
||||
|
||||
@@ -24,22 +24,75 @@ feature {NONE} -- Initialization
|
||||
make (create {like path_variables}.make (0), create {like query_variables}.make (0))
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
variable (n: STRING): detachable STRING
|
||||
-- Value related to variable name `n'
|
||||
do
|
||||
Result := query_variables.item (n)
|
||||
if Result = Void then
|
||||
Result := path_variables.item (n)
|
||||
end
|
||||
end
|
||||
feature -- Access
|
||||
|
||||
path_variables: HASH_TABLE [STRING, STRING]
|
||||
-- Variables being part of the path segments
|
||||
|
||||
query_variables: HASH_TABLE [STRING, STRING]
|
||||
-- Variables being part of the query segments (i.e: after the ? )
|
||||
-- Variables being part of the query segments (i.e: after the ?)
|
||||
|
||||
feature -- Query
|
||||
|
||||
path_variable (n: STRING): detachable STRING
|
||||
-- Value related to query variable name `n'
|
||||
do
|
||||
Result := path_variables.item (n)
|
||||
end
|
||||
|
||||
query_variable (n: STRING): detachable STRING
|
||||
-- Value related to path variable name `n'
|
||||
do
|
||||
Result := query_variables.item (n)
|
||||
end
|
||||
|
||||
variable (n: STRING): detachable STRING
|
||||
-- Value related to variable name `n'
|
||||
do
|
||||
Result := query_variable (n)
|
||||
if Result = Void then
|
||||
Result := path_variable (n)
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Query: url-decoded
|
||||
|
||||
url_decoded_query_variable (n: STRING): detachable STRING_32
|
||||
-- Unencoded value related to variable name `n'
|
||||
do
|
||||
if attached query_variable (n) as v then
|
||||
Result := url_decoded_string (v)
|
||||
end
|
||||
end
|
||||
|
||||
url_decoded_path_variable (n: STRING): detachable STRING_32
|
||||
-- Unencoded value related to variable name `n'
|
||||
do
|
||||
if attached path_variable (n) as v then
|
||||
Result := url_decoded_string (v)
|
||||
end
|
||||
end
|
||||
|
||||
url_decoded_variable (n: STRING): detachable STRING_32
|
||||
-- Unencoded value related to variable name `n'
|
||||
do
|
||||
if attached variable (n) as v then
|
||||
Result := url_decoded_string (v)
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
url_decoded_string (s: READABLE_STRING_GENERAL): STRING_32
|
||||
do
|
||||
Result := url_encoder.decoded_string (s.as_string_8)
|
||||
end
|
||||
|
||||
url_encoder: URL_ENCODER
|
||||
once
|
||||
create Result
|
||||
end
|
||||
|
||||
;note
|
||||
copyright: "2011-2011, Eiffel Software and others"
|
||||
|
||||
@@ -21,6 +21,9 @@ feature -- Test routines
|
||||
do
|
||||
uri_template_parse ("api/foo/{foo_id}/{?id,extra}", <<"foo_id">>, <<"id", "extra">>)
|
||||
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">>)
|
||||
end
|
||||
|
||||
test_uri_template_matcher
|
||||
@@ -49,6 +52,32 @@ feature -- Test routines
|
||||
|
||||
create tpl.make ("weather/{state}/{city}?forecast={day}")
|
||||
uri_template_match (tpl, "weather/California/Goleta?forecast=today", <<["state", "California"], ["city", "Goleta"]>>, <<["day", "today"]>>)
|
||||
|
||||
create tpl.make ("/hello")
|
||||
uri_template_match (tpl, "/hello", <<>>, <<>>)
|
||||
uri_template_mismatch (tpl, "/hello/Foo2") -- longer
|
||||
uri_template_mismatch (tpl, "/hell") -- shorter
|
||||
|
||||
create tpl.make ("/hello.{format}")
|
||||
uri_template_match (tpl, "/hello.xml", <<["format", "xml"]>>, <<>>)
|
||||
uri_template_mismatch (tpl, "/hello.xml/Bar")
|
||||
|
||||
|
||||
create tpl.make ("/hello.{format}/{name}")
|
||||
uri_template_match (tpl, "/hello.xml/Joce", <<["format", "xml"], ["name", "Joce"]>>, <<>>)
|
||||
|
||||
create tpl.make ("/hello/{name}.{format}")
|
||||
uri_template_match (tpl, "/hello/Joce.json", <<["name", "Joce"], ["format", "json"]>>, <<>>)
|
||||
|
||||
create tpl.make ("/hello/{name}.{format}/foo")
|
||||
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"]>>)
|
||||
|
||||
end
|
||||
|
||||
uri_template_string_errors: detachable LIST [STRING]
|
||||
@@ -544,6 +573,8 @@ feature -- Test routines
|
||||
i: INTEGER
|
||||
do
|
||||
create u.make (s)
|
||||
u.parse
|
||||
assert ("Template %""+ s +"%" is valid", u.is_valid)
|
||||
if attached u.path_variable_names as vars then
|
||||
matched := vars.count = path_vars.count
|
||||
from
|
||||
@@ -559,7 +590,7 @@ feature -- Test routines
|
||||
else
|
||||
matched := path_vars.is_empty
|
||||
end
|
||||
assert ("path variables matched", matched)
|
||||
assert ("path variables matched for %""+ s +"%"", matched)
|
||||
|
||||
if attached u.query_variable_names as vars then
|
||||
matched := vars.count = query_vars.count
|
||||
@@ -576,7 +607,7 @@ feature -- Test routines
|
||||
else
|
||||
matched := query_vars.is_empty
|
||||
end
|
||||
assert ("query variables matched", matched)
|
||||
assert ("query variables matched %""+ s +"%"", matched)
|
||||
end
|
||||
|
||||
uri_template_mismatch (a_uri_template: URI_TEMPLATE; a_uri: STRING)
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all">
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="ewsgi_spec" location="..\..\ewsgi_specification-safe.ecf" readonly="false"/>
|
||||
<library name="ewsgi" location="..\..\ewsgi-safe.ecf" readonly="false"/>
|
||||
<library name="http" location="..\..\..\..\protocol\http\http-safe.ecf"/>
|
||||
<cluster name="src" location=".\src\" recursive="true"/>
|
||||
</target>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<option warning="true" full_class_checking="true">
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||
<library name="ewsgi_spec" location="..\..\ewsgi_specification.ecf" readonly="false"/>
|
||||
<library name="ewsgi" location="..\..\ewsgi.ecf" readonly="false"/>
|
||||
<library name="http" location="..\..\..\..\protocol\http\http.ecf"/>
|
||||
<cluster name="src" location=".\src\" recursive="true"/>
|
||||
</target>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all">
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="ewsgi_spec" location="..\..\ewsgi_specification-safe.ecf" readonly="false"/>
|
||||
<library name="ewsgi" location="..\..\ewsgi-safe.ecf" readonly="false"/>
|
||||
<library name="libfcgi" location="..\..\..\libfcgi\libfcgi-safe.ecf" />
|
||||
<library name="http" location="..\..\..\..\protocol\http\http-safe.ecf"/>
|
||||
<cluster name="src" location=".\" recursive="true"/>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<option warning="true" full_class_checking="true">
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||
<library name="ewsgi_spec" location="..\..\ewsgi_specification.ecf" readonly="false"/>
|
||||
<library name="ewsgi" location="..\..\ewsgi.ecf" readonly="false"/>
|
||||
<library name="libfcgi" location="..\..\..\libfcgi\libfcgi.ecf" />
|
||||
<library name="http" location="..\..\..\..\protocol\http\http.ecf"/>
|
||||
<cluster name="src" location=".\" recursive="true"/>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all">
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="ewsgi_spec" location="..\..\ewsgi_specification-safe.ecf" readonly="false"/>
|
||||
<library name="ewsgi" location="..\..\ewsgi-safe.ecf" readonly="false"/>
|
||||
<library name="http" location="..\..\..\..\protocol\http\http-safe.ecf"/>
|
||||
<library name="nino" location="..\..\..\..\..\ext\server\nino\nino-safe.ecf" readonly="false">
|
||||
<renaming old_name="HTTP_CONSTANTS" new_name="NINO_HTTP_CONSTANTS"/>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<option warning="true" full_class_checking="true">
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||
<library name="ewsgi_spec" location="..\..\ewsgi_specification.ecf" readonly="false"/>
|
||||
<library name="ewsgi" location="..\..\ewsgi.ecf" readonly="false"/>
|
||||
<library name="http" location="..\..\..\..\protocol\http\http.ecf"/>
|
||||
<library name="nino" location="..\..\..\..\..\ext\server\nino\nino.ecf" readonly="false">
|
||||
<renaming old_name="HTTP_CONSTANTS" new_name="NINO_HTTP_CONSTANTS"/>
|
||||
|
||||
@@ -7,7 +7,7 @@ deferred class
|
||||
DEFAULT_EWSGI_APPLICATION
|
||||
|
||||
inherit
|
||||
GW_APPLICATION_IMP
|
||||
EWSGI_APPLICATION
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
|
||||
<library name="ewsgi_spec" location="../ewsgi_specification-safe.ecf"/>
|
||||
<library name="ewsgi" location="../ewsgi-safe.ecf"/>
|
||||
<library name="connector_cgi" location="../connectors/cgi/cgi-safe.ecf"/>
|
||||
<library name="error" location="..\..\..\error\error-safe.ecf"/>
|
||||
|
||||
21
library/server/ewsgi/default/ewsgi_cgi.ecf
Normal file
21
library/server/ewsgi/default/ewsgi_cgi.ecf
Normal file
@@ -0,0 +1,21 @@
|
||||
<?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="ewsgi_cgi" uuid="82D0E5BA-3EBD-4E0F-94D1-776375158DAA" library_target="ewsgi_cgi">
|
||||
<target name="ewsgi_cgi">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
<exclude>/\.git$</exclude>
|
||||
<exclude>/\.svn$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" full_class_checking="true" syntax="provisional">
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||
<library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/>
|
||||
<library name="ewsgi" location="../ewsgi.ecf"/>
|
||||
<library name="connector_cgi" location="../connectors/cgi/cgi.ecf"/>
|
||||
<library name="error" location="..\..\..\error\error.ecf"/>
|
||||
<library name="http" location="..\..\..\protocol\http\http.ecf"/>
|
||||
<library name="encoder" location="..\..\..\text\encoder\encoder.ecf" readonly="false"/>
|
||||
<cluster name="default_cgi" location="./cgi" recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
@@ -11,7 +11,6 @@
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
|
||||
<library name="ewsgi_spec" location="../ewsgi_specification-safe.ecf"/>
|
||||
<library name="ewsgi" location="../ewsgi-safe.ecf"/>
|
||||
<library name="connector_nino" location="../connectors/nino/nino-safe.ecf"/>
|
||||
<library name="nino" location="..\..\..\..\ext\server\nino\nino-safe.ecf" readonly="false">
|
||||
|
||||
25
library/server/ewsgi/default/ewsgi_nino.ecf
Normal file
25
library/server/ewsgi/default/ewsgi_nino.ecf
Normal file
@@ -0,0 +1,25 @@
|
||||
<?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="ewsgi_nino" uuid="11D70618-3D82-4C5B-9501-8833DD04A3D6" library_target="ewsgi_nino">
|
||||
<target name="ewsgi_nino">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
<exclude>/\.git$</exclude>
|
||||
<exclude>/\.svn$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" full_class_checking="true" syntax="provisional">
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||
<library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/>
|
||||
<library name="ewsgi" location="../ewsgi.ecf"/>
|
||||
<library name="connector_nino" location="../connectors/nino/nino.ecf"/>
|
||||
<library name="nino" location="..\..\..\..\ext\server\nino\nino.ecf" readonly="false">
|
||||
<renaming old_name="HTTP_CONSTANTS" new_name="NINO_HTTP_CONSTANTS"/>
|
||||
</library>
|
||||
|
||||
<library name="error" location="..\..\..\error\error.ecf"/>
|
||||
<library name="http" location="..\..\..\protocol\http\http.ecf"/>
|
||||
<library name="encoder" location="..\..\..\text\encoder\encoder.ecf" readonly="false"/>
|
||||
<cluster name="default_nino" location="./nino" recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
@@ -7,18 +7,21 @@ deferred class
|
||||
DEFAULT_EWSGI_APPLICATION
|
||||
|
||||
inherit
|
||||
GW_APPLICATION_IMP
|
||||
EWSGI_APPLICATION
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make_and_launch
|
||||
do
|
||||
print ("Example: start a Nino web server on port " + port_number.out + ", %Nand reply Hello World for any request such as http://localhost:8123/%N")
|
||||
port_number := 80
|
||||
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 {NINO_APPLICATION}.make_custom (agent execute, "")).listen (port_number)
|
||||
end
|
||||
|
||||
port_number: INTEGER = 80
|
||||
port_number: INTEGER
|
||||
|
||||
invariant
|
||||
port_number_valid: port_number > 0
|
||||
note
|
||||
copyright: "2011-2011, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
|
||||
@@ -12,16 +12,16 @@ create
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
make (a_callback: like {GW_AGENT_APPLICATION}.callback)
|
||||
make (a_callback: like {EWSGI_AGENT_APPLICATION}.callback)
|
||||
-- Initialize `Current'.
|
||||
do
|
||||
make_custom (a_callback, Void)
|
||||
end
|
||||
|
||||
make_custom (a_callback: like {GW_AGENT_APPLICATION}.callback; a_base_url: detachable STRING)
|
||||
make_custom (a_callback: like {EWSGI_AGENT_APPLICATION}.callback; a_base_url: detachable STRING)
|
||||
-- Initialize `Current'.
|
||||
local
|
||||
app: GW_AGENT_APPLICATION
|
||||
app: EWSGI_AGENT_APPLICATION
|
||||
do
|
||||
create app.make (a_callback)
|
||||
create connector.make_with_base (app, a_base_url)
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
<?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="ewsgi-full" uuid="D924DBE1-1231-434A-80EF-234BA09D1E30" library_target="ewsgi-full">
|
||||
<target name="ewsgi-full">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
<exclude>/\.git$</exclude>
|
||||
<exclude>/\.svn$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" full_class_checking="true" is_attached_by_default="false" void_safety="none" syntax="provisional">
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||
<library name="ewsgi_spec" location="ewsgi_specification.ecf"/>
|
||||
<library name="error" location="..\..\error\error.ecf"/>
|
||||
<library name="http" location="..\..\protocol\http\http.ecf"/>
|
||||
<library name="encoder" location="..\..\text\encoder\encoder.ecf" readonly="false"/>
|
||||
<library name="libfcgi" location="..\libfcgi\libfcgi.ecf"/>
|
||||
<library name="nino" location="..\..\..\ext\server\nino\nino.ecf" readonly="false">
|
||||
<renaming old_name="HTTP_CONSTANTS" new_name="NINO_HTTP_CONSTANTS"/>
|
||||
</library>
|
||||
<library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/>
|
||||
<cluster name="connectors" location="connectors\" recursive="true"/>
|
||||
<cluster name="interface" location="src\" recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
@@ -11,7 +11,6 @@
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
|
||||
<library name="ewsgi_spec" location="ewsgi_specification-safe.ecf"/>
|
||||
<library name="error" location="..\..\error\error-safe.ecf"/>
|
||||
<library name="http" location="..\..\protocol\http\http-safe.ecf"/>
|
||||
<library name="encoder" location="..\..\text\encoder\encoder-safe.ecf" readonly="false"/>
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||
<library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/>
|
||||
<library name="ewsgi_spec" location="ewsgi_specification.ecf"/>
|
||||
<library name="error" location="..\..\error\error.ecf"/>
|
||||
<library name="http" location="..\..\protocol\http\http.ecf"/>
|
||||
<library name="encoder" location="..\..\text\encoder\encoder.ecf" readonly="false"/>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?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="ewsgi_spec" uuid="D6455232-E709-43B3-A2C7-D3E6F6A98288" library_target="ewsgi_spec">
|
||||
<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="ewsgi_spec" uuid="AA193B9F-02FD-47B9-B60D-C42B9AB35E1C" library_target="ewsgi_spec">
|
||||
<target name="ewsgi_spec">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
@@ -1,5 +1,5 @@
|
||||
<?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="ewsgi_spec" uuid="D6455232-E709-43B3-A2C7-D3E6F6A98288" library_target="ewsgi_spec">
|
||||
<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="ewsgi_spec" uuid="AA193B9F-02FD-47B9-B60D-C42B9AB35E1C" library_target="ewsgi_spec">
|
||||
<target name="ewsgi_spec">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
@@ -13,7 +13,6 @@
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="default_nino" location="..\..\default\ewsgi_nino-safe.ecf" readonly="false"/>
|
||||
<library name="connector_nino" location="..\..\connectors\nino\nino-safe.ecf" readonly="false"/>
|
||||
<library name="ewsgi_spec" location="..\..\ewsgi_specification-safe.ecf" readonly="false"/>
|
||||
<library name="ewsgi" location="..\..\ewsgi-safe.ecf" readonly="false"/>
|
||||
<cluster name="src" location="src\" recursive="true"/>
|
||||
</target>
|
||||
|
||||
19
library/server/ewsgi/examples/hello_world/hello.ecf
Normal file
19
library/server/ewsgi/examples/hello_world/hello.ecf
Normal file
@@ -0,0 +1,19 @@
|
||||
<?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_world" uuid="734385F1-0D17-4B5F-9138-24DC8D4F06C6">
|
||||
<target name="hello_world">
|
||||
<root class="HELLO_WORLD" feature="make"/>
|
||||
<file_rule>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
<exclude>/\.git$</exclude>
|
||||
<exclude>/\.svn$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" full_class_checking="true" syntax="provisional">
|
||||
</option>
|
||||
<setting name="concurrency" value="thread"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||
<library name="default_nino" location="..\..\default\ewsgi_nino.ecf" readonly="false"/>
|
||||
<library name="connector_nino" location="..\..\connectors\nino\nino.ecf" readonly="false"/>
|
||||
<library name="ewsgi" location="..\..\ewsgi.ecf" readonly="false"/>
|
||||
<cluster name="src" location="src\" recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
@@ -18,7 +18,7 @@ feature {NONE} -- Initialization
|
||||
(create {NINO_APPLICATION}.make_custom (agent execute, "")).listen (port_number)
|
||||
end
|
||||
|
||||
execute (req: EWSGI_REQUEST; res: EWSGI_RESPONSE_STREAM)
|
||||
execute (req: EWSGI_REQUEST; res: EWSGI_RESPONSE_BUFFER)
|
||||
do
|
||||
res.write_header (200, <<["Content-Type", "text/plain"]>>)
|
||||
res.write_string ("Hello World!%N")
|
||||
|
||||
@@ -7,23 +7,22 @@
|
||||
<exclude>/\.svn$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="provisional">
|
||||
<assertions precondition="true" postcondition="true" invariant="true" supplier_precondition="true"/>
|
||||
</option>
|
||||
<setting name="concurrency" value="thread"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="ewsgi_spec" location="..\..\ewsgi_specification-safe.ecf" readonly="false"/>
|
||||
<library name="ewsgi" location="..\..\ewsgi-safe.ecf" readonly="false"/>
|
||||
</target>
|
||||
<target name="hello_nino_world" extends="hello_world">
|
||||
<root class="HELLO_WORLD" feature="make_and_launch"/>
|
||||
<library name="default_nino" location="..\..\default\ewsgi_nino-safe.ecf" readonly="false"/>
|
||||
<library name="connector_nino" location="..\..\connectors\nino\nino-safe.ecf" readonly="false"/>
|
||||
<library name="default_nino" location="..\..\default\ewsgi_nino-safe.ecf" readonly="false"/>
|
||||
<cluster name="src" location="src\" recursive="true"/>
|
||||
</target>
|
||||
<target name="hello_cgi_world" extends="hello_world">
|
||||
<root class="HELLO_WORLD" feature="make_and_launch"/>
|
||||
<library name="default_cgi" location="..\..\default\ewsgi_cgi-safe.ecf" readonly="false"/>
|
||||
<library name="connector_cgi" location="..\..\connectors\cgi\cgi-safe.ecf" readonly="false"/>
|
||||
<library name="default_cgi" location="..\..\default\ewsgi_cgi-safe.ecf" readonly="false"/>
|
||||
<cluster name="src" location="src\" recursive="true"/>
|
||||
</target>
|
||||
|
||||
</system>
|
||||
|
||||
@@ -19,7 +19,19 @@ feature -- Response
|
||||
|
||||
response (request: EWSGI_REQUEST): EWSGI_RESPONSE
|
||||
do
|
||||
create {HELLO_WORLD_RESPONSE} Result.make
|
||||
if request.environment.path_info.starts_with ("/streaming/") then
|
||||
Result := streaming_response (request)
|
||||
else
|
||||
create Result.make
|
||||
Result.set_status (200)
|
||||
Result.set_header ("Content-Type", "text/html; charset=utf-8")
|
||||
Result.set_message_body ("<html><body>Hello World</body></html>")
|
||||
end
|
||||
end
|
||||
|
||||
streaming_response (request: EWSGI_REQUEST): EWSGI_RESPONSE
|
||||
do
|
||||
create {HELLO_WORLD_RESPONSE} Result.make
|
||||
Result.set_status (200)
|
||||
Result.set_header ("Content-Type", "text/html; charset=utf-8")
|
||||
end
|
||||
|
||||
@@ -31,23 +31,26 @@ feature {NONE} -- Entity body
|
||||
local
|
||||
i: INTEGER
|
||||
do
|
||||
if current_hello >= 100000 then
|
||||
if current_hello >= 10000 then
|
||||
end_of_blocks := True
|
||||
else
|
||||
if current_hello = 0 then
|
||||
current_block := "<html><body>%N"
|
||||
current_block := "<html><style>div#status {position: absolute; top: 30%%; left: 40%%; border: red solid 1px; padding: 10px; background-color: #ffcccc;}</style><body>%N"
|
||||
current_block.append ("<a name=%"top%">Welcome</a><br/><div id=%"status%">In progress</div>")
|
||||
end
|
||||
from
|
||||
i := 0
|
||||
until
|
||||
i = 10000
|
||||
i = 1000
|
||||
loop
|
||||
current_block.append ("Hello World ("+ current_hello.out +","+ i.out +")<br/>%N")
|
||||
i := i + 1
|
||||
end
|
||||
current_hello := current_hello + i
|
||||
if current_hello = 100000 then
|
||||
current_block.append ("Bye bye..<br/></body></html>")
|
||||
current_block.append ("<div id=%"status%">In progress - "+ (100 * current_hello // 10000).out +"%%</div>")
|
||||
if current_hello = 10000 then
|
||||
current_block.append ("<a name=%"bottom%">Bye bye..</a><br/><div id=%"status%">Completed - GO TO <a href=%"#bottom%">BOTTOM</a></div></body></html>")
|
||||
end_of_blocks := True
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
note
|
||||
description: "Summary description for {EWSGI_AGENT_APPLICATION}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
EWSGI_AGENT_APPLICATION
|
||||
|
||||
inherit
|
||||
EWSGI_APPLICATION
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
make (a_callback: like callback; a_request_creator: like request_creator; a_response_creator: like response_creator)
|
||||
-- Initialize `Current'.
|
||||
do
|
||||
callback := a_callback
|
||||
request_creator := a_request_creator
|
||||
response_creator := a_response_creator
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
request_creator: FUNCTION [ANY, TUPLE [env: EWSGI_ENVIRONMENT; input: EWSGI_INPUT_STREAM], EWSGI_REQUEST]
|
||||
|
||||
response_creator: FUNCTION [ANY, TUPLE [req: EWSGI_REQUEST; output: EWSGI_OUTPUT_STREAM], EWSGI_RESPONSE_STREAM]
|
||||
|
||||
callback: PROCEDURE [ANY, TUPLE [req: like new_request; res: like new_response]]
|
||||
-- Procedure called on `execute'
|
||||
|
||||
execute (req: like new_request; res: like new_response)
|
||||
-- Execute the request
|
||||
do
|
||||
callback.call ([req, res])
|
||||
end
|
||||
|
||||
feature -- Factory
|
||||
|
||||
new_request (env: EWSGI_ENVIRONMENT; a_input: EWSGI_INPUT_STREAM): EWSGI_REQUEST
|
||||
do
|
||||
Result := request_creator.item ([env, a_input])
|
||||
end
|
||||
|
||||
new_response (req: EWSGI_REQUEST; a_output: EWSGI_OUTPUT_STREAM): EWSGI_RESPONSE_STREAM
|
||||
do
|
||||
Result := response_creator.item ([req, a_output])
|
||||
end
|
||||
|
||||
invariant
|
||||
callback_attached: callback /= Void
|
||||
|
||||
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
|
||||
@@ -8,73 +8,19 @@ note
|
||||
deferred class
|
||||
EWSGI_APPLICATION
|
||||
|
||||
feature -- Process request
|
||||
|
||||
process (env: EWSGI_ENVIRONMENT; a_input: EWSGI_INPUT_STREAM; a_output: EWSGI_OUTPUT_STREAM)
|
||||
-- Process request with environment `env', and i/o streams `a_input' and `a_output'
|
||||
local
|
||||
rescued: BOOLEAN
|
||||
req: detachable like new_request
|
||||
res: detachable like new_response
|
||||
do
|
||||
if not rescued then
|
||||
pre_execute (env)
|
||||
req := new_request (env, a_input)
|
||||
res := new_response (req, a_output)
|
||||
execute (req, res)
|
||||
post_execute (req, res)
|
||||
else
|
||||
rescue_execute (req, res, (create {EXCEPTION_MANAGER}).last_exception)
|
||||
end
|
||||
if res /= Void then
|
||||
res.commit (a_output)
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Execution
|
||||
|
||||
execute (req: EWSGI_REQUEST; res: EWSGI_RESPONSE_STREAM)
|
||||
execute (req: EWSGI_REQUEST; res: EWSGI_RESPONSE_BUFFER)
|
||||
-- Execute the request
|
||||
-- See `req.input' for input stream
|
||||
-- `req.environment' for the Gateway environment
|
||||
-- and `res.output' for output stream
|
||||
deferred
|
||||
end
|
||||
|
||||
pre_execute (env: EWSGI_ENVIRONMENT)
|
||||
-- Operation processed before `execute'
|
||||
-- and `res' for the output buffer
|
||||
require
|
||||
env_attached: env /= Void
|
||||
do
|
||||
end
|
||||
|
||||
post_execute (req: detachable EWSGI_REQUEST; res: detachable EWSGI_RESPONSE_STREAM)
|
||||
-- Operation processed after `execute', or after `rescue_execute'
|
||||
do
|
||||
end
|
||||
|
||||
rescue_execute (req: detachable EWSGI_REQUEST; res: detachable EWSGI_RESPONSE_STREAM; a_exception: detachable EXCEPTION)
|
||||
-- Operation processed on rescue of `execute'
|
||||
do
|
||||
post_execute (req, res)
|
||||
end
|
||||
|
||||
feature -- Factory
|
||||
|
||||
new_request (env: EWSGI_ENVIRONMENT; a_input: EWSGI_INPUT_STREAM): EWSGI_REQUEST
|
||||
-- New Request context based on `env' and `a_input'
|
||||
--| note: you can redefine this function to create your own
|
||||
--| descendant of EWSGI_REQUEST , or even to reuse/recycle existing
|
||||
--| instance of EWSGI_REQUEST
|
||||
deferred
|
||||
end
|
||||
|
||||
new_response (req: EWSGI_REQUEST; a_output: EWSGI_OUTPUT_STREAM): EWSGI_RESPONSE_STREAM
|
||||
-- New Response based on `req' and `a_output'
|
||||
--| note: you can redefine this function to create your own
|
||||
--| descendant of EWSGI_RESPONSE_STREAM , or even to reuse/recycle existing
|
||||
--| instance of EWSGI_RESPONSE_STREAM
|
||||
res_status_unset: not res.status_is_set
|
||||
deferred
|
||||
ensure
|
||||
res_status_set: res.status_is_set
|
||||
res_committed: res.message_committed
|
||||
end
|
||||
|
||||
note
|
||||
|
||||
@@ -4,85 +4,66 @@ note
|
||||
Interface for a request environment
|
||||
It includes CGI interface and a few extra values that are usually valuable
|
||||
|
||||
See http://ken.coar.org/cgi/draft-coar-cgi-v11-03.txt
|
||||
See http://www.ietf.org/rfc/rfc3875
|
||||
|
||||
2.2. Basic Rules
|
||||
|
||||
The following rules are used throughout this specification to
|
||||
describe basic parsing constructs.
|
||||
|
||||
alpha = lowalpha | hialpha
|
||||
alphanum = alpha | digit
|
||||
lowalpha = a | b | c | d | e | f | g | h
|
||||
| i | j | k | l | m | n | o | p
|
||||
| q | r | s | t | u | v | w | x
|
||||
| y | z
|
||||
hialpha = A | B | C | D | E | F | G | H
|
||||
| I | J | K | L | M | N | O | P
|
||||
| Q | R | S | T | U | V | W | X
|
||||
| Y | Z
|
||||
digit = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7
|
||||
| 8 | 9
|
||||
hex = digit | A | B | C | D | E | F | a
|
||||
| b | c | d | e | f
|
||||
escaped = % hex hex
|
||||
OCTET = <any 8-bit sequence of data>
|
||||
CHAR = <any US-ASCII character (octets 0 - 127)>
|
||||
CTL = <any US-ASCII control character
|
||||
(octets 0 - 31) and DEL (127)>
|
||||
CR = <US-ASCII CR, carriage return (13)>
|
||||
LF = <US-ASCII LF, linefeed (10)>
|
||||
SP = <US-ASCII SP, space (32)>
|
||||
HT = <US-ASCII HT, horizontal tab (9)>
|
||||
NL = CR | LF
|
||||
LWSP = SP | HT | NL
|
||||
tspecial = ( | ) | "@" | , | ; | : | \ | "
|
||||
| / | [ | ] | ? | < | > | { | }
|
||||
| SP | HT | NL
|
||||
token = 1*<any CHAR except CTLs or tspecials>
|
||||
quoted-string = ( " *qdtext " ) | ( "<" *qatext ">")
|
||||
qdtext = <any CHAR except %" and CTLs but including LWSP>
|
||||
qatext = <any CHAR except "<", ">" and CTLs but including LWSP>
|
||||
mark = - | _ | . | ! | ~ | * | ' | ( | )
|
||||
unreserved = alphanum | mark
|
||||
reserved = ; | / | ? | : | @ | & | = | $ | ,
|
||||
uric = reserved | unreserved | escaped
|
||||
|
||||
alpha = lowalpha | hialpha
|
||||
lowalpha = a | b | c | d | e | f | g | h |
|
||||
i | j | k | l | m | n | o | p |
|
||||
q | r | s | t | u | v | w | x |
|
||||
y | z
|
||||
hialpha = A | B | C | D | E | F | G | H |
|
||||
I | J | K | L | M | N | O | P |
|
||||
Q | R | S | T | U | V | W | X |
|
||||
Y | Z
|
||||
digit = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
|
||||
8 | 9
|
||||
alphanum = alpha | digit
|
||||
OCTET = <any 8-bit byte>
|
||||
CHAR = alpha | digit | separator | ! | # | $ |
|
||||
%% | & | ' | * | + | - | . | ` |
|
||||
^ | _ | { | | | } | ~ | CTL
|
||||
CTL = <any control character>
|
||||
SP = <space character>
|
||||
HT = <horizontal tab character>
|
||||
NL = <newline>
|
||||
LWSP = SP | HT | NL
|
||||
separator = ( | ) | < | > | @ | , | ; | : |
|
||||
\ | " | / | [ | ] | ? | = | { |
|
||||
} | SP | HT
|
||||
token = 1*<any CHAR except CTLs or separators>
|
||||
quoted-string = " *qdtext "
|
||||
qdtext = <any CHAR except " and CTLs but including LWSP>
|
||||
TEXT = <any printable character>
|
||||
|
||||
2.3. URL Encoding
|
||||
|
||||
reserved = ; | / | ? | : | @ | & | = | + | $ |
|
||||
, | [ | ]
|
||||
|
||||
hex = digit | A | B | C | D | E | F | a | b
|
||||
| c | d | e | f
|
||||
escaped = "%%" hex hex
|
||||
unreserved = alpha | digit | mark
|
||||
mark = - | _ | . | ! | ~ | * | ' | ( | )
|
||||
|
||||
Note that newline (NL) need not be a single character, but can
|
||||
be a character sequence.
|
||||
|
||||
3.2. The Script-URI
|
||||
|
||||
The 'Script-URI' is defined as the URI of the resource
|
||||
identified by the metavariables. Often, this URI will be the
|
||||
same as the URI requested by the client (the 'Client-URI');
|
||||
however, it need not be. Instead, it could be a URI invented
|
||||
by the server, and so it can only be used in the context of
|
||||
the server and its CGI interface.
|
||||
|
||||
The Script-URI has the syntax of generic-RL as defined in
|
||||
section 2.1 of RFC 1808 [7], with the exception that object
|
||||
parameters and fragment identifiers are not permitted:
|
||||
|
||||
<scheme>://<host><port>/<path>?<query>
|
||||
script-URI = <scheme> "://" <server-name> ":" <server-port>
|
||||
<script-path> <extra-path> "?" <query-string>
|
||||
|
||||
The various components of the Script-URI are defined by some
|
||||
of the metavariables (see section 4 below);
|
||||
|
||||
script-uri = protocol "://" SERVER_NAME ":" SERVER_PORT enc-script
|
||||
enc-path-info "?" QUERY_STRING
|
||||
where <scheme> is found from SERVER_PROTOCOL, <server-name>,
|
||||
<server-port> and <query-string> are the values of the respective
|
||||
meta-variables. The SCRIPT_NAME and PATH_INFO values, URL-encoded
|
||||
with ";", "=" and "?" reserved, give <script-path> and <extra-path>.
|
||||
|
||||
where 'protocol' is obtained from SERVER_PROTOCOL,
|
||||
'enc-script' is a URL-encoded version of SCRIPT_NAME and
|
||||
'enc-path-info' is a URL-encoded version of PATH_INFO. See
|
||||
section 4.6 for more information about the PATH_INFO
|
||||
metavariable.
|
||||
|
||||
Note that the scheme and the protocol are not identical; for
|
||||
instance, a resource accessed via an SSL mechanism may have a
|
||||
Client-URI with a scheme of "https" rather than "http".
|
||||
CGI/1.1 provides no means for the script to reconstruct this,
|
||||
and therefore the Script-URI includes the base protocol used.
|
||||
]"
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
@@ -518,6 +499,12 @@ feature -- Common Gateway Interface - 1.1 8 January 1996
|
||||
|
||||
feature -- HTTP_*
|
||||
|
||||
http_accept: detachable STRING
|
||||
-- Contents of the Accept: header from the current request, if there is one.
|
||||
-- Example: 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
|
||||
deferred
|
||||
end
|
||||
|
||||
http_accept_charset: detachable STRING
|
||||
-- Contents of the Accept-Charset: header from the current request, if there is one.
|
||||
-- Example: 'iso-8859-1,*,utf-8'.
|
||||
|
||||
@@ -4,8 +4,6 @@ note
|
||||
|
||||
You can create your own descendant of this class to
|
||||
add/remove specific value or processing
|
||||
|
||||
This object is created by {GW_APPLICATION}.new_request_context
|
||||
]"
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
|
||||
@@ -1,19 +1,38 @@
|
||||
note
|
||||
description: "Summary description for {EWSGI_RESPONSE_STREAM}."
|
||||
description: "Summary description for {EWSGI_RESPONSE_BUFFER}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
EWSGI_RESPONSE_STREAM
|
||||
EWSGI_RESPONSE_BUFFER
|
||||
|
||||
feature {EWSGI_APPLICATION} -- Commit
|
||||
|
||||
commit (a_output_stream: EWSGI_OUTPUT_STREAM)
|
||||
commit
|
||||
-- Commit the current response
|
||||
deferred
|
||||
ensure
|
||||
status_set: is_status_set
|
||||
status_is_set: status_is_set
|
||||
header_committed: header_committed
|
||||
message_committed: message_committed
|
||||
end
|
||||
|
||||
feature -- Status report
|
||||
|
||||
header_committed: BOOLEAN
|
||||
-- Header committed?
|
||||
deferred
|
||||
end
|
||||
|
||||
message_committed: BOOLEAN
|
||||
-- Message committed?
|
||||
deferred
|
||||
end
|
||||
|
||||
message_writable: BOOLEAN
|
||||
-- Can message be written?
|
||||
deferred
|
||||
end
|
||||
|
||||
feature {NONE} -- Core output operation
|
||||
@@ -26,7 +45,7 @@ feature {NONE} -- Core output operation
|
||||
|
||||
feature -- Status setting
|
||||
|
||||
is_status_set: BOOLEAN
|
||||
status_is_set: BOOLEAN
|
||||
-- Is status set?
|
||||
deferred
|
||||
end
|
||||
@@ -35,11 +54,12 @@ feature -- Status setting
|
||||
-- Set response status code
|
||||
-- Should be done before sending any data back to the client
|
||||
require
|
||||
status_not_set: not is_status_set
|
||||
status_not_set: not status_is_set
|
||||
header_not_committed: not header_committed
|
||||
deferred
|
||||
ensure
|
||||
status_code_set: status_code = a_code
|
||||
status_set: is_status_set
|
||||
status_set: status_is_set
|
||||
end
|
||||
|
||||
status_code: INTEGER
|
||||
@@ -47,33 +67,57 @@ feature -- Status setting
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Header output operation
|
||||
|
||||
write_headers_string (a_headers: STRING)
|
||||
require
|
||||
status_set: status_is_set
|
||||
header_not_committed: not header_committed
|
||||
deferred
|
||||
ensure
|
||||
status_set: status_is_set
|
||||
header_committed: header_committed
|
||||
end
|
||||
|
||||
write_header (a_status_code: INTEGER; a_headers: detachable ARRAY [TUPLE [key: STRING; value: STRING]])
|
||||
-- Send headers with status `a_status', and headers from `a_headers'
|
||||
require
|
||||
status_not_set: not status_is_set
|
||||
header_not_committed: not header_committed
|
||||
deferred
|
||||
ensure
|
||||
header_committed: header_committed
|
||||
status_set: status_is_set
|
||||
end
|
||||
|
||||
feature -- Output operation
|
||||
|
||||
write_string (s: STRING)
|
||||
-- Send the string `s'
|
||||
require
|
||||
status_set: is_status_set
|
||||
message_writable: message_writable
|
||||
deferred
|
||||
end
|
||||
|
||||
write_substring (s: STRING; a_begin_index, a_end_index: INTEGER)
|
||||
-- Send the substring `s[a_begin_index:a_end_index]'
|
||||
require
|
||||
message_writable: message_writable
|
||||
deferred
|
||||
end
|
||||
|
||||
write_file_content (fn: STRING)
|
||||
-- Send the content of file `fn'
|
||||
require
|
||||
status_set: is_status_set
|
||||
message_writable: message_writable
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Header output operation
|
||||
|
||||
write_header (a_status_code: INTEGER; a_headers: detachable ARRAY [TUPLE [key: STRING; value: STRING]])
|
||||
-- Send headers with status `a_status', and headers from `a_headers'
|
||||
require
|
||||
status_not_set: not is_status_set
|
||||
flush
|
||||
-- Flush if it makes sense
|
||||
deferred
|
||||
ensure
|
||||
status_set: is_status_set
|
||||
end
|
||||
|
||||
|
||||
note
|
||||
copyright: "2011-2011, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
@@ -5,10 +5,10 @@ note
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
GW_AGENT_APPLICATION
|
||||
EWSGI_AGENT_APPLICATION
|
||||
|
||||
inherit
|
||||
GW_APPLICATION_IMP
|
||||
EWSGI_APPLICATION
|
||||
|
||||
create
|
||||
make
|
||||
109
library/server/ewsgi/src/application/ewsgi_application.e
Normal file
109
library/server/ewsgi/src/application/ewsgi_application.e
Normal file
@@ -0,0 +1,109 @@
|
||||
note
|
||||
description: "[
|
||||
EWSGI_APPLICATION
|
||||
]"
|
||||
specification: "EWSGI specification https://github.com/Eiffel-World/Eiffel-Web-Framework/wiki/EWSGI-specification"
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
EWSGI_APPLICATION
|
||||
|
||||
feature {NONE} -- Execution
|
||||
|
||||
execute (req: EWSGI_REQUEST; res: EWSGI_RESPONSE_BUFFER)
|
||||
-- Execute the request
|
||||
-- See `req.input' for input stream
|
||||
-- `req.environment' for the Gateway environment
|
||||
-- and `res' for output buffer
|
||||
require
|
||||
res_status_unset: not res.status_is_set
|
||||
deferred
|
||||
ensure
|
||||
res_status_set: res.status_is_set
|
||||
res_committed: res.message_committed
|
||||
end
|
||||
|
||||
feature -- Process request
|
||||
|
||||
process (env: EWSGI_ENVIRONMENT; a_input: EWSGI_INPUT_STREAM; a_output: EWSGI_OUTPUT_STREAM)
|
||||
-- Process request with environment `env', and i/o streams `a_input' and `a_output'
|
||||
local
|
||||
rescued: BOOLEAN
|
||||
req: detachable like new_request
|
||||
res: detachable like new_response
|
||||
do
|
||||
if not rescued then
|
||||
request_count := request_count + 1
|
||||
pre_execute (env)
|
||||
req := new_request (env, a_input)
|
||||
res := new_response (req, a_output)
|
||||
execute (req, res)
|
||||
post_execute (req, res)
|
||||
else
|
||||
rescue_execute (req, res, (create {EXCEPTION_MANAGER}).last_exception)
|
||||
end
|
||||
if res /= Void then
|
||||
res.commit
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
request_count: INTEGER
|
||||
-- Request count
|
||||
|
||||
feature {NONE} -- Execution
|
||||
|
||||
pre_execute (env: EWSGI_ENVIRONMENT)
|
||||
-- Operation processed before `execute'
|
||||
require
|
||||
env_attached: env /= Void
|
||||
do
|
||||
end
|
||||
|
||||
post_execute (req: detachable EWSGI_REQUEST; res: detachable EWSGI_RESPONSE_BUFFER)
|
||||
-- Operation processed after `execute', or after `rescue_execute'
|
||||
do
|
||||
end
|
||||
|
||||
rescue_execute (req: detachable EWSGI_REQUEST; res: detachable EWSGI_RESPONSE_BUFFER; a_exception: detachable EXCEPTION)
|
||||
-- Operation processed on rescue of `execute'
|
||||
do
|
||||
if
|
||||
req /= Void and res /= Void
|
||||
and a_exception /= Void and then attached a_exception.exception_trace as l_trace
|
||||
then
|
||||
res.write_header ({HTTP_STATUS_CODE}.internal_server_error, Void)
|
||||
res.write_string ("<pre>" + l_trace + "</pre>")
|
||||
end
|
||||
post_execute (req, res)
|
||||
end
|
||||
|
||||
feature {NONE} -- Factory
|
||||
|
||||
new_request (env: EWSGI_ENVIRONMENT; a_input: EWSGI_INPUT_STREAM): EWSGI_REQUEST
|
||||
do
|
||||
create {EWSGI_REQUEST} Result.make (env, a_input)
|
||||
Result.environment.set_variable (request_count.out, "REQUEST_COUNT")
|
||||
end
|
||||
|
||||
new_response (req: EWSGI_REQUEST; a_output: EWSGI_OUTPUT_STREAM): EWSGI_RESPONSE_BUFFER
|
||||
do
|
||||
create {EWSGI_RESPONSE_BUFFER} Result.make (a_output)
|
||||
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
|
||||
@@ -1,69 +0,0 @@
|
||||
note
|
||||
description: "Summary description for {GW_APPLICATION_IMP} "
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
GW_APPLICATION_IMP
|
||||
|
||||
inherit
|
||||
EWSGI_APPLICATION
|
||||
redefine
|
||||
process,
|
||||
rescue_execute
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
request_count: INTEGER
|
||||
-- Request count
|
||||
|
||||
feature -- Execution
|
||||
|
||||
process (env: EWSGI_ENVIRONMENT; a_input: EWSGI_INPUT_STREAM; a_output: EWSGI_OUTPUT_STREAM)
|
||||
-- Process request with environment `env', and i/o streams `a_input' and `a_output'
|
||||
do
|
||||
request_count := request_count + 1
|
||||
Precursor (env, a_input, a_output)
|
||||
end
|
||||
|
||||
rescue_execute (req: detachable EWSGI_REQUEST; res: detachable EWSGI_RESPONSE_STREAM; a_exception: detachable EXCEPTION)
|
||||
-- Operation processed on rescue of `execute'
|
||||
do
|
||||
if
|
||||
req /= Void and res /= Void
|
||||
and a_exception /= Void and then attached a_exception.exception_trace as l_trace
|
||||
then
|
||||
res.write_header ({HTTP_STATUS_CODE}.internal_server_error, Void)
|
||||
res.write_string ("<pre>" + l_trace + "</pre>")
|
||||
end
|
||||
Precursor (req, res, a_exception)
|
||||
end
|
||||
|
||||
feature -- Factory
|
||||
|
||||
new_request (env: EWSGI_ENVIRONMENT; a_input: EWSGI_INPUT_STREAM): EWSGI_REQUEST
|
||||
do
|
||||
create {GW_REQUEST_IMP} Result.make (env, a_input)
|
||||
Result.execution_variables.set_variable (request_count.out, "REQUEST_COUNT")
|
||||
end
|
||||
|
||||
new_response (req: EWSGI_REQUEST; a_output: EWSGI_OUTPUT_STREAM): EWSGI_RESPONSE_STREAM
|
||||
do
|
||||
create {GW_RESPONSE_STREAM_IMP} Result.make (a_output)
|
||||
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
|
||||
44
library/server/ewsgi/src/connector/ewsgi_connector.e
Normal file
44
library/server/ewsgi/src/connector/ewsgi_connector.e
Normal file
@@ -0,0 +1,44 @@
|
||||
note
|
||||
description: "Summary description for {EWSGI_CONNECTOR}."
|
||||
specification: "EWSGI/connector specification https://github.com/Eiffel-World/Eiffel-Web-Framework/wiki/EWSGI-specification"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
EWSGI_CONNECTOR
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (a_app: like application)
|
||||
do
|
||||
application := a_app
|
||||
initialize
|
||||
end
|
||||
|
||||
initialize
|
||||
-- Initialize connector
|
||||
do
|
||||
end
|
||||
|
||||
feature {NONE} -- Access
|
||||
|
||||
application: EWSGI_APPLICATION
|
||||
-- Gateway Application
|
||||
|
||||
feature -- Server
|
||||
|
||||
launch
|
||||
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
|
||||
@@ -8,7 +8,14 @@ class
|
||||
GW_BUFFERED_RESPONSE
|
||||
|
||||
inherit
|
||||
EWSGI_RESPONSE_STREAM
|
||||
EWSGI_RESPONSE_BUFFER
|
||||
rename
|
||||
make as buffer_make
|
||||
redefine
|
||||
write,
|
||||
flush,
|
||||
commit
|
||||
end
|
||||
|
||||
create {EWSGI_APPLICATION}
|
||||
make
|
||||
@@ -17,13 +24,11 @@ feature {NONE} -- Initialization
|
||||
|
||||
make (a_output: like output; a_buffer_size: INTEGER)
|
||||
do
|
||||
output := a_output
|
||||
buffer_make (a_output)
|
||||
buffer_capacity := a_buffer_size
|
||||
create buffer.make (a_buffer_size)
|
||||
end
|
||||
|
||||
output: EWSGI_OUTPUT_STREAM
|
||||
|
||||
buffer: STRING_8
|
||||
|
||||
buffer_capacity: INTEGER
|
||||
@@ -60,77 +65,13 @@ feature {NONE} -- Core output operation
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Status setting
|
||||
|
||||
is_status_set: BOOLEAN
|
||||
do
|
||||
Result := status_code /= 0
|
||||
end
|
||||
|
||||
set_status_code (a_code: INTEGER)
|
||||
-- Set response status code
|
||||
-- Should be done before sending any data back to the client
|
||||
do
|
||||
status_code := a_code
|
||||
output.put_status_line (status_code)
|
||||
--| We could also just append it to the `buffer'
|
||||
end
|
||||
|
||||
status_code: INTEGER
|
||||
-- Response status
|
||||
|
||||
feature -- Output operation
|
||||
|
||||
write_string (s: STRING)
|
||||
-- Send the string `s'
|
||||
flush
|
||||
do
|
||||
write (s)
|
||||
flush_buffer
|
||||
end
|
||||
|
||||
write_file_content (fn: STRING)
|
||||
-- Send the content of file `fn'
|
||||
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 (buffer_capacity)
|
||||
write (f.last_string)
|
||||
end
|
||||
f.close
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Header output operation
|
||||
|
||||
write_header (a_status_code: INTEGER; a_headers: detachable ARRAY [TUPLE [key: STRING; value: STRING]])
|
||||
-- Send headers with status `a_status', and headers from `a_headers'
|
||||
local
|
||||
h: GW_HEADER
|
||||
i,n: INTEGER
|
||||
do
|
||||
set_status_code (a_status_code)
|
||||
create h.make
|
||||
if a_headers /= Void then
|
||||
from
|
||||
i := a_headers.lower
|
||||
n := a_headers.upper
|
||||
until
|
||||
i > n
|
||||
loop
|
||||
h.put_header_key_value (a_headers[i].key, a_headers[i].value)
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
write (h.string)
|
||||
end
|
||||
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
flush_buffer
|
||||
@@ -145,10 +86,10 @@ feature {NONE} -- Implementation
|
||||
|
||||
feature {EWSGI_APPLICATION} -- Commit
|
||||
|
||||
commit (a_output: EWSGI_OUTPUT_STREAM)
|
||||
commit
|
||||
do
|
||||
flush_buffer
|
||||
a_output.flush
|
||||
Precursor
|
||||
end
|
||||
|
||||
;note
|
||||
@@ -1,6 +1,5 @@
|
||||
note
|
||||
description: "Summary description for {GW_IN_MEMORY_RESPONSE}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
@@ -8,9 +7,14 @@ class
|
||||
GW_IN_MEMORY_RESPONSE
|
||||
|
||||
inherit
|
||||
EWSGI_RESPONSE_STREAM
|
||||
EWSGI_RESPONSE_BUFFER
|
||||
redefine
|
||||
commit
|
||||
make,
|
||||
commit,
|
||||
write,
|
||||
set_status_code,
|
||||
write_header,
|
||||
flush
|
||||
end
|
||||
|
||||
create {EWSGI_APPLICATION}
|
||||
@@ -18,8 +22,9 @@ create {EWSGI_APPLICATION}
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make
|
||||
make (a_output: EWSGI_OUTPUT_STREAM)
|
||||
do
|
||||
Precursor (a_output)
|
||||
create header.make
|
||||
create body.make (100)
|
||||
end
|
||||
@@ -38,11 +43,6 @@ feature {NONE} -- Status output
|
||||
|
||||
feature -- Status setting
|
||||
|
||||
is_status_set: BOOLEAN
|
||||
do
|
||||
Result := status_code /= 0
|
||||
end
|
||||
|
||||
set_status_code (a_code: INTEGER)
|
||||
-- Set response status code
|
||||
-- Should be done before sending any data back to the client
|
||||
@@ -50,34 +50,11 @@ feature -- Status setting
|
||||
status_code := a_code
|
||||
end
|
||||
|
||||
status_code: INTEGER
|
||||
-- Response status
|
||||
|
||||
feature -- Output operation
|
||||
|
||||
write_string (s: STRING)
|
||||
-- Send the string `s'
|
||||
flush
|
||||
do
|
||||
write (s)
|
||||
end
|
||||
|
||||
write_file_content (fn: STRING)
|
||||
-- Send the content of file `fn'
|
||||
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)
|
||||
write (f.last_string)
|
||||
end
|
||||
f.close
|
||||
end
|
||||
--| Do nothing ... this is in_memory response
|
||||
end
|
||||
|
||||
feature -- Header output operation
|
||||
@@ -106,12 +83,17 @@ feature -- Header output operation
|
||||
|
||||
feature {EWSGI_APPLICATION} -- Commit
|
||||
|
||||
commit (a_output: EWSGI_OUTPUT_STREAM)
|
||||
commit
|
||||
local
|
||||
o: like output
|
||||
do
|
||||
a_output.put_status_line (status_code)
|
||||
a_output.put_string (header.string)
|
||||
a_output.put_string (body)
|
||||
a_output.flush
|
||||
o := output
|
||||
o.put_status_line (status_code)
|
||||
o.put_string (header.string)
|
||||
header_committed := True
|
||||
o.put_string (body)
|
||||
o.flush
|
||||
Precursor
|
||||
end
|
||||
|
||||
;note
|
||||
@@ -10,34 +10,14 @@ deferred class
|
||||
inherit
|
||||
EWSGI_APPLICATION
|
||||
redefine
|
||||
process
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
request_count: INTEGER
|
||||
-- Request count
|
||||
|
||||
feature -- Execution
|
||||
|
||||
process (env: EWSGI_ENVIRONMENT; a_input: EWSGI_INPUT_STREAM; a_output: EWSGI_OUTPUT_STREAM)
|
||||
-- Process request with environment `env', and i/o streams `a_input' and `a_output'
|
||||
do
|
||||
request_count := request_count + 1
|
||||
Precursor (env, a_input, a_output)
|
||||
new_response
|
||||
end
|
||||
|
||||
feature -- Factory
|
||||
|
||||
new_request (env: EWSGI_ENVIRONMENT; a_input: EWSGI_INPUT_STREAM): EWSGI_REQUEST
|
||||
do
|
||||
create {GW_REQUEST_IMP} Result.make (env, a_input)
|
||||
Result.execution_variables.set_variable (request_count.out, "REQUEST_COUNT")
|
||||
end
|
||||
|
||||
new_response (req: EWSGI_REQUEST; a_output: EWSGI_OUTPUT_STREAM): GW_IN_MEMORY_RESPONSE
|
||||
do
|
||||
create {GW_IN_MEMORY_RESPONSE} Result.make
|
||||
create {GW_IN_MEMORY_RESPONSE} Result.make (a_output)
|
||||
end
|
||||
|
||||
note
|
||||
@@ -28,10 +28,10 @@ feature {NONE} -- Initialization
|
||||
|
||||
feature {EWSGI_RESPONSE_APPLICATION} -- Response status
|
||||
|
||||
transmit_to (res: EWSGI_RESPONSE_STREAM)
|
||||
transmit_to (res: EWSGI_RESPONSE_BUFFER)
|
||||
do
|
||||
res.set_status_code (status)
|
||||
res.write_string (headers)
|
||||
res.write_headers_string (headers)
|
||||
from
|
||||
read_block
|
||||
res.write_string (last_block)
|
||||
@@ -131,7 +131,8 @@ feature {EWSGI_RESPONSE_APPLICATION} -- Message body
|
||||
-- -- TBD!
|
||||
end
|
||||
ensure
|
||||
not is_buffered implies last_block.count <= max_block_size
|
||||
--Commented, since it is far from obvious to ensure that:
|
||||
-- not is_buffered implies last_block.count <= max_block_size
|
||||
end
|
||||
|
||||
last_block: STRING
|
||||
@@ -10,14 +10,13 @@ deferred class
|
||||
|
||||
feature -- Execution
|
||||
|
||||
execute (req: EWSGI_REQUEST; res: EWSGI_RESPONSE_STREAM)
|
||||
execute (req: EWSGI_REQUEST; res: EWSGI_RESPONSE_BUFFER)
|
||||
-- Execute the request
|
||||
-- See `req.input' for input stream
|
||||
-- `req.environment' for the Gateway environment
|
||||
-- and `res.output' for output stream
|
||||
local
|
||||
rs: EWSGI_RESPONSE
|
||||
s: STRING
|
||||
do
|
||||
rs := response (req)
|
||||
if rs.ready_to_transmit then
|
||||
76
library/server/ewsgi/src/request/ewsgi_cookie.e
Normal file
76
library/server/ewsgi/src/request/ewsgi_cookie.e
Normal file
@@ -0,0 +1,76 @@
|
||||
note
|
||||
description: "[
|
||||
Contains all information of a rfc2109 cookie that was read from the request header
|
||||
]"
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
EWSGI_COOKIE
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
convert
|
||||
value: {READABLE_STRING_8, STRING_8, READABLE_STRING_GENERAL, STRING_GENERAL}
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (a_name: STRING; a_value: STRING)
|
||||
-- Creates current.
|
||||
require
|
||||
a_name_not_empty: a_name /= Void and then not a_name.is_empty
|
||||
a_value_not_empty: a_value /= Void and then not a_value.is_empty
|
||||
do
|
||||
name := a_name
|
||||
value := a_value
|
||||
ensure
|
||||
a_name_set: name = a_name
|
||||
a_value_set: value = a_value
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
name: STRING
|
||||
-- Required. The name of the state information ("cookie") is NAME,
|
||||
-- and its value is VALUE. NAMEs that begin with $ are reserved for
|
||||
-- other uses and must not be used by applications.
|
||||
|
||||
value: STRING
|
||||
-- The VALUE is opaque to the user agent and may be anything the
|
||||
-- origin server chooses to send, possibly in a server-selected
|
||||
-- printable ASCII encoding. "Opaque" implies that the content is of
|
||||
-- interest and relevance only to the origin server. The content
|
||||
-- may, in fact, be readable by anyone that examines the Set-Cookie
|
||||
-- header.
|
||||
|
||||
feature -- Query
|
||||
|
||||
variables: detachable HASH_TABLE [STRING, STRING]
|
||||
-- Potential variable contained in the encoded cookie's value.
|
||||
|
||||
feature -- Status report
|
||||
|
||||
value_is_string (s: READABLE_STRING_GENERAL): BOOLEAN
|
||||
-- Is `value' same string as `s'
|
||||
do
|
||||
Result := s.same_string (value)
|
||||
end
|
||||
|
||||
invariant
|
||||
name_attached: name /= Void
|
||||
value_attached: value /= Void
|
||||
|
||||
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
|
||||
617
library/server/ewsgi/src/request/ewsgi_environment.e
Normal file
617
library/server/ewsgi/src/request/ewsgi_environment.e
Normal file
@@ -0,0 +1,617 @@
|
||||
note
|
||||
description: "[
|
||||
|
||||
Interface for a request environment
|
||||
It includes CGI interface and a few extra values that are usually valuable
|
||||
|
||||
See http://www.ietf.org/rfc/rfc3875
|
||||
|
||||
2.2. Basic Rules
|
||||
|
||||
The following rules are used throughout this specification to
|
||||
describe basic parsing constructs.
|
||||
|
||||
alpha = lowalpha | hialpha
|
||||
lowalpha = a | b | c | d | e | f | g | h |
|
||||
i | j | k | l | m | n | o | p |
|
||||
q | r | s | t | u | v | w | x |
|
||||
y | z
|
||||
hialpha = A | B | C | D | E | F | G | H |
|
||||
I | J | K | L | M | N | O | P |
|
||||
Q | R | S | T | U | V | W | X |
|
||||
Y | Z
|
||||
digit = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
|
||||
8 | 9
|
||||
alphanum = alpha | digit
|
||||
OCTET = <any 8-bit byte>
|
||||
CHAR = alpha | digit | separator | ! | # | $ |
|
||||
%% | & | ' | * | + | - | . | ` |
|
||||
^ | _ | { | | | } | ~ | CTL
|
||||
CTL = <any control character>
|
||||
SP = <space character>
|
||||
HT = <horizontal tab character>
|
||||
NL = <newline>
|
||||
LWSP = SP | HT | NL
|
||||
separator = ( | ) | < | > | @ | , | ; | : |
|
||||
\ | " | / | [ | ] | ? | = | { |
|
||||
} | SP | HT
|
||||
token = 1*<any CHAR except CTLs or separators>
|
||||
quoted-string = " *qdtext "
|
||||
qdtext = <any CHAR except " and CTLs but including LWSP>
|
||||
TEXT = <any printable character>
|
||||
|
||||
2.3. URL Encoding
|
||||
|
||||
reserved = ; | / | ? | : | @ | & | = | + | $ |
|
||||
, | [ | ]
|
||||
|
||||
hex = digit | A | B | C | D | E | F | a | b
|
||||
| c | d | e | f
|
||||
escaped = "%%" hex hex
|
||||
unreserved = alpha | digit | mark
|
||||
mark = - | _ | . | ! | ~ | * | ' | ( | )
|
||||
|
||||
Note that newline (NL) need not be a single character, but can
|
||||
be a character sequence.
|
||||
|
||||
3.2. The Script-URI
|
||||
|
||||
script-URI = <scheme> "://" <server-name> ":" <server-port>
|
||||
<script-path> <extra-path> "?" <query-string>
|
||||
|
||||
where <scheme> is found from SERVER_PROTOCOL, <server-name>,
|
||||
<server-port> and <query-string> are the values of the respective
|
||||
meta-variables. The SCRIPT_NAME and PATH_INFO values, URL-encoded
|
||||
with ";", "=" and "?" reserved, give <script-path> and <extra-path>.
|
||||
|
||||
]"
|
||||
specification: "EWSGI specification https://github.com/Eiffel-World/Eiffel-Web-Framework/wiki/EWSGI-specification"
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred
|
||||
class
|
||||
EWSGI_ENVIRONMENT
|
||||
|
||||
inherit
|
||||
EWSGI_VARIABLES [STRING_8]
|
||||
|
||||
ITERABLE [STRING_8]
|
||||
|
||||
feature -- Access
|
||||
|
||||
table: HASH_TABLE [STRING, STRING]
|
||||
-- These variables are specific to requests made with HTTP.
|
||||
-- Interpretation of these variables may depend on the value of
|
||||
-- SERVER_PROTOCOL.
|
||||
--
|
||||
-- Environment variables with names beginning with "HTTP_" contain
|
||||
-- header data read from the client, if the protocol used was HTTP.
|
||||
-- The HTTP header name is converted to upper case, has all
|
||||
-- occurrences of "-" replaced with "_" and has "HTTP_" prepended to
|
||||
-- give the environment variable name. The header data may be
|
||||
-- presented as sent by the client, or may be rewritten in ways which
|
||||
-- do not change its semantics. If multiple headers with the same
|
||||
-- field-name are received then they must be rewritten as a single
|
||||
-- header having the same semantics. Similarly, a header that is
|
||||
-- received on more than one line must be merged onto a single line.
|
||||
-- The server must, if necessary, change the representation of the
|
||||
-- data (for example, the character set) to be appropriate for a CGI
|
||||
-- environment variable.
|
||||
--
|
||||
-- The server is not required to create environment variables for all
|
||||
-- the headers that it receives. In particular, it may remove any
|
||||
-- headers carrying authentication information, such as
|
||||
-- "Authorization"; it may remove headers whose value is available to
|
||||
-- the script via other variables, such as "Content-Length" and
|
||||
-- "Content-Type".
|
||||
--
|
||||
-- For convenience it might also include the following CGI entries
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Access: table
|
||||
|
||||
new_cursor: HASH_TABLE_ITERATION_CURSOR [STRING_8, STRING_8]
|
||||
-- Fresh cursor associated with current structure
|
||||
do
|
||||
create Result.make (table)
|
||||
end
|
||||
|
||||
feature -- Common Gateway Interface - 1.1 8 January 1996
|
||||
|
||||
auth_type: detachable STRING
|
||||
-- This variable is specific to requests made via the "http"
|
||||
-- scheme.
|
||||
--
|
||||
-- If the Script-URI required access authentication for external
|
||||
-- access, then the server MUST set the value of this variable
|
||||
-- from the 'auth-scheme' token in the request's "Authorization"
|
||||
-- header field. Otherwise it is set to NULL.
|
||||
--
|
||||
-- AUTH_TYPE = "" | auth-scheme
|
||||
-- auth-scheme = "Basic" | "Digest" | token
|
||||
--
|
||||
-- HTTP access authentication schemes are described in section 11
|
||||
-- of the HTTP/1.1 specification [8]. The auth-scheme is not
|
||||
-- case-sensitive.
|
||||
--
|
||||
-- Servers MUST provide this metavariable to scripts if the
|
||||
-- request header included an "Authorization" field that was
|
||||
-- authenticated.
|
||||
deferred
|
||||
end
|
||||
|
||||
content_length: detachable STRING
|
||||
-- This metavariable is set to the size of the message-body
|
||||
-- entity attached to the request, if any, in decimal number of
|
||||
-- octets. If no data are attached, then this metavariable is
|
||||
-- either NULL or not defined. The syntax is the same as for the
|
||||
-- HTTP "Content-Length" header field (section 14.14, HTTP/1.1
|
||||
-- specification [8]).
|
||||
--
|
||||
-- CONTENT_LENGTH = "" | 1*digit
|
||||
--
|
||||
-- Servers MUST provide this metavariable to scripts if the
|
||||
-- request was accompanied by a message-body entity.
|
||||
deferred
|
||||
end
|
||||
|
||||
content_length_value: INTEGER
|
||||
-- Integer value related to `content_length"
|
||||
deferred
|
||||
end
|
||||
|
||||
content_type: detachable STRING
|
||||
-- If the request includes a message-body, CONTENT_TYPE is set to
|
||||
-- the Internet Media Type [9] of the attached entity if the type
|
||||
-- was provided via a "Content-type" field in the request header,
|
||||
-- or if the server can determine it in the absence of a supplied
|
||||
-- "Content-type" field. The syntax is the same as for the HTTP
|
||||
-- "Content-Type" header field.
|
||||
--
|
||||
-- CONTENT_TYPE = "" | media-type
|
||||
-- media-type = type "/" subtype *( ";" parameter)
|
||||
-- type = token
|
||||
-- subtype = token
|
||||
-- parameter = attribute "=" value
|
||||
-- attribute = token
|
||||
-- value = token | quoted-string
|
||||
--
|
||||
-- The type, subtype, and parameter attribute names are not
|
||||
-- case-sensitive. Parameter values MAY be case sensitive. Media
|
||||
-- types and their use in HTTP are described in section 3.7 of
|
||||
-- the HTTP/1.1 specification [8].
|
||||
--
|
||||
-- Example:
|
||||
--
|
||||
-- application/x-www-form-urlencoded
|
||||
--
|
||||
-- There is no default value for this variable. If and only if it
|
||||
-- is unset, then the script MAY attempt to determine the media
|
||||
-- type from the data received. If the type remains unknown, then
|
||||
-- the script MAY choose to either assume a content-type of
|
||||
-- application/octet-stream or reject the request with a 415
|
||||
-- ("Unsupported Media Type") error. See section 7.2.1.3 for more
|
||||
-- information about returning error status values.
|
||||
--
|
||||
-- Servers MUST provide this metavariable to scripts if a
|
||||
-- "Content-Type" field was present in the original request
|
||||
-- header. If the server receives a request with an attached
|
||||
-- entity but no "Content-Type" header field, it MAY attempt to
|
||||
-- determine the correct datatype, or it MAY omit this
|
||||
-- metavariable when communicating the request information to the
|
||||
-- script.
|
||||
deferred
|
||||
end
|
||||
|
||||
gateway_interface: STRING
|
||||
-- This metavariable is set to the dialect of CGI being used by
|
||||
-- the server to communicate with the script. Syntax:
|
||||
--
|
||||
-- GATEWAY_INTERFACE = "CGI" "/" major "." minor
|
||||
-- major = 1*digit
|
||||
-- minor = 1*digit
|
||||
--
|
||||
-- Note that the major and minor numbers are treated as separate
|
||||
-- integers and hence each may be more than a single digit. Thus
|
||||
-- CGI/2.4 is a lower version than CGI/2.13 which in turn is
|
||||
-- lower than CGI/12.3. Leading zeros in either the major or the
|
||||
-- minor number MUST be ignored by scripts and SHOULD NOT be
|
||||
-- generated by servers.
|
||||
--
|
||||
-- This document defines the 1.1 version of the CGI interface
|
||||
-- ("CGI/1.1").
|
||||
--
|
||||
-- Servers MUST provide this metavariable to scripts.
|
||||
--
|
||||
-- The version of the CGI specification to which this server
|
||||
-- complies. Syntax:
|
||||
--
|
||||
-- GATEWAY_INTERFACE = "CGI" "/" 1*digit "." 1*digit
|
||||
--
|
||||
-- Note that the major and minor numbers are treated as separate
|
||||
-- integers and that each may be incremented higher than a single
|
||||
-- digit. Thus CGI/2.4 is a lower version than CGI/2.13 which in
|
||||
-- turn is lower than CGI/12.3. Leading zeros must be ignored by
|
||||
-- scripts and should never be generated by servers.
|
||||
deferred
|
||||
end
|
||||
|
||||
path_info: STRING assign update_path_info
|
||||
-- The PATH_INFO metavariable specifies a path to be interpreted
|
||||
-- by the CGI script. It identifies the resource or sub-resource
|
||||
-- to be returned by the CGI script, and it is derived from the
|
||||
-- portion of the URI path following the script name but
|
||||
-- preceding any query data. The syntax and semantics are similar
|
||||
-- to a decoded HTTP URL 'path' token (defined in RFC 2396 [4]),
|
||||
-- with the exception that a PATH_INFO of "/" represents a single
|
||||
-- void path segment.
|
||||
--
|
||||
-- PATH_INFO = "" | ( "/" path )
|
||||
-- path = segment *( "/" segment )
|
||||
-- segment = *pchar
|
||||
-- pchar = <any CHAR except "/">
|
||||
--
|
||||
-- The PATH_INFO string is the trailing part of the <path>
|
||||
-- component of the Script-URI (see section 3.2) that follows the
|
||||
-- SCRIPT_NAME portion of the path.
|
||||
--
|
||||
-- Servers MAY impose their own restrictions and limitations on
|
||||
-- what values they will accept for PATH_INFO, and MAY reject or
|
||||
-- edit any values they consider objectionable before passing
|
||||
-- them to the script.
|
||||
--
|
||||
-- Servers MUST make this URI component available to CGI scripts.
|
||||
-- The PATH_INFO value is case-sensitive, and the server MUST
|
||||
-- preserve the case of the PATH_INFO element of the URI when
|
||||
-- making it available to scripts.
|
||||
deferred
|
||||
end
|
||||
|
||||
path_translated: detachable STRING
|
||||
-- PATH_TRANSLATED is derived by taking any path-info component
|
||||
-- of the request URI (see section 6.1.6), decoding it (see
|
||||
-- section 3.1), parsing it as a URI in its own right, and
|
||||
-- performing any virtual-to-physical translation appropriate to
|
||||
-- map it onto the server's document repository structure. If the
|
||||
-- request URI includes no path-info component, the
|
||||
-- PATH_TRANSLATED metavariable SHOULD NOT be defined.
|
||||
--
|
||||
--
|
||||
-- PATH_TRANSLATED = *CHAR
|
||||
--
|
||||
-- For a request such as the following:
|
||||
--
|
||||
-- http://somehost.com/cgi-bin/somescript/this%2eis%2epath%2einfo
|
||||
--
|
||||
-- the PATH_INFO component would be decoded, and the result
|
||||
-- parsed as though it were a request for the following:
|
||||
--
|
||||
-- http://somehost.com/this.is.the.path.info
|
||||
--
|
||||
-- This would then be translated to a location in the server's
|
||||
-- document repository, perhaps a filesystem path something like
|
||||
-- this:
|
||||
--
|
||||
-- /usr/local/www/htdocs/this.is.the.path.info
|
||||
--
|
||||
-- The result of the translation is the value of PATH_TRANSLATED.
|
||||
--
|
||||
-- The value of PATH_TRANSLATED may or may not map to a valid
|
||||
-- repository location. Servers MUST preserve the case of the
|
||||
-- path-info segment if and only if the underlying repository
|
||||
-- supports case-sensitive names. If the repository is only
|
||||
-- case-aware, case-preserving, or case-blind with regard to
|
||||
-- document names, servers are not required to preserve the case
|
||||
-- of the original segment through the translation.
|
||||
--
|
||||
-- The translation algorithm the server uses to derive
|
||||
-- PATH_TRANSLATED is implementation defined; CGI scripts which
|
||||
-- use this variable may suffer limited portability.
|
||||
--
|
||||
-- Servers SHOULD provide this metavariable to scripts if and
|
||||
-- only if the request URI includes a path-info component.
|
||||
deferred
|
||||
end
|
||||
|
||||
query_string: STRING
|
||||
-- A URL-encoded string; the <query> part of the Script-URI. (See
|
||||
-- section 3.2.)
|
||||
--
|
||||
-- QUERY_STRING = query-string
|
||||
-- query-string = *uric
|
||||
|
||||
-- The URL syntax for a query string is described in section 3 of
|
||||
-- RFC 2396 [4].
|
||||
--
|
||||
-- Servers MUST supply this value to scripts. The QUERY_STRING
|
||||
-- value is case-sensitive. If the Script-URI does not include a
|
||||
-- query component, the QUERY_STRING metavariable MUST be defined
|
||||
-- as an empty string ("").
|
||||
deferred
|
||||
end
|
||||
|
||||
remote_addr: STRING
|
||||
-- The IP address of the client sending the request to the
|
||||
-- server. This is not necessarily that of the user agent (such
|
||||
-- as if the request came through a proxy).
|
||||
--
|
||||
-- REMOTE_ADDR = hostnumber
|
||||
-- hostnumber = ipv4-address | ipv6-address
|
||||
|
||||
-- The definitions of ipv4-address and ipv6-address are provided
|
||||
-- in Appendix B of RFC 2373 [13].
|
||||
--
|
||||
-- Servers MUST supply this value to scripts.
|
||||
deferred
|
||||
end
|
||||
|
||||
remote_host: detachable STRING
|
||||
-- The fully qualified domain name of the client sending the
|
||||
-- request to the server, if available, otherwise NULL. (See
|
||||
-- section 6.1.9.) Fully qualified domain names take the form as
|
||||
-- described in section 3.5 of RFC 1034 [10] and section 2.1 of
|
||||
-- RFC 1123 [5]. Domain names are not case sensitive.
|
||||
--
|
||||
-- Servers SHOULD provide this information to scripts.
|
||||
deferred
|
||||
end
|
||||
|
||||
remote_ident: detachable STRING
|
||||
-- The identity information reported about the connection by a
|
||||
-- RFC 1413 [11] request to the remote agent, if available.
|
||||
-- Servers MAY choose not to support this feature, or not to
|
||||
-- request the data for efficiency reasons.
|
||||
--
|
||||
-- REMOTE_IDENT = *CHAR
|
||||
--
|
||||
-- The data returned may be used for authentication purposes, but
|
||||
-- the level of trust reposed in them should be minimal.
|
||||
--
|
||||
-- Servers MAY supply this information to scripts if the RFC1413
|
||||
-- [11] lookup is performed.
|
||||
deferred
|
||||
end
|
||||
|
||||
remote_user: detachable STRING
|
||||
-- If the request required authentication using the "Basic"
|
||||
-- mechanism (i.e., the AUTH_TYPE metavariable is set to
|
||||
-- "Basic"), then the value of the REMOTE_USER metavariable is
|
||||
-- set to the user-ID supplied. In all other cases the value of
|
||||
-- this metavariable is undefined.
|
||||
--
|
||||
-- REMOTE_USER = *OCTET
|
||||
--
|
||||
-- This variable is specific to requests made via the HTTP
|
||||
-- protocol.
|
||||
--
|
||||
-- Servers SHOULD provide this metavariable to scripts.
|
||||
deferred
|
||||
end
|
||||
|
||||
request_method: STRING
|
||||
-- The REQUEST_METHOD metavariable is set to the method with
|
||||
-- which the request was made, as described in section 5.1.1 of
|
||||
-- the HTTP/1.0 specification [3] and section 5.1.1 of the
|
||||
-- HTTP/1.1 specification [8].
|
||||
--
|
||||
-- REQUEST_METHOD = http-method
|
||||
-- http-method = "GET" | "HEAD" | "POST" | "PUT" | "DELETE"
|
||||
-- | "OPTIONS" | "TRACE" | extension-method
|
||||
-- extension-method = token
|
||||
--
|
||||
-- The method is case sensitive. CGI/1.1 servers MAY choose to
|
||||
-- process some methods directly rather than passing them to
|
||||
-- scripts.
|
||||
--
|
||||
-- This variable is specific to requests made with HTTP.
|
||||
--
|
||||
-- Servers MUST provide this metavariable to scripts.
|
||||
deferred
|
||||
end
|
||||
|
||||
script_name: STRING
|
||||
-- The SCRIPT_NAME metavariable is set to a URL path that could
|
||||
-- identify the CGI script (rather than the script's output). The
|
||||
-- syntax and semantics are identical to a decoded HTTP URL
|
||||
-- 'path' token (see RFC 2396 [4]).
|
||||
--
|
||||
-- SCRIPT_NAME = "" | ( "/" [ path ] )
|
||||
--
|
||||
-- The SCRIPT_NAME string is some leading part of the <path>
|
||||
-- component of the Script-URI derived in some implementation
|
||||
-- defined manner. No PATH_INFO or QUERY_STRING segments (see
|
||||
-- sections 6.1.6 and 6.1.8) are included in the SCRIPT_NAME
|
||||
-- value.
|
||||
--
|
||||
-- Servers MUST provide this metavariable to scripts.
|
||||
deferred
|
||||
end
|
||||
|
||||
server_name: STRING
|
||||
-- The SERVER_NAME metavariable is set to the name of the server,
|
||||
-- as derived from the <host> part of the Script-URI (see section
|
||||
-- 3.2).
|
||||
--
|
||||
-- SERVER_NAME = hostname | hostnumber
|
||||
--
|
||||
-- Servers MUST provide this metavariable to scripts.
|
||||
deferred
|
||||
end
|
||||
|
||||
server_port: INTEGER
|
||||
-- The SERVER_PORT metavariable is set to the port on which the
|
||||
-- request was received, as used in the <port> part of the
|
||||
-- Script-URI.
|
||||
--
|
||||
-- SERVER_PORT = 1*digit
|
||||
--
|
||||
-- If the <port> portion of the script-URI is blank, the actual
|
||||
-- port number upon which the request was received MUST be
|
||||
-- supplied.
|
||||
--
|
||||
-- Servers MUST provide this metavariable to scripts.
|
||||
deferred
|
||||
end
|
||||
|
||||
server_protocol: STRING
|
||||
-- The SERVER_PROTOCOL metavariable is set to the name and
|
||||
-- revision of the information protocol with which the request
|
||||
-- arrived. This is not necessarily the same as the protocol
|
||||
-- version used by the server in its response to the client.
|
||||
--
|
||||
-- SERVER_PROTOCOL = HTTP-Version | extension-version
|
||||
-- | extension-token
|
||||
-- HTTP-Version = "HTTP" "/" 1*digit "." 1*digit
|
||||
-- extension-version = protocol "/" 1*digit "." 1*digit
|
||||
-- protocol = 1*( alpha | digit | "+" | "-" | "." )
|
||||
-- extension-token = token
|
||||
--
|
||||
-- 'protocol' is a version of the <scheme> part of the
|
||||
-- Script-URI, but is not identical to it. For example, the
|
||||
-- scheme of a request may be "https" while the protocol remains
|
||||
-- "http". The protocol is not case sensitive, but by convention,
|
||||
-- 'protocol' is in upper case.
|
||||
--
|
||||
-- A well-known extension token value is "INCLUDED", which
|
||||
-- signals that the current document is being included as part of
|
||||
-- a composite document, rather than being the direct target of
|
||||
-- the client request.
|
||||
--
|
||||
-- Servers MUST provide this metavariable to scripts.
|
||||
deferred
|
||||
end
|
||||
|
||||
server_software: STRING
|
||||
-- The SERVER_SOFTWARE metavariable is set to the name and
|
||||
-- version of the information server software answering the
|
||||
-- request (and running the gateway).
|
||||
--
|
||||
-- SERVER_SOFTWARE = 1*product
|
||||
-- product = token [ "/" product-version ]
|
||||
-- product-version = token
|
||||
|
||||
-- Servers MUST provide this metavariable to scripts.
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- HTTP_*
|
||||
|
||||
http_accept: detachable STRING
|
||||
-- Contents of the Accept: header from the current request, if there is one.
|
||||
-- Example: 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
|
||||
deferred
|
||||
end
|
||||
|
||||
http_accept_charset: detachable STRING
|
||||
-- Contents of the Accept-Charset: header from the current request, if there is one.
|
||||
-- Example: 'iso-8859-1,*,utf-8'.
|
||||
deferred
|
||||
end
|
||||
|
||||
http_accept_encoding: detachable STRING
|
||||
-- Contents of the Accept-Encoding: header from the current request, if there is one.
|
||||
-- Example: 'gzip'.
|
||||
deferred
|
||||
end
|
||||
|
||||
http_accept_language: detachable STRING
|
||||
-- Contents of the Accept-Language: header from the current request, if there is one.
|
||||
-- Example: 'en'.
|
||||
deferred
|
||||
end
|
||||
|
||||
http_connection: detachable STRING
|
||||
-- Contents of the Connection: header from the current request, if there is one.
|
||||
-- Example: 'Keep-Alive'.
|
||||
deferred
|
||||
end
|
||||
|
||||
http_host: detachable STRING
|
||||
-- Contents of the Host: header from the current request, if there is one.
|
||||
deferred
|
||||
end
|
||||
|
||||
http_referer: detachable STRING
|
||||
-- The address of the page (if any) which referred the user agent to the current page.
|
||||
-- This is set by the user agent.
|
||||
-- Not all user agents will set this, and some provide the ability to modify HTTP_REFERER as a feature.
|
||||
-- In short, it cannot really be trusted.
|
||||
deferred
|
||||
end
|
||||
|
||||
http_user_agent: detachable STRING
|
||||
-- Contents of the User-Agent: header from the current request, if there is one.
|
||||
-- This is a string denoting the user agent being which is accessing the page.
|
||||
-- A typical example is: Mozilla/4.5 [en] (X11; U; Linux 2.2.9 i586).
|
||||
-- Among other things, you can use this value to tailor your page's
|
||||
-- output to the capabilities of the user agent.
|
||||
deferred
|
||||
end
|
||||
|
||||
http_authorization: detachable STRING
|
||||
-- Contents of the Authorization: header from the current request, if there is one.
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Extra
|
||||
|
||||
request_uri: STRING
|
||||
-- The URI which was given in order to access this page; for instance, '/index.html'.
|
||||
deferred
|
||||
end
|
||||
|
||||
orig_path_info: detachable STRING
|
||||
-- Original version of `path_info' before processed by Current environment
|
||||
deferred
|
||||
end
|
||||
|
||||
feature {EWSGI_REQUEST} -- Element change
|
||||
|
||||
set_orig_path_info (s: STRING)
|
||||
-- Set ORIG_PATH_INFO to `s'
|
||||
require
|
||||
s_attached: s /= Void
|
||||
deferred
|
||||
ensure
|
||||
same_orig_path_info: orig_path_info ~ variable ({EWSGI_ENVIRONMENT_NAMES}.orig_path_info)
|
||||
end
|
||||
|
||||
unset_orig_path_info
|
||||
-- Unset ORIG_PATH_INFO
|
||||
deferred
|
||||
ensure
|
||||
unset: not has_variable ({EWSGI_ENVIRONMENT_NAMES}.orig_path_info)
|
||||
end
|
||||
|
||||
update_path_info (a_path_info: like path_info)
|
||||
-- Updated PATH_INFO
|
||||
deferred
|
||||
ensure
|
||||
same_path_info: path_info ~ variable ({EWSGI_ENVIRONMENT_NAMES}.path_info)
|
||||
end
|
||||
|
||||
invariant
|
||||
server_name_not_empty: not server_name.is_empty
|
||||
server_port_set: server_port /= 0
|
||||
request_method_attached: request_method /= Void
|
||||
path_info_attached: path_info /= Void
|
||||
query_string_attached: query_string /= Void
|
||||
remote_addr_attached: remote_addr /= Void
|
||||
|
||||
path_info_identical: path_info ~ variable ({EWSGI_ENVIRONMENT_NAMES}.path_info)
|
||||
|
||||
;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
|
||||
89
library/server/ewsgi/src/request/ewsgi_environment_names.e
Normal file
89
library/server/ewsgi/src/request/ewsgi_environment_names.e
Normal file
@@ -0,0 +1,89 @@
|
||||
note
|
||||
description: "Summary description for {EWSGI_ENVIRONMENT_NAMES}."
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
EWSGI_ENVIRONMENT_NAMES
|
||||
|
||||
feature -- Access
|
||||
|
||||
request_uri: STRING = "REQUEST_URI"
|
||||
|
||||
request_method: STRING = "REQUEST_METHOD"
|
||||
|
||||
query_string: STRING = "QUERY_STRING"
|
||||
|
||||
content_type: STRING = "CONTENT_TYPE"
|
||||
|
||||
content_length: STRING = "CONTENT_LENGTH"
|
||||
|
||||
path_info: STRING = "PATH_INFO"
|
||||
|
||||
path_translated: STRING = "PATH_TRANSLATED"
|
||||
|
||||
http_user_agent: STRING = "HTTP_USER_AGENT"
|
||||
|
||||
http_authorization: STRING = "HTTP_AUTHORIZATION"
|
||||
|
||||
http_host: STRING = "HTTP_HOST"
|
||||
|
||||
http_cookie: STRING = "HTTP_COOKIE"
|
||||
|
||||
http_from: STRING = "HTTP_FROM"
|
||||
|
||||
http_accept: STRING = "HTTP_ACCEPT"
|
||||
|
||||
http_accept_charset: STRING = "HTTP_ACCEPT_CHARSET"
|
||||
|
||||
http_accept_encoding: STRING = "HTTP_ACCEPT_ENCODING"
|
||||
|
||||
http_accept_language: STRING = "HTTP_ACCEPT_LANGUAGE"
|
||||
|
||||
http_connection: STRING = "HTTP_CONNECTION"
|
||||
|
||||
http_referer: STRING = "HTTP_REFERER"
|
||||
|
||||
gateway_interface: STRING = "GATEWAY_INTERFACE"
|
||||
|
||||
auth_type: STRING = "AUTH_TYPE"
|
||||
|
||||
remote_host: STRING = "REMOTE_HOST"
|
||||
|
||||
remote_addr: STRING = "REMOTE_ADDR"
|
||||
|
||||
remote_ident: STRING = "REMOTE_IDENT"
|
||||
|
||||
remote_user: STRING = "REMOTE_USER"
|
||||
|
||||
script_name: STRING = "SCRIPT_NAME"
|
||||
|
||||
server_name: STRING = "SERVER_NAME"
|
||||
|
||||
server_port: STRING = "SERVER_PORT"
|
||||
|
||||
server_protocol: STRING = "SERVER_PROTOCOL"
|
||||
|
||||
server_software: STRING = "SERVER_SOFTWARE"
|
||||
|
||||
feature -- Extra names
|
||||
|
||||
request_time: STRING = "REQUEST_TIME"
|
||||
|
||||
self: STRING = "SELF"
|
||||
|
||||
orig_path_info: STRING = "ORIG_PATH_INFO"
|
||||
|
||||
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
|
||||
@@ -1,21 +1,15 @@
|
||||
note
|
||||
description: "[
|
||||
Server request context of the httpd request
|
||||
|
||||
You can create your own descendant of this class to
|
||||
add/remove specific value or processing
|
||||
|
||||
This object is created by {EWSGI_APPLICATION}.new_request
|
||||
EWSGI interface to represent the Request
|
||||
|
||||
]"
|
||||
specification: "EWSGI specification https://github.com/Eiffel-World/Eiffel-Web-Framework/wiki/EWSGI-specification"
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
GW_REQUEST_IMP
|
||||
|
||||
inherit
|
||||
EWSGI_REQUEST
|
||||
|
||||
create
|
||||
@@ -31,7 +25,6 @@ feature {NONE} -- Initialization
|
||||
input := a_input
|
||||
environment := env
|
||||
content_length := env.content_length_value
|
||||
create execution_variables.make (10)
|
||||
create uploaded_files.make (0)
|
||||
|
||||
raw_post_data_recorded := True
|
||||
@@ -100,6 +93,8 @@ feature -- Access: environment variables
|
||||
|
||||
environment_variable (a_name: STRING): detachable STRING
|
||||
-- Environment variable related to `a_name'
|
||||
require
|
||||
a_name_valid: a_name /= Void and then not a_name.is_empty
|
||||
do
|
||||
Result := environment.variable (a_name)
|
||||
end
|
||||
@@ -107,20 +102,10 @@ feature -- Access: environment variables
|
||||
content_length: INTEGER
|
||||
-- Extracted Content-Length value
|
||||
|
||||
feature -- Access: execution variables
|
||||
|
||||
execution_variables: GW_EXECUTION_VARIABLES
|
||||
-- Execution variables set by the application
|
||||
|
||||
execution_variable (a_name: STRING): detachable STRING_32
|
||||
-- Execution variable related to `a_name'
|
||||
do
|
||||
Result := execution_variables.variable (a_name)
|
||||
end
|
||||
|
||||
feature -- URL parameters
|
||||
|
||||
parameters: GW_REQUEST_VARIABLES
|
||||
parameters: EWSGI_REQUEST_VARIABLES
|
||||
-- Variables extracted from QUERY_STRING
|
||||
local
|
||||
vars: like internal_parameters
|
||||
p,e: INTEGER
|
||||
@@ -155,13 +140,16 @@ feature -- URL parameters
|
||||
|
||||
parameter (a_name: STRING): detachable STRING_32
|
||||
-- Parameter for name `n'.
|
||||
require
|
||||
a_name_valid: a_name /= Void and then not a_name.is_empty
|
||||
do
|
||||
Result := parameters.variable (a_name)
|
||||
end
|
||||
|
||||
feature -- Form fields and related
|
||||
|
||||
form_fields: GW_REQUEST_VARIABLES
|
||||
form_fields: EWSGI_REQUEST_VARIABLES
|
||||
-- Variables sent by POST request
|
||||
local
|
||||
vars: like internal_form_fields
|
||||
s: STRING
|
||||
@@ -198,6 +186,8 @@ feature -- Form fields and related
|
||||
|
||||
form_field (a_name: STRING): detachable STRING_32
|
||||
-- Field for name `a_name'.
|
||||
require
|
||||
a_name_valid: a_name /= Void and then not a_name.is_empty
|
||||
do
|
||||
Result := form_fields.variable (a_name)
|
||||
end
|
||||
@@ -244,6 +234,8 @@ feature -- Cookies
|
||||
|
||||
cookies_variable (a_name: STRING): detachable STRING
|
||||
-- Field for name `a_name'.
|
||||
require
|
||||
a_name_valid: a_name /= Void and then not a_name.is_empty
|
||||
do
|
||||
Result := cookies_variables.item (a_name)
|
||||
end
|
||||
@@ -302,16 +294,6 @@ feature -- Access: global variable
|
||||
do
|
||||
create Result.make (100)
|
||||
|
||||
vars := execution_variables
|
||||
from
|
||||
vars.start
|
||||
until
|
||||
vars.after
|
||||
loop
|
||||
Result.put (vars.item_for_iteration, vars.key_for_iteration)
|
||||
vars.forth
|
||||
end
|
||||
|
||||
vars := environment.table
|
||||
from
|
||||
vars.start
|
||||
@@ -360,16 +342,13 @@ feature -- Access: global variable
|
||||
local
|
||||
s: detachable STRING_GENERAL
|
||||
do
|
||||
s := execution_variable (a_name)
|
||||
s := environment_variable (a_name)
|
||||
if s = Void then
|
||||
s := environment_variable (a_name)
|
||||
s := parameter (a_name)
|
||||
if s = Void then
|
||||
s := parameter (a_name)
|
||||
s := form_field (a_name)
|
||||
if s = Void then
|
||||
s := form_field (a_name)
|
||||
if s = Void then
|
||||
s := cookies_variable (a_name)
|
||||
end
|
||||
s := cookies_variable (a_name)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -378,7 +357,6 @@ feature -- Access: global variable
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
feature -- Access extra information
|
||||
|
||||
request_time: detachable DATE_TIME
|
||||
@@ -392,6 +370,28 @@ feature -- Access extra information
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Uploaded File Handling
|
||||
|
||||
is_uploaded_file (a_filename: STRING): BOOLEAN
|
||||
-- Is `a_filename' a file uploaded via HTTP Form
|
||||
local
|
||||
l_files: like uploaded_files
|
||||
do
|
||||
l_files := uploaded_files
|
||||
if not l_files.is_empty then
|
||||
from
|
||||
l_files.start
|
||||
until
|
||||
l_files.after or Result
|
||||
loop
|
||||
if attached l_files.item_for_iteration.tmp_name as l_tmp_name and then l_tmp_name.same_string (a_filename) then
|
||||
Result := True
|
||||
end
|
||||
l_files.forth
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feature -- URL Utility
|
||||
|
||||
absolute_script_url (a_path: STRING): STRING
|
||||
@@ -489,28 +489,6 @@ feature -- Element change
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Uploaded File Handling
|
||||
|
||||
is_uploaded_file (a_filename: STRING): BOOLEAN
|
||||
-- Is `a_filename' a file uploaded via HTTP Form
|
||||
local
|
||||
l_files: like uploaded_files
|
||||
do
|
||||
l_files := uploaded_files
|
||||
if not l_files.is_empty then
|
||||
from
|
||||
l_files.start
|
||||
until
|
||||
l_files.after or Result
|
||||
loop
|
||||
if attached l_files.item_for_iteration.tmp_name as l_tmp_name and then l_tmp_name.same_string (a_filename) then
|
||||
Result := True
|
||||
end
|
||||
l_files.forth
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Temporary File handling
|
||||
|
||||
delete_uploaded_file (uf: EWSGI_UPLOADED_FILE_DATA)
|
||||
@@ -8,7 +8,7 @@ note
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
GW_REQUEST_VARIABLES
|
||||
EWSGI_REQUEST_VARIABLES
|
||||
|
||||
inherit
|
||||
EWSGI_VARIABLES [STRING_32]
|
||||
103
library/server/ewsgi/src/request/ewsgi_uploaded_file_data.e
Normal file
103
library/server/ewsgi/src/request/ewsgi_uploaded_file_data.e
Normal file
@@ -0,0 +1,103 @@
|
||||
note
|
||||
description: "Summary description for {GW_UPLOADED_FILE}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
EWSGI_UPLOADED_FILE_DATA
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (n: like name; t: like content_type; s: like size)
|
||||
do
|
||||
name := n
|
||||
content_type := t
|
||||
size := s
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
name: STRING
|
||||
-- original filename
|
||||
|
||||
content_type: STRING
|
||||
-- Content type
|
||||
|
||||
size: INTEGER
|
||||
-- Size of uploaded file
|
||||
|
||||
tmp_name: detachable STRING
|
||||
-- Filename of tmp file
|
||||
|
||||
tmp_basename: detachable STRING
|
||||
-- Basename of tmp file
|
||||
|
||||
feature -- Basic operation
|
||||
|
||||
move_to (a_destination: STRING): BOOLEAN
|
||||
-- Move current uploaded file to `a_destination'
|
||||
require
|
||||
has_no_error: not has_error
|
||||
local
|
||||
f: RAW_FILE
|
||||
do
|
||||
if attached tmp_name as n then
|
||||
create f.make (n)
|
||||
if f.exists then
|
||||
f.change_name (a_destination)
|
||||
Result := True
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Status
|
||||
|
||||
has_error: BOOLEAN
|
||||
-- Has error during uploading
|
||||
do
|
||||
Result := error /= 0
|
||||
end
|
||||
|
||||
error: INTEGER
|
||||
-- Eventual error code
|
||||
--| no error => 0
|
||||
|
||||
feature -- Element change
|
||||
|
||||
set_error (e: like error)
|
||||
-- Set `error' to `e'
|
||||
do
|
||||
error := e
|
||||
end
|
||||
|
||||
set_tmp_name (n: like tmp_name)
|
||||
-- Set `tmp_name' to `n'
|
||||
do
|
||||
tmp_name := n
|
||||
end
|
||||
|
||||
set_tmp_basename (n: like tmp_basename)
|
||||
-- Set `tmp_basename' to `n'
|
||||
do
|
||||
tmp_basename := n
|
||||
end
|
||||
|
||||
invariant
|
||||
|
||||
valid_tmp_name: not has_error implies attached tmp_name as n and then not n.is_empty
|
||||
|
||||
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
|
||||
80
library/server/ewsgi/src/request/ewsgi_variables.e
Normal file
80
library/server/ewsgi/src/request/ewsgi_variables.e
Normal file
@@ -0,0 +1,80 @@
|
||||
note
|
||||
description : "[
|
||||
Interface to access the variable stored in a container
|
||||
]"
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
EWSGI_VARIABLES [G -> STRING_GENERAL]
|
||||
|
||||
inherit
|
||||
ITERABLE [G]
|
||||
|
||||
feature -- Status report
|
||||
|
||||
has_variable (a_name: STRING): BOOLEAN
|
||||
-- Has variable associated with `a_name'
|
||||
require
|
||||
a_name_not_empty: a_name /= Void and then not a_name.is_empty
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
variable (a_name: STRING): detachable G
|
||||
-- Value for variable associated with `a_name'
|
||||
-- If not found, return Void
|
||||
require
|
||||
a_name_not_empty: a_name /= Void and then not a_name.is_empty
|
||||
deferred
|
||||
end
|
||||
|
||||
variable_or_default (a_name: STRING; a_default: G; use_default_when_empty: BOOLEAN): G
|
||||
-- Value for variable `a_name'
|
||||
-- If not found, return `a_default'
|
||||
require
|
||||
a_name_not_empty: a_name /= Void and then not a_name.is_empty
|
||||
do
|
||||
if attached variable (a_name) as s then
|
||||
if use_default_when_empty and then s.is_empty then
|
||||
Result := a_default
|
||||
else
|
||||
Result := s
|
||||
end
|
||||
else
|
||||
Result := a_default
|
||||
end
|
||||
end
|
||||
|
||||
feature {EWSGI_REQUEST, EWSGI_APPLICATION, EWSGI_CONNECTOR} -- Element change
|
||||
|
||||
set_variable (a_name: STRING; a_value: G)
|
||||
require
|
||||
a_name_not_empty: a_name /= Void and then not a_name.is_empty
|
||||
deferred
|
||||
ensure
|
||||
variable_set: has_variable (a_name) and then variable (a_name) ~ a_value
|
||||
end
|
||||
|
||||
unset_variable (a_name: STRING)
|
||||
require
|
||||
a_name_not_empty: a_name /= Void and then not a_name.is_empty
|
||||
deferred
|
||||
ensure
|
||||
variable_unset: not has_variable (a_name)
|
||||
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
|
||||
@@ -1,56 +0,0 @@
|
||||
note
|
||||
description: "Summary description for {GW_EXECUTION_VARIABLES}."
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
GW_EXECUTION_VARIABLES
|
||||
|
||||
inherit
|
||||
EWSGI_VARIABLES [STRING_32]
|
||||
undefine
|
||||
copy, is_equal
|
||||
end
|
||||
|
||||
HASH_TABLE [STRING_32, STRING]
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Status report
|
||||
|
||||
variable (a_name: STRING): detachable STRING_32
|
||||
do
|
||||
Result := item (a_name)
|
||||
end
|
||||
|
||||
has_variable (a_name: STRING): BOOLEAN
|
||||
do
|
||||
Result := has (a_name)
|
||||
end
|
||||
|
||||
feature {EWSGI_REQUEST, EWSGI_APPLICATION, EWSGI_CONNECTOR} -- Element change
|
||||
|
||||
set_variable (a_name: STRING; a_value: STRING_32)
|
||||
do
|
||||
force (a_value, a_name)
|
||||
end
|
||||
|
||||
unset_variable (a_name: STRING)
|
||||
do
|
||||
remove (a_name)
|
||||
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
|
||||
@@ -1,14 +1,14 @@
|
||||
note
|
||||
description: "Summary description for {GW_RESPONSE_STREAM_IMP}."
|
||||
author: ""
|
||||
description: "[
|
||||
Response buffer
|
||||
|
||||
]"
|
||||
specification: "EWSGI specification https://github.com/Eiffel-World/Eiffel-Web-Framework/wiki/EWSGI-specification"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
GW_RESPONSE_STREAM_IMP
|
||||
|
||||
inherit
|
||||
EWSGI_RESPONSE_STREAM
|
||||
EWSGI_RESPONSE_BUFFER
|
||||
|
||||
create {EWSGI_APPLICATION}
|
||||
make
|
||||
@@ -22,23 +22,44 @@ feature {NONE} -- Initialization
|
||||
|
||||
feature {EWSGI_APPLICATION} -- Commit
|
||||
|
||||
commit (a_output_stream: EWSGI_OUTPUT_STREAM)
|
||||
commit
|
||||
-- Commit the current response
|
||||
do
|
||||
a_output_stream.flush
|
||||
output.flush
|
||||
message_committed := True
|
||||
ensure
|
||||
status_is_set: status_is_set
|
||||
header_committed: header_committed
|
||||
message_committed: message_committed
|
||||
end
|
||||
|
||||
feature -- Status report
|
||||
|
||||
header_committed: BOOLEAN
|
||||
-- Header committed?
|
||||
|
||||
message_committed: BOOLEAN
|
||||
-- Message committed?
|
||||
|
||||
message_writable: BOOLEAN
|
||||
-- Can message be written?
|
||||
do
|
||||
Result := status_is_set and header_committed
|
||||
end
|
||||
|
||||
feature {NONE} -- Core output operation
|
||||
|
||||
write (s: STRING)
|
||||
-- Send the content of `s'
|
||||
-- this can be used for header and body
|
||||
do
|
||||
output.put_string (s)
|
||||
end
|
||||
|
||||
feature -- Status setting
|
||||
|
||||
is_status_set: BOOLEAN
|
||||
status_is_set: BOOLEAN
|
||||
-- Is status set?
|
||||
do
|
||||
Result := status_code /= 0
|
||||
end
|
||||
@@ -46,32 +67,39 @@ feature -- Status setting
|
||||
set_status_code (a_code: INTEGER)
|
||||
-- Set response status code
|
||||
-- Should be done before sending any data back to the client
|
||||
require
|
||||
status_not_set: not status_is_set
|
||||
header_not_committed: not header_committed
|
||||
do
|
||||
status_code := a_code
|
||||
output.put_status_line (a_code)
|
||||
ensure
|
||||
status_code_set: status_code = a_code
|
||||
status_set: status_is_set
|
||||
end
|
||||
|
||||
status_code: INTEGER
|
||||
-- Response status
|
||||
|
||||
feature -- Output operation
|
||||
|
||||
write_string (s: STRING)
|
||||
-- Send the string `s'
|
||||
do
|
||||
write (s)
|
||||
end
|
||||
|
||||
write_file_content (fn: STRING)
|
||||
-- Send the content of file `fn'
|
||||
do
|
||||
output.put_file_content (fn)
|
||||
end
|
||||
-- Response status
|
||||
|
||||
feature -- Header output operation
|
||||
|
||||
write_headers_string (a_headers: STRING)
|
||||
require
|
||||
status_set: status_is_set
|
||||
header_not_committed: not header_committed
|
||||
do
|
||||
write (a_headers)
|
||||
header_committed := True
|
||||
ensure
|
||||
status_set: status_is_set
|
||||
header_committed: header_committed
|
||||
end
|
||||
|
||||
write_header (a_status_code: INTEGER; a_headers: detachable ARRAY [TUPLE [key: STRING; value: STRING]])
|
||||
-- Send headers with status `a_status', and headers from `a_headers'
|
||||
require
|
||||
status_not_set: not status_is_set
|
||||
header_not_committed: not header_committed
|
||||
local
|
||||
h: GW_HEADER
|
||||
i,n: INTEGER
|
||||
@@ -90,7 +118,42 @@ feature -- Header output operation
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
write (h.string)
|
||||
write_headers_string (h.string)
|
||||
ensure
|
||||
status_set: status_is_set
|
||||
header_committed: header_committed
|
||||
end
|
||||
|
||||
feature -- Output operation
|
||||
|
||||
write_string (s: STRING)
|
||||
-- Send the string `s'
|
||||
require
|
||||
message_writable: message_writable
|
||||
do
|
||||
write (s)
|
||||
end
|
||||
|
||||
write_substring (s: STRING; start_index, end_index: INTEGER)
|
||||
-- Send the substring `start_index:end_index]'
|
||||
--| Could be optimized according to the target output
|
||||
require
|
||||
message_writable: message_writable
|
||||
do
|
||||
output.put_substring (s, start_index, end_index)
|
||||
end
|
||||
|
||||
write_file_content (fn: STRING)
|
||||
-- Send the content of file `fn'
|
||||
require
|
||||
message_writable: message_writable
|
||||
do
|
||||
output.put_file_content (fn)
|
||||
end
|
||||
|
||||
flush
|
||||
do
|
||||
output.flush
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation: Access
|
||||
41
library/server/ewsgi/src/stream/ewsgi_input_stream.e
Normal file
41
library/server/ewsgi/src/stream/ewsgi_input_stream.e
Normal file
@@ -0,0 +1,41 @@
|
||||
note
|
||||
description : "[
|
||||
Objects that represents the input stream
|
||||
]"
|
||||
specification: "EWSGI/connector specification https://github.com/Eiffel-World/Eiffel-Web-Framework/wiki/EWSGI-specification"
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
EWSGI_INPUT_STREAM
|
||||
|
||||
feature -- Access
|
||||
|
||||
last_string: STRING_8
|
||||
-- Last read string from stream
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Basic operation
|
||||
|
||||
read_stream (n: INTEGER)
|
||||
require
|
||||
n_positive: n > 0
|
||||
deferred
|
||||
ensure
|
||||
at_max_n: last_string.count <= n
|
||||
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
|
||||
84
library/server/ewsgi/src/stream/ewsgi_output_stream.e
Normal file
84
library/server/ewsgi/src/stream/ewsgi_output_stream.e
Normal file
@@ -0,0 +1,84 @@
|
||||
note
|
||||
description : "[
|
||||
Objects that represents the output stream
|
||||
]"
|
||||
specification: "EWSGI/connector specification https://github.com/Eiffel-World/Eiffel-Web-Framework/wiki/EWSGI-specification"
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
EWSGI_OUTPUT_STREAM
|
||||
|
||||
feature -- Core operation
|
||||
|
||||
put_string (s: STRING_8)
|
||||
-- Write `s' into the output stream
|
||||
require
|
||||
s_not_empty: s /= Void and then not s.is_empty
|
||||
deferred
|
||||
end
|
||||
|
||||
flush
|
||||
-- Flush the output stream
|
||||
do
|
||||
end
|
||||
|
||||
feature -- Status writing
|
||||
|
||||
put_status_line (a_code: INTEGER)
|
||||
-- Put status code line for `a_code'
|
||||
--| Note this is a default implementation, and could be redefined
|
||||
--| for instance in relation to NPH CGI script
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Basic operation
|
||||
|
||||
put_substring (s: STRING; start_index, end_index: INTEGER)
|
||||
-- Write `s[start_index:end_index]' into the output stream
|
||||
--| Could be redefined for optimization
|
||||
require
|
||||
s_not_empty: s /= Void and then not s.is_empty
|
||||
do
|
||||
put_string (s.substring (start_index, end_index))
|
||||
end
|
||||
|
||||
put_file_content (fn: STRING)
|
||||
-- Send the content of file `fn'
|
||||
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 (4096)
|
||||
put_string (f.last_string)
|
||||
end
|
||||
f.close
|
||||
end
|
||||
end
|
||||
|
||||
put_header_line (s: STRING)
|
||||
-- Send `s' to http client as header line
|
||||
do
|
||||
put_string (s)
|
||||
put_string ("%R%N")
|
||||
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
|
||||
@@ -231,11 +231,13 @@ feature -- Others
|
||||
feature -- Redirection
|
||||
|
||||
put_redirection (a_location: STRING; a_code: INTEGER)
|
||||
-- Tell the client to redirect to page with `a_location' right away
|
||||
do
|
||||
put_header_key_value ("Location", a_location)
|
||||
end
|
||||
|
||||
put_refresh (a_location: STRING; a_timeout: INTEGER; a_code: INTEGER)
|
||||
-- Tell the client to refresh page with `a_location' after `a_timeout' in seconds
|
||||
do
|
||||
put_header_key_value ("Refresh", a_timeout.out + "; url=" + a_location)
|
||||
end
|
||||
|
||||
24
library/server/ewsgi/tests/ewsgi-full-safe.ecf
Normal file
24
library/server/ewsgi/tests/ewsgi-full-safe.ecf
Normal 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="ewsgi-full" uuid="663191A1-53D8-4974-AB46-7359C7377AD2" library_target="ewsgi-full">
|
||||
<target name="ewsgi-full">
|
||||
<root all_classes="true"/>
|
||||
<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>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="encoder" location="..\..\..\text\encoder\encoder-safe.ecf" readonly="false"/>
|
||||
<library name="error" location="..\..\..\error\error-safe.ecf"/>
|
||||
<library name="http" location="..\..\..\protocol\http\http-safe.ecf"/>
|
||||
<library name="libfcgi" location="..\..\libfcgi\libfcgi-safe.ecf"/>
|
||||
<library name="nino" location="..\..\..\..\ext\server\nino\nino-safe.ecf" readonly="false">
|
||||
<renaming old_name="HTTP_CONSTANTS" new_name="NINO_HTTP_CONSTANTS"/>
|
||||
</library>
|
||||
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
|
||||
<cluster name="connectors" location="..\connectors\" recursive="true"/>
|
||||
<cluster name="interface" location="..\src\" recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
24
library/server/ewsgi/tests/ewsgi-full.ecf
Normal file
24
library/server/ewsgi/tests/ewsgi-full.ecf
Normal 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="ewsgi-full" uuid="663191A1-53D8-4974-AB46-7359C7377AD2" library_target="ewsgi-full">
|
||||
<target name="ewsgi-full">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
<exclude>/\.git$</exclude>
|
||||
<exclude>/\.svn$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" full_class_checking="true" syntax="provisional">
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||
<library name="error" location="..\..\..\error\error.ecf"/>
|
||||
<library name="http" location="..\..\..\protocol\http\http.ecf"/>
|
||||
<library name="encoder" location="..\..\..\text\encoder\encoder.ecf" readonly="false"/>
|
||||
<library name="libfcgi" location="..\..\libfcgi\libfcgi.ecf"/>
|
||||
<library name="nino" location="..\..\..\..\ext\server\nino\nino.ecf" readonly="false">
|
||||
<renaming old_name="HTTP_CONSTANTS" new_name="NINO_HTTP_CONSTANTS"/>
|
||||
</library>
|
||||
<library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/>
|
||||
<cluster name="connectors" location="..\connectors\" recursive="true"/>
|
||||
<cluster name="interface" location="..\src\" recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
52
library/server/libfcgi/fcgi-safe.ecf
Normal file
52
library/server/libfcgi/fcgi-safe.ecf
Normal file
@@ -0,0 +1,52 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-6-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-6-0 http://www.eiffel.com/developers/xml/configuration-1-6-0.xsd" name="fcgi" uuid="3F4BCF74-3503-4533-9D74-5A65EC4CA3C4" library_target="fcgi">
|
||||
<target name="fcgi">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
<exclude>/\.svn$</exclude>
|
||||
<exclude>/\.git$</exclude>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
</file_rule>
|
||||
|
||||
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" >
|
||||
</option>
|
||||
<external_include location="$ECF_CONFIG_PATH/spec/include/libfcgi">
|
||||
<condition>
|
||||
<platform excluded_value="windows"/>
|
||||
</condition>
|
||||
</external_include>
|
||||
<external_include location="$ECF_CONFIG_PATH\spec\include\libfcgi">
|
||||
<condition>
|
||||
<platform value="windows"/>
|
||||
</condition>
|
||||
</external_include>
|
||||
<external_library location="$ECF_CONFIG_PATH\spec\lib\$ISE_PLATFORM\$ISE_C_COMPILER\libfcgi.lib">
|
||||
<condition>
|
||||
<platform value="windows"/>
|
||||
</condition>
|
||||
</external_library>
|
||||
<external_library location="/usr/local/lib/libfcgi.so">
|
||||
<condition>
|
||||
<platform excluded_value="windows"/>
|
||||
</condition>
|
||||
</external_library>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<cluster name="interface" location="interface" recursive="true"/>
|
||||
<cluster name="implementation" location="implementation" recursive="true">
|
||||
<file_rule>
|
||||
<exclude>/linux$</exclude>
|
||||
<exclude>/fake$</exclude>
|
||||
<condition>
|
||||
<platform value="windows"/>
|
||||
</condition>
|
||||
</file_rule>
|
||||
<file_rule>
|
||||
<exclude>/windows$</exclude>
|
||||
<exclude>/fake$</exclude>
|
||||
<condition>
|
||||
<platform excluded_value="windows"/>
|
||||
</condition>
|
||||
</file_rule>
|
||||
</cluster>
|
||||
</target>
|
||||
</system>
|
||||
@@ -8,7 +8,7 @@
|
||||
<exclude>/EIFGENs$</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">
|
||||
</option>
|
||||
<external_include location="$ECF_CONFIG_PATH/spec/include/libfcgi">
|
||||
<condition>
|
||||
@@ -30,7 +30,7 @@
|
||||
<platform excluded_value="windows"/>
|
||||
</condition>
|
||||
</external_library>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||
<cluster name="interface" location="interface" recursive="true"/>
|
||||
<cluster name="implementation" location="implementation" recursive="true">
|
||||
<file_rule>
|
||||
|
||||
16
library/server/libfcgi/tests/eiffelweb-safe.ecf
Normal file
16
library/server/libfcgi/tests/eiffelweb-safe.ecf
Normal file
@@ -0,0 +1,16 @@
|
||||
<?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="eiffelweb" uuid="6A03BC65-BD03-4B68-B51E-2543F9471D42">
|
||||
<target name="eiffelweb">
|
||||
<root cluster="application" class="APPLICATION_ROOT" feature="make"/>
|
||||
<file_rule>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
<exclude>/\.git$</exclude>
|
||||
<exclude>/\.svn$</exclude>
|
||||
</file_rule>
|
||||
<setting name="console_application" value="true"/>
|
||||
<setting name="concurrency" value="thread"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="fcgi" location="..\fcgi-safe.ecf" readonly="false"/>
|
||||
<cluster name="application" location=".\" recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
@@ -9,7 +9,7 @@
|
||||
</file_rule>
|
||||
<setting name="console_application" value="true"/>
|
||||
<setting name="concurrency" value="thread"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||
<library name="fcgi" location="..\fcgi.ecf" readonly="false"/>
|
||||
<cluster name="application" location=".\" recursive="true"/>
|
||||
</target>
|
||||
|
||||
14
library/server/request/router/doc/README.txt
Normal file
14
library/server/request/router/doc/README.txt
Normal file
@@ -0,0 +1,14 @@
|
||||
This library introduce the notion of router and handler
|
||||
The Router manages the association between URI,URI template and Handler
|
||||
The Router is in charge to route/dispatch a request to one of the Handler according to the URI and how the Handler is mapped in the Router.
|
||||
|
||||
Common usage
|
||||
|
||||
router: REQUEST_ROUTER
|
||||
hello_handler: REQUEST_HANDLER
|
||||
|
||||
create {REQUEST_URI_TEMPLATE_ROUTER} router.make
|
||||
create {REQUEST_AGENT_HANDLER} hello_handler.make (agent handle_hello)
|
||||
|
||||
router.map ("/hello/{name}", hello_handler)
|
||||
router.map_agent ("/hello/{name}", agent handle_hello)
|
||||
10
library/server/request/router/license.lic
Normal file
10
library/server/request/router/license.lic
Normal 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
|
||||
]"
|
||||
39
library/server/request/router/router-safe.ecf
Normal file
39
library/server/request/router/router-safe.ecf
Normal file
@@ -0,0 +1,39 @@
|
||||
<?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="router" uuid="7E530655-8578-4AF8-99CA-175A0025D843" library_target="router">
|
||||
<target name="router">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
<exclude>/.git$</exclude>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
<exclude>/.svn$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all">
|
||||
<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" location="..\..\ewsgi\ewsgi-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"/>
|
||||
<cluster name="src" location="src\" recursive="true"/>
|
||||
</target>
|
||||
<target name="ewsgi_compliant_router">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
<exclude>/.git$</exclude>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
<exclude>/.svn$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all">
|
||||
<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" location="..\..\ewsgi\ewsgi_spec-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"/>
|
||||
<cluster name="src" location="src\" recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
39
library/server/request/router/router.ecf
Normal file
39
library/server/request/router/router.ecf
Normal file
@@ -0,0 +1,39 @@
|
||||
<?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="router" uuid="7E530655-8578-4AF8-99CA-175A0025D843" library_target="router">
|
||||
<target name="router">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
<exclude>/.git$</exclude>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
<exclude>/.svn$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" full_class_checking="true">
|
||||
<assertions precondition="true"/>
|
||||
</option>
|
||||
<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" location="..\..\ewsgi\ewsgi.ecf"/>
|
||||
<library name="http" location="..\..\..\protocol\http\http.ecf"/>
|
||||
<library name="uri_template" location="..\..\..\protocol\uri_template\uri_template.ecf"/>
|
||||
<library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/>
|
||||
<cluster name="src" location="src\" recursive="true"/>
|
||||
</target>
|
||||
<target name="ewsgi_compliant_router">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
<exclude>/.git$</exclude>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
<exclude>/.svn$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" full_class_checking="true">
|
||||
<assertions precondition="true"/>
|
||||
</option>
|
||||
<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" location="..\..\ewsgi\ewsgi.ecf"/>
|
||||
<library name="http" location="..\..\..\protocol\http\http.ecf"/>
|
||||
<library name="uri_template" location="..\..\..\protocol\uri_template\uri_template.ecf"/>
|
||||
<library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/>
|
||||
<cluster name="src" location="src\" recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
@@ -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_BUFFER)
|
||||
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_BUFFER)
|
||||
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
|
||||
@@ -0,0 +1,95 @@
|
||||
note
|
||||
description: "Summary description for {REQUEST_HANDLER_CONTEXT}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
REQUEST_HANDLER_CONTEXT
|
||||
|
||||
inherit
|
||||
ANY
|
||||
|
||||
REQUEST_FORMAT_UTILITY
|
||||
export
|
||||
{NONE} all
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
request: EWSGI_REQUEST
|
||||
-- Associated request
|
||||
|
||||
path: STRING
|
||||
-- ???
|
||||
|
||||
request_content_type (content_type_supported: detachable ARRAY [STRING]): detachable STRING
|
||||
local
|
||||
s: detachable STRING
|
||||
i,n: INTEGER
|
||||
do
|
||||
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
|
||||
|
||||
feature -- Query
|
||||
|
||||
path_parameter (a_name: STRING): detachable STRING_32
|
||||
-- Parameter value for path variable `a_name'
|
||||
deferred
|
||||
end
|
||||
|
||||
query_parameter (a_name: STRING): detachable STRING_32
|
||||
-- Parameter value for query variable `a_name'
|
||||
--| i.e after the ? character
|
||||
deferred
|
||||
end
|
||||
|
||||
parameter (a_name: STRING): detachable STRING_32
|
||||
-- Any parameter value for variable `a_name'
|
||||
-- URI template parameter and query parameters
|
||||
do
|
||||
Result := query_parameter (a_name)
|
||||
if Result = Void then
|
||||
Result := path_parameter (a_name)
|
||||
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
|
||||
@@ -0,0 +1,45 @@
|
||||
note
|
||||
description: "Summary description for {REQUEST_URI_HANDLER_CONTEXT}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
REQUEST_URI_HANDLER_CONTEXT
|
||||
|
||||
inherit
|
||||
REQUEST_HANDLER_CONTEXT
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (req: EWSGI_REQUEST; p: like path)
|
||||
do
|
||||
request := req
|
||||
path := p
|
||||
end
|
||||
|
||||
feature -- Query
|
||||
|
||||
path_parameter (a_name: STRING): detachable STRING_32
|
||||
do
|
||||
end
|
||||
|
||||
query_parameter (a_name: STRING): detachable STRING_32
|
||||
do
|
||||
Result := request.parameter (a_name)
|
||||
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
|
||||
@@ -0,0 +1,57 @@
|
||||
note
|
||||
description: "Summary description for {REQUEST_URI_TEMPLATE_HANDLER_CONTEXT}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
REQUEST_URI_TEMPLATE_HANDLER_CONTEXT
|
||||
|
||||
inherit
|
||||
REQUEST_HANDLER_CONTEXT
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (req: EWSGI_REQUEST; tpl: URI_TEMPLATE; tpl_res: URI_TEMPLATE_MATCH_RESULT; p: like path)
|
||||
do
|
||||
request := req
|
||||
uri_template := tpl
|
||||
uri_template_match := tpl_res
|
||||
path := p
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
uri_template: URI_TEMPLATE
|
||||
|
||||
uri_template_match: URI_TEMPLATE_MATCH_RESULT
|
||||
|
||||
feature -- Query
|
||||
|
||||
path_parameter (a_name: STRING): detachable STRING_32
|
||||
do
|
||||
Result := uri_template_match.url_decoded_path_variable (a_name)
|
||||
end
|
||||
|
||||
query_parameter (a_name: STRING): detachable STRING_32
|
||||
do
|
||||
Result := uri_template_match.url_decoded_query_variable (a_name)
|
||||
if Result = Void then
|
||||
Result := request.parameter (a_name)
|
||||
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
|
||||
@@ -0,0 +1,45 @@
|
||||
note
|
||||
description: "Summary description for REQUEST_AGENT_HANDLER."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
REQUEST_AGENT_HANDLER
|
||||
|
||||
inherit
|
||||
REQUEST_HANDLER
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Initialization
|
||||
|
||||
make (act: like action)
|
||||
do
|
||||
action := act
|
||||
initialize
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
action: PROCEDURE [ANY, TUPLE [ctx: REQUEST_HANDLER_CONTEXT; req: EWSGI_REQUEST; res: EWSGI_RESPONSE_BUFFER]]
|
||||
|
||||
feature -- Execution
|
||||
|
||||
execute_application (ctx: REQUEST_HANDLER_CONTEXT; req: EWSGI_REQUEST; res: EWSGI_RESPONSE_BUFFER)
|
||||
do
|
||||
action.call ([ctx, req, res])
|
||||
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
|
||||
310
library/server/request/router/src/handler/request_handler.e
Normal file
310
library/server/request/router/src/handler/request_handler.e
Normal file
@@ -0,0 +1,310 @@
|
||||
note
|
||||
description: "Summary description for {REQUEST_HANDLER}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
REQUEST_HANDLER
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
initialize
|
||||
-- Initialize various attributes
|
||||
do
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
description: detachable STRING
|
||||
-- Optional descriptiong
|
||||
|
||||
feature -- Status report
|
||||
|
||||
is_valid_context (req: EWSGI_REQUEST): BOOLEAN
|
||||
-- Is `req' valid context for current handler?
|
||||
do
|
||||
Result := request_method_name_supported (req.environment.request_method)
|
||||
end
|
||||
|
||||
feature -- Execution
|
||||
|
||||
execute (a_hdl_context: REQUEST_HANDLER_CONTEXT; req: EWSGI_REQUEST; res: EWSGI_RESPONSE_BUFFER)
|
||||
-- Execute request handler
|
||||
require
|
||||
is_valid_context: is_valid_context (req)
|
||||
local
|
||||
rescued: BOOLEAN
|
||||
do
|
||||
if not rescued then
|
||||
if request_method_name_supported (req.environment.request_method) then
|
||||
pre_execute (req)
|
||||
execute_application (a_hdl_context, req, res)
|
||||
post_execute (req, res)
|
||||
else
|
||||
execute_method_not_allowed (a_hdl_context, req, res)
|
||||
end
|
||||
else
|
||||
rescue_execute (req, res)
|
||||
end
|
||||
rescue
|
||||
rescued := True
|
||||
retry
|
||||
end
|
||||
|
||||
execute_method_not_allowed (a_hdl_context: REQUEST_HANDLER_CONTEXT; req: EWSGI_REQUEST; res: EWSGI_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: EWSGI_REQUEST; res: EWSGI_RESPONSE_BUFFER)
|
||||
-- Execute request handler
|
||||
deferred
|
||||
end
|
||||
|
||||
pre_execute (req: EWSGI_REQUEST)
|
||||
-- Operation processed before `execute'
|
||||
do
|
||||
--| To be redefined if needed
|
||||
end
|
||||
|
||||
post_execute (req: EWSGI_REQUEST; res: EWSGI_RESPONSE_BUFFER)
|
||||
-- Operation processed after `execute'
|
||||
do
|
||||
--| To be redefined if needed
|
||||
end
|
||||
|
||||
rescue_execute (req: EWSGI_REQUEST; res: EWSGI_RESPONSE_BUFFER)
|
||||
-- Operation processed after a rescue
|
||||
do
|
||||
--| To be redefined if needed
|
||||
post_execute (req, res)
|
||||
end
|
||||
|
||||
feature -- Execution: report
|
||||
|
||||
-- execution_information (req: EWSGI_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: EWSGI_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: EWSGI_REQUEST; args: detachable STRING; abs: BOOLEAN): STRING
|
||||
-- Associated url based on `path' and `args'
|
||||
-- if `abs' then return absolute url
|
||||
local
|
||||
s: detachable STRING
|
||||
do
|
||||
s := args
|
||||
if s /= Void and then s.count > 0 then
|
||||
if s[1] /= '/' then
|
||||
s := req.environment.request_uri + "/" + s
|
||||
else
|
||||
s := req.environment.request_uri + s
|
||||
end
|
||||
else
|
||||
s := req.environment.request_uri
|
||||
end
|
||||
if abs then
|
||||
Result := req.absolute_script_url (s)
|
||||
else
|
||||
Result := req.script_url (s)
|
||||
end
|
||||
ensure
|
||||
result_attached: Result /= Void
|
||||
end
|
||||
|
||||
feature -- Element change
|
||||
|
||||
set_description (s: like description)
|
||||
-- Set `description' to `s'
|
||||
do
|
||||
description := s
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
supported_request_methods: INTEGER
|
||||
-- Support request method such as GET, POST, ...
|
||||
|
||||
feature {NONE} -- Status report
|
||||
|
||||
request_method_id_supported (a_id: INTEGER): BOOLEAN
|
||||
do
|
||||
Result := (supported_request_methods & a_id) = a_id
|
||||
end
|
||||
|
||||
request_method_name_supported (n: STRING): BOOLEAN
|
||||
-- Is request method `n' supported?
|
||||
do
|
||||
Result := request_method_id_supported (request_method_constants.method_id (n))
|
||||
end
|
||||
|
||||
request_method_constants: HTTP_REQUEST_METHOD_CONSTANTS
|
||||
once
|
||||
create Result
|
||||
end
|
||||
|
||||
feature -- Status report
|
||||
|
||||
supported_request_method_names: LIST [STRING]
|
||||
-- Support request method such as GET, POST, ...
|
||||
do
|
||||
create {LINKED_LIST [STRING]} Result.make
|
||||
if method_get_supported then
|
||||
Result.extend (request_method_constants.method_get_name)
|
||||
end
|
||||
if method_post_supported then
|
||||
Result.extend (request_method_constants.method_post_name)
|
||||
end
|
||||
if method_put_supported then
|
||||
Result.extend (request_method_constants.method_put_name)
|
||||
end
|
||||
if method_delete_supported then
|
||||
Result.extend (request_method_constants.method_delete_name)
|
||||
end
|
||||
if method_head_supported then
|
||||
Result.extend (request_method_constants.method_head_name)
|
||||
end
|
||||
end
|
||||
|
||||
method_get_supported: BOOLEAN
|
||||
do
|
||||
Result := request_method_id_supported ({HTTP_REQUEST_METHOD_CONSTANTS}.method_get)
|
||||
end
|
||||
|
||||
method_post_supported: BOOLEAN
|
||||
do
|
||||
Result := request_method_id_supported ({HTTP_REQUEST_METHOD_CONSTANTS}.method_post)
|
||||
end
|
||||
|
||||
method_put_supported: BOOLEAN
|
||||
do
|
||||
Result := request_method_id_supported ({HTTP_REQUEST_METHOD_CONSTANTS}.method_put)
|
||||
end
|
||||
|
||||
method_delete_supported: BOOLEAN
|
||||
do
|
||||
Result := request_method_id_supported ({HTTP_REQUEST_METHOD_CONSTANTS}.method_delete)
|
||||
end
|
||||
|
||||
method_head_supported: BOOLEAN
|
||||
do
|
||||
Result := request_method_id_supported ({HTTP_REQUEST_METHOD_CONSTANTS}.method_head)
|
||||
end
|
||||
|
||||
feature -- Element change: request methods
|
||||
|
||||
reset_supported_request_methods
|
||||
do
|
||||
supported_request_methods := 0
|
||||
end
|
||||
|
||||
enable_request_method_get
|
||||
do
|
||||
enable_request_method ({HTTP_REQUEST_METHOD_CONSTANTS}.method_get)
|
||||
end
|
||||
|
||||
enable_request_method_post
|
||||
do
|
||||
enable_request_method ({HTTP_REQUEST_METHOD_CONSTANTS}.method_post)
|
||||
end
|
||||
|
||||
enable_request_method_put
|
||||
do
|
||||
enable_request_method ({HTTP_REQUEST_METHOD_CONSTANTS}.method_put)
|
||||
end
|
||||
|
||||
enable_request_method_delete
|
||||
do
|
||||
enable_request_method ({HTTP_REQUEST_METHOD_CONSTANTS}.method_delete)
|
||||
end
|
||||
|
||||
enable_request_method_head
|
||||
do
|
||||
enable_request_method ({HTTP_REQUEST_METHOD_CONSTANTS}.method_head)
|
||||
end
|
||||
|
||||
enable_request_method (m: INTEGER)
|
||||
do
|
||||
supported_request_methods := supported_request_methods | m
|
||||
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
|
||||
87
library/server/request/router/src/router/request_router.e
Normal file
87
library/server/request/router/src/router/request_router.e
Normal file
@@ -0,0 +1,87 @@
|
||||
note
|
||||
description: "Summary description for {REQUEST_ROUTER}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
REQUEST_ROUTER
|
||||
|
||||
feature -- Registration
|
||||
|
||||
map_default (r: like default_handler)
|
||||
-- Map default handler
|
||||
-- If no route/handler is found,
|
||||
-- then use `default_handler' as default if not Void
|
||||
do
|
||||
default_handler := r
|
||||
end
|
||||
|
||||
map (a_id: STRING; h: REQUEST_HANDLER)
|
||||
-- Map handler `h' with `a_id'
|
||||
deferred
|
||||
end
|
||||
|
||||
map_agent (a_id: STRING; a_action: like {REQUEST_AGENT_HANDLER}.action)
|
||||
local
|
||||
h: REQUEST_AGENT_HANDLER
|
||||
do
|
||||
create h.make (a_action)
|
||||
map (a_id, h)
|
||||
end
|
||||
|
||||
feature -- Execution
|
||||
|
||||
dispatch (req: EWSGI_REQUEST; res: EWSGI_RESPONSE_BUFFER): detachable REQUEST_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
|
||||
do
|
||||
d := handler (req)
|
||||
if d /= Void then
|
||||
Result := d.handler
|
||||
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, "/")
|
||||
end
|
||||
Result.execute (ctx, req, res)
|
||||
end
|
||||
ensure
|
||||
result_void_implie_no_default: Result = Void implies default_handler = Void
|
||||
end
|
||||
|
||||
feature {NONE} -- Access: Implementation
|
||||
|
||||
handler (req: EWSGI_REQUEST): detachable TUPLE [handler: REQUEST_HANDLER; context: REQUEST_HANDLER_CONTEXT]
|
||||
-- Handler whose map matched with `req'
|
||||
require
|
||||
req_valid: req /= Void and then req.environment.path_info /= Void
|
||||
deferred
|
||||
ensure
|
||||
req_path_info_unchanged: req.environment.path_info.same_string (old req.environment.path_info)
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
default_handler: detachable REQUEST_HANDLER
|
||||
-- Default handler
|
||||
|
||||
;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
|
||||
169
library/server/request/router/src/router/request_uri_router.e
Normal file
169
library/server/request/router/src/router/request_uri_router.e
Normal file
@@ -0,0 +1,169 @@
|
||||
note
|
||||
description: "Summary description for {REQUEST_URI_ROUTER}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
REQUEST_URI_ROUTER
|
||||
|
||||
inherit
|
||||
REQUEST_ROUTER
|
||||
|
||||
ITERABLE [REQUEST_HANDLER]
|
||||
redefine
|
||||
new_cursor
|
||||
end
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Initialization
|
||||
|
||||
make (n: INTEGER)
|
||||
do
|
||||
create handlers.make (n)
|
||||
handlers.compare_objects
|
||||
end
|
||||
|
||||
feature -- Registration
|
||||
|
||||
map (p: STRING; h: REQUEST_HANDLER)
|
||||
do
|
||||
handlers.force (h, p)
|
||||
end
|
||||
|
||||
feature {NONE} -- Access: Implementation
|
||||
|
||||
handler (req: EWSGI_REQUEST): detachable TUPLE [handler: REQUEST_HANDLER; context: REQUEST_HANDLER_CONTEXT]
|
||||
local
|
||||
h: detachable REQUEST_HANDLER
|
||||
ctx: detachable REQUEST_HANDLER_CONTEXT
|
||||
do
|
||||
h := handler_by_path (req.environment.path_info)
|
||||
if h = Void then
|
||||
if attached smart_handler_by_path (req.environment.path_info) as info then
|
||||
h := info.handler
|
||||
ctx := handler_context (info.path, req)
|
||||
end
|
||||
end
|
||||
if h /= Void then
|
||||
if h.is_valid_context (req) then
|
||||
if ctx = Void then
|
||||
ctx := handler_context (Void, req)
|
||||
end
|
||||
Result := [h, ctx]
|
||||
else
|
||||
Result := Void
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
smart_handler (req: EWSGI_REQUEST): detachable TUPLE [path: STRING; handler: REQUEST_HANDLER]
|
||||
require
|
||||
req_valid: req /= Void and then req.environment.path_info /= Void
|
||||
do
|
||||
Result := smart_handler_by_path (req.environment.path_info)
|
||||
ensure
|
||||
req_path_info_unchanged: req.environment.path_info.same_string (old req.environment.path_info)
|
||||
end
|
||||
|
||||
handler_by_path (a_path: STRING): detachable REQUEST_HANDLER
|
||||
require
|
||||
a_path_valid: a_path /= Void
|
||||
do
|
||||
Result := handlers.item (context_path (a_path))
|
||||
ensure
|
||||
a_path_unchanged: a_path.same_string (old a_path)
|
||||
end
|
||||
|
||||
smart_handler_by_path (a_path: STRING): detachable TUPLE [path: STRING; handler: REQUEST_HANDLER]
|
||||
require
|
||||
a_path_valid: a_path /= Void
|
||||
local
|
||||
p: INTEGER
|
||||
l_context_path, l_path: STRING
|
||||
h: detachable REQUEST_HANDLER
|
||||
do
|
||||
l_context_path := context_path (a_path)
|
||||
from
|
||||
p := l_context_path.count + 1
|
||||
until
|
||||
p <= 1 or Result /= Void
|
||||
loop
|
||||
l_path := l_context_path.substring (1, p - 1)
|
||||
h := handler_by_path (l_path)
|
||||
if h /= Void then
|
||||
Result := [l_path, h]
|
||||
else
|
||||
p := l_context_path.last_index_of ('/', p - 1)
|
||||
end
|
||||
variant
|
||||
p
|
||||
end
|
||||
ensure
|
||||
a_path_unchanged: a_path.same_string (old a_path)
|
||||
end
|
||||
|
||||
feature -- Context factory
|
||||
|
||||
handler_context (p: detachable STRING; req: EWSGI_REQUEST): REQUEST_URI_HANDLER_CONTEXT
|
||||
do
|
||||
if p /= Void then
|
||||
create Result.make (req, p)
|
||||
else
|
||||
create Result.make (req, req.environment.path_info)
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
new_cursor: HASH_TABLE_ITERATION_CURSOR [REQUEST_HANDLER, STRING]
|
||||
-- Fresh cursor associated with current structure
|
||||
do
|
||||
Result := handlers.new_cursor
|
||||
end
|
||||
|
||||
item (a_path: STRING): detachable REQUEST_HANDLER
|
||||
do
|
||||
Result := handler_by_path (a_path)
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
handlers: HASH_TABLE [REQUEST_HANDLER, STRING]
|
||||
-- Handlers
|
||||
|
||||
context_path (a_path: STRING): STRING
|
||||
-- Prepared path from context which match requirement
|
||||
-- i.e: not empty, starting with '/'
|
||||
local
|
||||
p: INTEGER
|
||||
do
|
||||
Result := a_path
|
||||
if Result.is_empty then
|
||||
Result := "/"
|
||||
else
|
||||
if Result[1] /= '/' then
|
||||
Result := "/" + Result
|
||||
end
|
||||
p := Result.index_of ('.', 1)
|
||||
if p > 0 then
|
||||
Result := Result.substring (1, p - 1)
|
||||
end
|
||||
end
|
||||
ensure
|
||||
result_not_empty: not Result.is_empty
|
||||
end
|
||||
|
||||
;note
|
||||
copyright: "2011-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
|
||||
@@ -0,0 +1,138 @@
|
||||
note
|
||||
description: "Summary description for {REQUEST_URI_TEMPLATE_ROUTER}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
REQUEST_URI_TEMPLATE_ROUTER
|
||||
|
||||
inherit
|
||||
REQUEST_ROUTER
|
||||
|
||||
ITERABLE [REQUEST_HANDLER]
|
||||
redefine
|
||||
new_cursor
|
||||
end
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Initialization
|
||||
|
||||
make (n: INTEGER)
|
||||
do
|
||||
create handlers.make (n)
|
||||
create templates.make (n)
|
||||
handlers.compare_objects
|
||||
end
|
||||
|
||||
feature -- Registration
|
||||
|
||||
map_with_uri_template (uri: URI_TEMPLATE; h: REQUEST_HANDLER)
|
||||
do
|
||||
handlers.force (h, uri.template)
|
||||
templates.force (uri, uri.template)
|
||||
end
|
||||
|
||||
map (tpl: STRING; h: REQUEST_HANDLER)
|
||||
local
|
||||
uri: URI_TEMPLATE
|
||||
do
|
||||
create uri.make (tpl)
|
||||
map_with_uri_template (uri, h)
|
||||
end
|
||||
|
||||
feature {NONE} -- Access: Implementation
|
||||
|
||||
handler (req: EWSGI_REQUEST): detachable TUPLE [handler: REQUEST_HANDLER; context: REQUEST_HANDLER_CONTEXT]
|
||||
local
|
||||
ctx: detachable REQUEST_URI_TEMPLATE_HANDLER_CONTEXT
|
||||
l_handlers: like handlers
|
||||
t: STRING
|
||||
p: STRING
|
||||
do
|
||||
p := req.environment.request_uri
|
||||
from
|
||||
l_handlers := handlers
|
||||
l_handlers.start
|
||||
until
|
||||
l_handlers.after or Result /= Void
|
||||
loop
|
||||
t := l_handlers.key_for_iteration
|
||||
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_handlers.item_for_iteration, ctx]
|
||||
end
|
||||
l_handlers.forth
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Context factory
|
||||
|
||||
handler_context (p: detachable STRING; req: EWSGI_REQUEST; tpl: URI_TEMPLATE; tpl_res: URI_TEMPLATE_MATCH_RESULT): REQUEST_URI_TEMPLATE_HANDLER_CONTEXT
|
||||
do
|
||||
if p /= Void then
|
||||
create Result.make (req, tpl, tpl_res, p)
|
||||
else
|
||||
create Result.make (req, tpl, tpl_res, req.environment.path_info)
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
new_cursor: HASH_TABLE_ITERATION_CURSOR [REQUEST_HANDLER, STRING]
|
||||
-- Fresh cursor associated with current structure
|
||||
do
|
||||
Result := handlers.new_cursor
|
||||
end
|
||||
|
||||
item (a_path: STRING): detachable REQUEST_HANDLER
|
||||
do
|
||||
Result := handlers.item (a_path)
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
handlers: HASH_TABLE [REQUEST_HANDLER, STRING]
|
||||
-- Handlers indexed by the template expression
|
||||
-- see `templates'
|
||||
|
||||
templates: HASH_TABLE [URI_TEMPLATE, STRING]
|
||||
-- URI Template indexed by the template expression
|
||||
|
||||
context_path (a_path: STRING): STRING
|
||||
-- Prepared path from context which match requirement
|
||||
-- i.e: not empty, starting with '/'
|
||||
local
|
||||
p: INTEGER
|
||||
do
|
||||
Result := a_path
|
||||
if Result.is_empty then
|
||||
Result := "/"
|
||||
else
|
||||
if Result[1] /= '/' then
|
||||
Result := "/" + Result
|
||||
end
|
||||
p := Result.index_of ('.', 1)
|
||||
if p > 0 then
|
||||
Result := Result.substring (1, p - 1)
|
||||
end
|
||||
end
|
||||
ensure
|
||||
result_not_empty: not Result.is_empty
|
||||
end
|
||||
|
||||
;note
|
||||
copyright: "2011-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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user