Tried to reduce gap between both EWSGI proposals

Re-adapt the Spec-compliant solution (instead of Lib-compliant solution).
  Thus no more 100% deferred interface.
Rename EWSGI_RESPONSE into EWSGI_RESPONSE_BUFFER
Added in extra/response-as-result/  an copy/paste from the implementation of Paul's proposal (not up to date with Paul's spec). But this is mainly for information and tests.
Removed part of the ewsgi/specification interfaces ... to be able to test EWSGI compliant library against the pure specification (experimental).
Renamed most of the GW_... into EWSGI_...
This commit is contained in:
Jocelyn Fiat
2011-08-01 16:41:16 +02:00
parent bbcc9ef44b
commit 4eb22d0272
61 changed files with 1570 additions and 534 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -1,292 +0,0 @@
note
description: "Summary description for {EWSGI_ENVIRONMENT_VARIABLES}."
legal: "See notice at end of class."
status: "See notice at end of class."
date: "$Date$"
revision: "$Revision$"
class
EWSGI_ENVIRONMENT_VARIABLES
inherit
EWSGI_ENVIRONMENT
redefine
update_path_info
end
create
make_with_variables
feature {NONE} -- Initialization
make_with_variables (a_vars: HASH_TABLE [STRING, STRING])
-- Fill with variable from `a_vars'
local
s: detachable STRING
do
create empty_string.make_empty
create table.make (a_vars.count)
from
a_vars.start
until
a_vars.after
loop
table.force (a_vars.item_for_iteration, a_vars.key_for_iteration)
a_vars.forth
end
--| QUERY_STRING
query_string := variable_or_default ({EWSGI_ENVIRONMENT_NAMES}.query_string, empty_string, False)
--| REQUEST_METHOD
request_method := variable_or_default ({EWSGI_ENVIRONMENT_NAMES}.request_method, empty_string, False)
--| CONTENT_TYPE
s := variable ({EWSGI_ENVIRONMENT_NAMES}.content_type)
if s /= Void and then not s.is_empty then
content_type := s
else
content_type := Void
end
--| CONTENT_LENGTH
s := variable ({EWSGI_ENVIRONMENT_NAMES}.content_length)
content_length := s
if s /= Void and then s.is_integer then
content_length_value := s.to_integer
else
--| content_length := 0
end
--| PATH_INFO
path_info := variable_or_default ({EWSGI_ENVIRONMENT_NAMES}.path_info, empty_string, False)
--| SERVER_NAME
server_name := variable_or_default ({EWSGI_ENVIRONMENT_NAMES}.server_name, empty_string, False)
--| SERVER_PORT
s := variable ({EWSGI_ENVIRONMENT_NAMES}.server_port)
if s /= Void and then s.is_integer then
server_port := s.to_integer
else
server_port := 80
end
--| SCRIPT_NAME
script_name := variable_or_default ({EWSGI_ENVIRONMENT_NAMES}.script_name, empty_string, False)
--| REMOTE_ADDR
remote_addr := variable_or_default ({EWSGI_ENVIRONMENT_NAMES}.remote_addr, empty_string, False)
--| REMOTE_HOST
remote_host := variable_or_default ({EWSGI_ENVIRONMENT_NAMES}.remote_host, empty_string, False)
--| REQUEST_URI
request_uri := variable_or_default ({EWSGI_ENVIRONMENT_NAMES}.request_uri, empty_string, False)
end
feature -- Access
table: HASH_TABLE [STRING, STRING]
feature -- Access
variable (a_name: STRING): detachable STRING
do
Result := table.item (a_name)
end
has_variable (a_name: STRING): BOOLEAN
do
Result := table.has_key (a_name)
end
feature {EWSGI_REQUEST, EWSGI_APPLICATION, EWSGI_CONNECTOR} -- Element change
set_variable (a_name: STRING; a_value: STRING)
do
table.force (a_value, a_name)
end
unset_variable (a_name: STRING)
do
table.remove (a_name)
end
feature -- Common Gateway Interface - 1.1 8 January 1996
auth_type: detachable STRING
content_length: detachable STRING
content_length_value: INTEGER
content_type: detachable STRING
gateway_interface: STRING
do
Result := variable_or_default ({EWSGI_ENVIRONMENT_NAMES}.gateway_interface, "", False)
end
path_info: STRING
-- <Precursor/>
--
--| For instance, if the current script was accessed via the URL
--| http://www.example.com/eiffel/path_info.exe/some/stuff?foo=bar, then $_SERVER['PATH_INFO'] would contain /some/stuff.
--|
--| Note that is the PATH_INFO variable does not exists, the `path_info' value will be empty
path_translated: detachable STRING
do
Result := variable ({EWSGI_ENVIRONMENT_NAMES}.path_translated)
end
query_string: STRING
remote_addr: STRING
remote_host: STRING
remote_ident: detachable STRING
do
Result := variable ({EWSGI_ENVIRONMENT_NAMES}.remote_ident)
end
remote_user: detachable STRING
do
Result := variable ({EWSGI_ENVIRONMENT_NAMES}.remote_user)
end
request_method: STRING
script_name: STRING
server_name: STRING
server_port: INTEGER
server_protocol: STRING
do
Result := variable_or_default ({EWSGI_ENVIRONMENT_NAMES}.server_protocol, "HTTP/1.0", True)
end
server_software: STRING
do
Result := variable_or_default ({EWSGI_ENVIRONMENT_NAMES}.server_software, "Unknown Server", True)
end
feature -- HTTP_*
http_accept: detachable STRING
-- Contents of the Accept: header from the current request, if there is one.
do
Result := table.item ({EWSGI_ENVIRONMENT_NAMES}.http_accept)
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'.
do
Result := table.item ({EWSGI_ENVIRONMENT_NAMES}.http_accept_charset)
end
http_accept_encoding: detachable STRING
-- Contents of the Accept-Encoding: header from the current request, if there is one.
-- Example: 'gzip'.
do
Result := table.item ({EWSGI_ENVIRONMENT_NAMES}.http_accept_encoding)
end
http_accept_language: detachable STRING
-- Contents of the Accept-Language: header from the current request, if there is one.
-- Example: 'en'.
do
Result := table.item ({EWSGI_ENVIRONMENT_NAMES}.http_accept_language)
end
http_connection: detachable STRING
-- Contents of the Connection: header from the current request, if there is one.
-- Example: 'Keep-Alive'.
do
Result := table.item ({EWSGI_ENVIRONMENT_NAMES}.http_connection)
end
http_host: detachable STRING
-- Contents of the Host: header from the current request, if there is one.
do
Result := table.item ({EWSGI_ENVIRONMENT_NAMES}.http_host)
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.
do
Result := table.item ({EWSGI_ENVIRONMENT_NAMES}.http_referer)
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.
do
Result := table.item ({EWSGI_ENVIRONMENT_NAMES}.http_user_agent)
end
http_authorization: detachable STRING
-- Contents of the Authorization: header from the current request, if there is one.
do
Result := table.item ({EWSGI_ENVIRONMENT_NAMES}.http_authorization)
end
feature -- Extra
request_uri: STRING
-- The URI which was given in order to access this page; for instance, '/index.html'.
orig_path_info: detachable STRING
-- Original version of `path_info' before processed by Current environment
feature {EWSGI_REQUEST} -- Update
set_orig_path_info (s: STRING)
do
orig_path_info := s
set_variable ({EWSGI_ENVIRONMENT_NAMES}.orig_path_info, s)
end
unset_orig_path_info
do
orig_path_info := Void
unset_variable ({EWSGI_ENVIRONMENT_NAMES}.orig_path_info)
end
update_path_info (a_path_info: like path_info)
do
path_info := a_path_info
set_variable ({EWSGI_ENVIRONMENT_NAMES}.path_info, a_path_info)
end
feature {NONE} -- Implementation
empty_string: STRING
-- Reusable empty string
invariant
empty_string_unchanged: empty_string.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

View File

@@ -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."

View File

@@ -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
@@ -57,14 +77,21 @@ 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
@@ -73,10 +100,12 @@ 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
status_not_set: not status_is_set
header_not_committed: not header_committed
deferred
ensure
status_set: is_status_set
header_committed: header_committed
status_set: status_is_set
end
note